From 9e507272dab27a65717e7a6f70ceb5e0ff9f2480 Mon Sep 17 00:00:00 2001 From: Graham Esau Date: Fri, 16 Apr 2021 13:56:26 +0100 Subject: [PATCH] Process validation attributes in tuple structs --- schemars/tests/expected/validate_tuple.json | 18 +++++++++++ schemars/tests/validate.rs | 11 +++++++ schemars_derive/src/schema_exprs.rs | 36 +++++++++++++++------ 3 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 schemars/tests/expected/validate_tuple.json diff --git a/schemars/tests/expected/validate_tuple.json b/schemars/tests/expected/validate_tuple.json new file mode 100644 index 0000000..8ab6eaa --- /dev/null +++ b/schemars/tests/expected/validate_tuple.json @@ -0,0 +1,18 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Tuple", + "type": "array", + "items": [ + { + "type": "integer", + "format": "uint8", + "maximum": 10.0, + "minimum": 0.0 + }, + { + "type": "boolean" + } + ], + "maxItems": 2, + "minItems": 2 +} \ No newline at end of file diff --git a/schemars/tests/validate.rs b/schemars/tests/validate.rs index 8992df2..00d1b57 100644 --- a/schemars/tests/validate.rs +++ b/schemars/tests/validate.rs @@ -47,6 +47,17 @@ fn validate() -> TestResult { test_default_generated_schema::("validate") } +#[derive(Debug, JsonSchema)] +pub struct Tuple( + #[validate(range(max = 10))] u8, + #[validate(required)] Option, +); + +#[test] +fn validate_tuple() -> TestResult { + test_default_generated_schema::("validate_tuple") +} + #[derive(Debug, JsonSchema)] pub struct NewType(#[validate(range(max = 10))] u8); diff --git a/schemars_derive/src/schema_exprs.rs b/schemars_derive/src/schema_exprs.rs index 261d6bc..739641c 100644 --- a/schemars_derive/src/schema_exprs.rs +++ b/schemars_derive/src/schema_exprs.rs @@ -61,7 +61,14 @@ fn expr_for_field(field: &Field, allow_ref: bool) -> TokenStream { let span = field.original.span(); let gen = quote!(gen); - field.validation_attrs.apply_to_schema(if allow_ref { + let schema_expr = if field.validation_attrs.required { + quote_spanned! {span=> + { + #type_def + <#ty as schemars::JsonSchema>::_schemars_private_non_optional_json_schema(#gen) + } + } + } else if allow_ref { quote_spanned! {span=> { #type_def @@ -75,7 +82,8 @@ fn expr_for_field(field: &Field, allow_ref: bool) -> TokenStream { <#ty as schemars::JsonSchema>::json_schema(#gen) } } - }) + }; + field.validation_attrs.apply_to_schema(schema_expr) } pub fn type_for_field_schema(field: &Field, local_id: usize) -> (syn::Type, Option) { @@ -375,17 +383,25 @@ fn expr_for_newtype_struct(field: &Field) -> TokenStream { } fn expr_for_tuple_struct(fields: &[Field]) -> TokenStream { - let (types, type_defs): (Vec<_>, Vec<_>) = fields + let fields: Vec<_> = fields .iter() .filter(|f| !f.serde_attrs.skip_deserializing()) - .enumerate() - .map(|(i, f)| type_for_field_schema(f, i)) - .unzip(); + .map(|f| expr_for_field(f, true)) + .collect(); + let len = fields.len() as u32; + quote! { - { - #(#type_defs)* - gen.subschema_for::<(#(#types),*)>() - } + schemars::schema::Schema::Object( + schemars::schema::SchemaObject { + instance_type: Some(schemars::schema::InstanceType::Array.into()), + array: Some(Box::new(schemars::schema::ArrayValidation { + items: Some(vec![#(#fields),*].into()), + max_items: Some(#len), + min_items: Some(#len), + ..Default::default() + })), + ..Default::default() + }) } }