Merge branch 'master' into validate
This commit is contained in:
		
						commit
						b68132f17d
					
				
					 31 changed files with 440 additions and 143 deletions
				
			
		| 
						 | 
				
			
			@ -13,6 +13,10 @@ use syn::Meta::{List, NameValue};
 | 
			
		|||
use syn::MetaNameValue;
 | 
			
		||||
use syn::NestedMeta::{Lit, Meta};
 | 
			
		||||
 | 
			
		||||
// FIXME using the same struct for containers+variants+fields means that
 | 
			
		||||
//  with/schema_with are accepted (but ignored) on containers, and
 | 
			
		||||
//  repr/crate_name are accepted (but ignored) on variants and fields etc.
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Default)]
 | 
			
		||||
pub struct Attrs {
 | 
			
		||||
    pub with: Option<WithAttr>,
 | 
			
		||||
| 
						 | 
				
			
			@ -21,6 +25,7 @@ pub struct Attrs {
 | 
			
		|||
    pub deprecated: bool,
 | 
			
		||||
    pub examples: Vec<syn::Path>,
 | 
			
		||||
    pub repr: Option<syn::Type>,
 | 
			
		||||
    pub crate_name: Option<syn::Path>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
| 
						 | 
				
			
			@ -125,6 +130,16 @@ impl Attrs {
 | 
			
		|||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Meta(NameValue(m)) if m.path.is_ident("crate") && attr_type == "schemars" => {
 | 
			
		||||
                    if let Ok(p) = parse_lit_into_path(errors, attr_type, "crate", &m.lit) {
 | 
			
		||||
                        if self.crate_name.is_some() {
 | 
			
		||||
                            duplicate_error(m)
 | 
			
		||||
                        } else {
 | 
			
		||||
                            self.crate_name = Some(p)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                _ if ignore_errors => {}
 | 
			
		||||
 | 
			
		||||
                Meta(meta_item) => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -125,11 +125,11 @@ impl ValidationAttrs {
 | 
			
		|||
        // `schema_object` - the SchemaObject for the struct that contains this field.
 | 
			
		||||
        let mut statements = Vec::new();
 | 
			
		||||
 | 
			
		||||
        if self.required {
 | 
			
		||||
            statements.push(quote! {
 | 
			
		||||
                schema_object.object().required.insert(#field_name.to_owned());
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        // if self.required {
 | 
			
		||||
        //     statements.push(quote! {
 | 
			
		||||
        //         schema_object.object().required.insert(#field_name.to_owned());
 | 
			
		||||
        //     });
 | 
			
		||||
        // }
 | 
			
		||||
 | 
			
		||||
        let mut array_validation = Vec::new();
 | 
			
		||||
        let mut number_validation = Vec::new();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,7 @@ mod schema_exprs;
 | 
			
		|||
 | 
			
		||||
use ast::*;
 | 
			
		||||
use proc_macro2::TokenStream;
 | 
			
		||||
use syn::spanned::Spanned;
 | 
			
		||||
 | 
			
		||||
#[proc_macro_derive(JsonSchema, attributes(schemars, serde, validate))]
 | 
			
		||||
pub fn derive_json_schema_wrapper(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
 | 
			
		||||
| 
						 | 
				
			
			@ -40,14 +41,20 @@ fn derive_json_schema(
 | 
			
		|||
    attr::process_serde_attrs(&mut input)?;
 | 
			
		||||
 | 
			
		||||
    let cont = Container::from_ast(&input)?;
 | 
			
		||||
    let crate_alias = cont.attrs.crate_name.as_ref().map(|path| {
 | 
			
		||||
        quote_spanned! {path.span()=>
 | 
			
		||||
            use #path as schemars;
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    let type_name = &cont.ident;
 | 
			
		||||
    let (impl_generics, ty_generics, where_clause) = cont.generics.split_for_impl();
 | 
			
		||||
 | 
			
		||||
    if let Some(transparent_field) = cont.transparent_field() {
 | 
			
		||||
        let (ty, type_def) = schema_exprs::type_for_schema(transparent_field, 0);
 | 
			
		||||
        let (ty, type_def) = schema_exprs::type_for_field_schema(transparent_field, 0);
 | 
			
		||||
        return Ok(quote! {
 | 
			
		||||
            const _: () = {
 | 
			
		||||
                #crate_alias
 | 
			
		||||
                #type_def
 | 
			
		||||
 | 
			
		||||
                #[automatically_derived]
 | 
			
		||||
| 
						 | 
				
			
			@ -64,18 +71,12 @@ fn derive_json_schema(
 | 
			
		|||
                        <#ty as schemars::JsonSchema>::json_schema(gen)
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    fn json_schema_for_flatten(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
 | 
			
		||||
                        <#ty as schemars::JsonSchema>::json_schema_for_flatten(gen)
 | 
			
		||||
                    fn _schemars_private_non_optional_json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
 | 
			
		||||
                        <#ty as schemars::JsonSchema>::_schemars_private_non_optional_json_schema(gen)
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    fn add_schema_as_property(
 | 
			
		||||
                        gen: &mut schemars::gen::SchemaGenerator,
 | 
			
		||||
                        parent: &mut schemars::schema::SchemaObject,
 | 
			
		||||
                        name: String,
 | 
			
		||||
                        metadata: Option<schemars::schema::Metadata>,
 | 
			
		||||
                        required: Option<bool>,
 | 
			
		||||
                    ) {
 | 
			
		||||
                        <#ty as schemars::JsonSchema>::add_schema_as_property(gen, parent, name, metadata, required)
 | 
			
		||||
                    fn _schemars_private_is_option() -> bool {
 | 
			
		||||
                        <#ty as schemars::JsonSchema>::_schemars_private_is_option()
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
            };
 | 
			
		||||
| 
						 | 
				
			
			@ -122,16 +123,20 @@ fn derive_json_schema(
 | 
			
		|||
    };
 | 
			
		||||
 | 
			
		||||
    Ok(quote! {
 | 
			
		||||
        #[automatically_derived]
 | 
			
		||||
        #[allow(unused_braces)]
 | 
			
		||||
        impl #impl_generics schemars::JsonSchema for #type_name #ty_generics #where_clause {
 | 
			
		||||
            fn schema_name() -> std::string::String {
 | 
			
		||||
                #schema_name
 | 
			
		||||
            }
 | 
			
		||||
        const _: () = {
 | 
			
		||||
            #crate_alias
 | 
			
		||||
 | 
			
		||||
            fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
 | 
			
		||||
                #schema_expr
 | 
			
		||||
            }
 | 
			
		||||
            #[automatically_derived]
 | 
			
		||||
            #[allow(unused_braces)]
 | 
			
		||||
            impl #impl_generics schemars::JsonSchema for #type_name #ty_generics #where_clause {
 | 
			
		||||
                fn schema_name() -> std::string::String {
 | 
			
		||||
                    #schema_name
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
 | 
			
		||||
                    #schema_expr
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        };
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,7 +49,7 @@ impl<'a> SchemaMetadata<'a> {
 | 
			
		|||
        quote! {
 | 
			
		||||
            {
 | 
			
		||||
                let schema = #schema_expr;
 | 
			
		||||
                gen.apply_metadata(schema, #self)
 | 
			
		||||
                schemars::_private::apply_metadata(schema, #self)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,31 +57,38 @@ pub fn expr_for_repr(cont: &Container) -> Result<TokenStream, syn::Error> {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
fn expr_for_field(field: &Field, allow_ref: bool) -> TokenStream {
 | 
			
		||||
    let (ty, type_def) = type_for_schema(field, 0);
 | 
			
		||||
    let (ty, type_def) = type_for_field_schema(field, 0);
 | 
			
		||||
    let span = field.original.span();
 | 
			
		||||
    let gen = quote!(gen);
 | 
			
		||||
 | 
			
		||||
    if allow_ref {
 | 
			
		||||
        quote_spanned! {span=>
 | 
			
		||||
            {
 | 
			
		||||
                #type_def
 | 
			
		||||
                gen.subschema_for::<#ty>()
 | 
			
		||||
                #gen.subschema_for::<#ty>()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        quote_spanned! {span=>
 | 
			
		||||
            {
 | 
			
		||||
                #type_def
 | 
			
		||||
                <#ty as schemars::JsonSchema>::json_schema(gen)
 | 
			
		||||
                <#ty as schemars::JsonSchema>::json_schema(#gen)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn type_for_schema(field: &Field, local_id: usize) -> (syn::Type, Option<TokenStream>) {
 | 
			
		||||
pub fn type_for_field_schema(field: &Field, local_id: usize) -> (syn::Type, Option<TokenStream>) {
 | 
			
		||||
    match &field.attrs.with {
 | 
			
		||||
        None => (field.ty.to_owned(), None),
 | 
			
		||||
        Some(WithAttr::Type(ty)) => (ty.to_owned(), None),
 | 
			
		||||
        Some(WithAttr::Function(fun)) => {
 | 
			
		||||
        Some(with_attr) => type_for_schema(with_attr, local_id),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn type_for_schema(with_attr: &WithAttr, local_id: usize) -> (syn::Type, Option<TokenStream>) {
 | 
			
		||||
    match with_attr {
 | 
			
		||||
        WithAttr::Type(ty) => (ty.to_owned(), None),
 | 
			
		||||
        WithAttr::Function(fun) => {
 | 
			
		||||
            let ty_name = format_ident!("_SchemarsSchemaWithFunction{}", local_id);
 | 
			
		||||
            let fn_name = fun.segments.last().unwrap().ident.to_string();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -315,9 +322,14 @@ fn expr_for_adjacent_tagged_enum<'a>(
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
fn expr_for_untagged_enum_variant(variant: &Variant, deny_unknown_fields: bool) -> TokenStream {
 | 
			
		||||
    if let Some(WithAttr::Type(with)) = &variant.attrs.with {
 | 
			
		||||
    if let Some(with_attr) = &variant.attrs.with {
 | 
			
		||||
        let (ty, type_def) = type_for_schema(with_attr, 0);
 | 
			
		||||
        let gen = quote!(gen);
 | 
			
		||||
        return quote_spanned! {variant.original.span()=>
 | 
			
		||||
            gen.subschema_for::<#with>()
 | 
			
		||||
            {
 | 
			
		||||
                #type_def
 | 
			
		||||
                #gen.subschema_for::<#ty>()
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -333,9 +345,14 @@ fn expr_for_untagged_enum_variant_for_flatten(
 | 
			
		|||
    variant: &Variant,
 | 
			
		||||
    deny_unknown_fields: bool,
 | 
			
		||||
) -> Option<TokenStream> {
 | 
			
		||||
    if let Some(WithAttr::Type(with)) = &variant.attrs.with {
 | 
			
		||||
    if let Some(with_attr) = &variant.attrs.with {
 | 
			
		||||
        let (ty, type_def) = type_for_schema(with_attr, 0);
 | 
			
		||||
        let gen = quote!(gen);
 | 
			
		||||
        return Some(quote_spanned! {variant.original.span()=>
 | 
			
		||||
            <#with as schemars::JsonSchema>::json_schema(gen)
 | 
			
		||||
            {
 | 
			
		||||
                #type_def
 | 
			
		||||
                <#ty as schemars::JsonSchema>::json_schema(#gen)
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -362,7 +379,7 @@ fn expr_for_tuple_struct(fields: &[Field]) -> TokenStream {
 | 
			
		|||
        .iter()
 | 
			
		||||
        .filter(|f| !f.serde_attrs.skip_deserializing())
 | 
			
		||||
        .enumerate()
 | 
			
		||||
        .map(|(i, f)| type_for_schema(f, i))
 | 
			
		||||
        .map(|(i, f)| type_for_field_schema(f, i))
 | 
			
		||||
        .unzip();
 | 
			
		||||
    quote! {
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -409,20 +426,16 @@ fn expr_for_struct(
 | 
			
		|||
                ..SchemaMetadata::from_attrs(&field.attrs)
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            let (ty, type_def) = type_for_schema(field, type_defs.len());
 | 
			
		||||
            let (ty, type_def) = type_for_field_schema(field, type_defs.len());
 | 
			
		||||
            if let Some(type_def) = type_def {
 | 
			
		||||
                type_defs.push(type_def);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let args = quote!(gen, &mut schema_object, #name.to_owned(), #metadata, #required);
 | 
			
		||||
            let validation = field.validation_attrs.validation_statements(&name);
 | 
			
		||||
 | 
			
		||||
            quote_spanned! {ty.span()=>
 | 
			
		||||
                <#ty as schemars::JsonSchema>::add_schema_as_property(
 | 
			
		||||
                    gen,
 | 
			
		||||
                    &mut schema_object,
 | 
			
		||||
                    #name.to_owned(),
 | 
			
		||||
                    #metadata,
 | 
			
		||||
                    #required);
 | 
			
		||||
                schemars::_private::add_schema_as_property::<#ty>(#args);
 | 
			
		||||
                #validation
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
| 
						 | 
				
			
			@ -431,13 +444,14 @@ fn expr_for_struct(
 | 
			
		|||
    let flattens: Vec<_> = flattened_fields
 | 
			
		||||
        .into_iter()
 | 
			
		||||
        .map(|field| {
 | 
			
		||||
            let (ty, type_def) = type_for_schema(field, type_defs.len());
 | 
			
		||||
            let (ty, type_def) = type_for_field_schema(field, type_defs.len());
 | 
			
		||||
            if let Some(type_def) = type_def {
 | 
			
		||||
                type_defs.push(type_def);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let gen = quote!(gen);
 | 
			
		||||
            quote_spanned! {ty.span()=>
 | 
			
		||||
                .flatten(<#ty as schemars::JsonSchema>::json_schema_for_flatten(gen))
 | 
			
		||||
                .flatten(schemars::_private::json_schema_for_flatten::<#ty>(#gen))
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
        .collect();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue