parent
8207892fa6
commit
11b7a09c93
4 changed files with 235 additions and 3 deletions
|
@ -59,3 +59,19 @@ pub enum Untagged {
|
|||
fn enum_untagged() -> TestResult {
|
||||
test_default_generated_schema::<Untagged>("enum-untagged")
|
||||
}
|
||||
|
||||
#[derive(Debug, JsonSchema)]
|
||||
#[schemars(tag = "t", content = "c")]
|
||||
pub enum Adjacent {
|
||||
UnitOne,
|
||||
StringMap(Map<String, String>),
|
||||
UnitStructNewType(UnitStruct),
|
||||
StructNewType(Struct),
|
||||
Struct { foo: i32, bar: bool },
|
||||
Tuple(i32, bool),
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enum_adjacent_tagged() -> TestResult {
|
||||
test_default_generated_schema::<Adjacent>("enum_adjacent_tagged-untagged")
|
||||
}
|
||||
|
|
150
schemars/tests/expected/enum_adjacent_tagged-untagged.json
Normal file
150
schemars/tests/expected/enum_adjacent_tagged-untagged.json
Normal file
|
@ -0,0 +1,150 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Adjacent",
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"t"
|
||||
],
|
||||
"properties": {
|
||||
"t": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"UnitOne"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"c",
|
||||
"t"
|
||||
],
|
||||
"properties": {
|
||||
"c": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"t": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"StringMap"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"c",
|
||||
"t"
|
||||
],
|
||||
"properties": {
|
||||
"c": {
|
||||
"type": "null"
|
||||
},
|
||||
"t": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"UnitStructNewType"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"c",
|
||||
"t"
|
||||
],
|
||||
"properties": {
|
||||
"c": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"bar",
|
||||
"foo"
|
||||
],
|
||||
"properties": {
|
||||
"bar": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"foo": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"StructNewType"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"c",
|
||||
"t"
|
||||
],
|
||||
"properties": {
|
||||
"c": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"bar",
|
||||
"foo"
|
||||
],
|
||||
"properties": {
|
||||
"bar": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"foo": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Struct"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"c",
|
||||
"t"
|
||||
],
|
||||
"properties": {
|
||||
"c": {
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
{
|
||||
"type": "boolean"
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
},
|
||||
"t": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Tuple"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -11,8 +11,7 @@ static SERDE_KEYWORDS: &[&str] = &[
|
|||
// TODO: for structs with `deny_unknown_fields`, set schema's `additionalProperties` to false.
|
||||
// "deny_unknown_fields",
|
||||
"tag",
|
||||
// TODO: support adjecently tagged enums (https://github.com/GREsau/schemars/issues/4)
|
||||
// "content",
|
||||
"content",
|
||||
"untagged",
|
||||
"default",
|
||||
"skip",
|
||||
|
|
|
@ -131,7 +131,9 @@ fn schema_for_enum(variants: &[Variant], cattrs: &serde_attr::Container) -> Toke
|
|||
TagType::External => schema_for_external_tagged_enum(variants),
|
||||
TagType::None => schema_for_untagged_enum(variants),
|
||||
TagType::Internal { tag } => schema_for_internal_tagged_enum(variants, tag),
|
||||
TagType::Adjacent { .. } => unimplemented!("Adjacent tagged enums not yet supported."),
|
||||
TagType::Adjacent { tag, content } => {
|
||||
schema_for_adjacent_tagged_enum(variants, tag, content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -268,6 +270,71 @@ fn schema_for_untagged_enum_variant(variant: &Variant) -> TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
fn schema_for_adjacent_tagged_enum<'a>(
|
||||
variants: impl Iterator<Item = &'a Variant<'a>>,
|
||||
tag_name: &str,
|
||||
content_name: &str,
|
||||
) -> TokenStream {
|
||||
let schemas = variants.map(|variant| {
|
||||
let content_schema = match variant.style {
|
||||
Style::Unit => None,
|
||||
Style::Newtype => {
|
||||
let field = &variant.fields[0];
|
||||
let ty = get_json_schema_type(field);
|
||||
Some(quote_spanned! {field.original.span()=>
|
||||
<#ty>::json_schema(gen)
|
||||
})
|
||||
}
|
||||
Style::Struct => Some(schema_for_struct(&variant.fields, None)),
|
||||
Style::Tuple => Some(schema_for_tuple_struct(&variant.fields)),
|
||||
};
|
||||
|
||||
let (add_content_property, add_content_required) = content_schema
|
||||
.map(|content_schema| {
|
||||
(
|
||||
quote!(props.insert(#content_name.to_owned(), #content_schema);),
|
||||
quote!(required.insert(#content_name.to_owned());),
|
||||
)
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
let name = variant.attrs.name().deserialize_name();
|
||||
let tag_schema = wrap_schema_fields(quote! {
|
||||
instance_type: Some(schemars::schema::InstanceType::String.into()),
|
||||
enum_values: Some(vec![#name.into()]),
|
||||
});
|
||||
|
||||
let outer_schema = wrap_schema_fields(quote! {
|
||||
instance_type: Some(schemars::schema::InstanceType::Object.into()),
|
||||
object: Some(Box::new(schemars::schema::ObjectValidation {
|
||||
properties: {
|
||||
let mut props = schemars::Map::new();
|
||||
props.insert(#tag_name.to_owned(), #tag_schema);
|
||||
#add_content_property
|
||||
props
|
||||
},
|
||||
required: {
|
||||
let mut required = schemars::Set::new();
|
||||
required.insert(#tag_name.to_owned());
|
||||
#add_content_required
|
||||
required
|
||||
},
|
||||
..Default::default()
|
||||
})),
|
||||
});
|
||||
|
||||
let doc_metadata = SchemaMetadata::from_doc_attrs(&variant.original.attrs);
|
||||
doc_metadata.apply_to_schema(outer_schema)
|
||||
});
|
||||
|
||||
wrap_schema_fields(quote! {
|
||||
subschemas: Some(Box::new(schemars::schema::SubschemaValidation {
|
||||
any_of: Some(vec![#(#schemas),*]),
|
||||
..Default::default()
|
||||
})),
|
||||
})
|
||||
}
|
||||
|
||||
fn schema_for_unit_struct() -> TokenStream {
|
||||
quote! {
|
||||
gen.subschema_for::<()>()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue