diff --git a/schemars/src/make_schema.rs b/schemars/src/make_schema.rs index 1a210a6..0f29343 100644 --- a/schemars/src/make_schema.rs +++ b/schemars/src/make_schema.rs @@ -35,8 +35,6 @@ macro_rules! no_ref_schema { }; } -// TODO structs, enums, tuples - // TODO any other serde types other than serde_json value? // https://github.com/serde-rs/serde/blob/ce75418e40a593fc5c0902cbf4a45305a4178dd7/serde/src/ser/impls.rs // Cell, RefCell, Mutex, RwLock, Result?, Duration, SystemTime, diff --git a/schemars_derive/src/lib.rs b/schemars_derive/src/lib.rs index 18408c9..f126e73 100644 --- a/schemars_derive/src/lib.rs +++ b/schemars_derive/src/lib.rs @@ -23,9 +23,9 @@ pub fn derive_make_schema(input: proc_macro::TokenStream) -> proc_macro::TokenSt let name = cont.ident; let (impl_generics, ty_generics, where_clause) = cont.generics.split_for_impl(); - let fn_contents = match cont.data { - Data::Struct(Style::Struct, ref fields) => struct_implementation(fields), - Data::Enum(ref variants) => enum_implementation(variants), + let schema_contents = match cont.data { + Data::Struct(Style::Struct, ref fields) => schema_for_struct(fields), + Data::Enum(ref variants) => schema_for_enum(variants), _ => unimplemented!("work in progress!"), }; @@ -33,11 +33,11 @@ pub fn derive_make_schema(input: proc_macro::TokenStream) -> proc_macro::TokenSt #[automatically_derived] impl #impl_generics schemars::make_schema::MakeSchema for #name #ty_generics #where_clause { fn make_schema(gen: &mut schemars::SchemaGenerator) -> schemars::Schema { - let mut o = schemars::SchemaObject { + schemars::SchemaObject { + #schema_contents ..Default::default() - }; - #fn_contents - o.into() + } + .into() } }; }; @@ -50,34 +50,39 @@ fn compile_error(span: Span, message: String) -> TokenStream { } } -fn is_unit_variant(v: &Variant) -> bool { +fn name_for_unit_variant(v: &Variant) -> Option { match v.style { - Style::Unit => true, - _ => false, + Style::Unit => Some(v.attrs.name().deserialize_name()), + _ => None, } } -fn enum_implementation(variants: &[Variant]) -> TokenStream { - if variants.iter().all(is_unit_variant) { - let names = variants - .into_iter() - .map(|v| v.attrs.name().deserialize_name()); +fn schema_for_enum(variants: &[Variant]) -> TokenStream { + // TODO handle untagged or adjacently tagged enums + let unit_names: Vec<_> = variants.iter().filter_map(name_for_unit_variant).collect(); + + if unit_names.len() == variants.len() { return quote! { - o.enum_values = Some(vec![#(#names.into()),*]); + enum_values: Some(vec![#(#unit_names.into()),*]), }; } + unimplemented!("work in progress!") } -fn struct_implementation(fields: &[Field]) -> TokenStream { +fn schema_for_struct(fields: &[Field]) -> TokenStream { let recurse = fields.into_iter().map(|f| { let name = f.attrs.name().deserialize_name(); let ty = f.ty; quote_spanned! {f.original.span()=> - o.properties.insert(#name.to_owned(), gen.subschema_for::<#ty>()); + props.insert(#name.to_owned(), gen.subschema_for::<#ty>()); } }); quote! { - #(#recurse)* + properties: { + let mut props = std::collections::BTreeMap::new(); + #(#recurse)* + props + }, } }