Skip to content

Commit

Permalink
fix newtype variant impl
Browse files Browse the repository at this point in the history
  • Loading branch information
msrd0 committed Mar 12, 2022
1 parent 198bdb0 commit 7f01d65
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 54 deletions.
7 changes: 4 additions & 3 deletions derive/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ fn gen_enum(name: Option<&LitStr>, doc: &[String], variants: &[LitStr]) -> Token
}
}

fn gen_alt(name: Option<&LitStr>, doc: &[String], alt: &[ParseData]) -> TokenStream {
fn gen_alt(name: Option<&LitStr>, doc: &[String], alt: &[TypeOrInline]) -> TokenStream {
let str = path!(::core::primitive::str);
let string = path!(::std::string::String);
let option = path!(::core::option::Option);
Expand All @@ -152,7 +152,7 @@ fn gen_alt(name: Option<&LitStr>, doc: &[String], alt: &[ParseData]) -> TokenStr
};
let doc = gen_doc_option(doc);

let impls = alt.into_iter().map(|alt| alt.gen_visit_impl());
let fns = alt.into_iter().map(|alt| alt.visit_type_fn());
quote! {
const OBJECT_NAME: #option<&'static #str> = #name;
const OBJECT_DOC: #option<&'static #str> = #doc;
Expand All @@ -174,7 +174,8 @@ fn gen_alt(name: Option<&LitStr>, doc: &[String], alt: &[ParseData]) -> TokenStr

#({
let visitor = ::openapi_type::AlternativesVisitor::visit_alternative(alt_visitor);
#impls
let visit_type_fn = #fns;
visit_type_fn(visitor);
})*
}
}
Expand Down
69 changes: 31 additions & 38 deletions derive/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub(super) enum ParseDataType {
variants: Vec<LitStr>
},
Alternatives {
alts: Vec<ParseData>
alts: Vec<TypeOrInline>
},
Unit
}
Expand Down Expand Up @@ -142,7 +142,7 @@ pub(super) fn parse_struct(ident: &Ident, strukt: &DataStruct, attrs: &Container

pub(super) fn parse_enum(ident: &Ident, inum: &DataEnum, attrs: &ContainerAttributes) -> syn::Result<ParseData> {
let mut strings: Vec<LitStr> = Vec::new();
let mut types: Vec<(LitStr, ParseData)> = Vec::new();
let mut types: Vec<(LitStr, TypeOrInline)> = Vec::new();

for v in &inum.variants {
let name = v.ident.to_lit_str();
Expand All @@ -151,34 +151,24 @@ pub(super) fn parse_enum(ident: &Ident, inum: &DataEnum, attrs: &ContainerAttrib
let fields = parse_named_fields(named_fields, attrs.rename_all.as_ref())?;
let struct_name = format!("{ident}::{}", name.value());
// TODO add documentation here
types.push((name, ParseData {
name: Some(struct_name.to_lit_str()),
doc: Vec::new(),
ty: ParseDataType::Struct {
fields,
// serde seems to only allow this attribute on the outer
// container, not on a per-variant basis
deny_unknown_fields: attrs.deny_unknown_fields
}
}));
types.push((
name,
TypeOrInline::Inline(ParseData {
name: Some(struct_name.to_lit_str()),
doc: Vec::new(),
ty: ParseDataType::Struct {
fields,
// serde seems to only allow this attribute on the outer
// container, not on a per-variant basis
deny_unknown_fields: attrs.deny_unknown_fields
}
})
));
},
Fields::Unnamed(unnamed_fields) if unnamed_fields.unnamed.len() == 1 => {
let struct_name = format!("{ident}::{}", name.value());
let ty = unnamed_fields.unnamed.first().unwrap().ty.clone();
// TODO add documentation here
types.push((name.clone(), ParseData {
name: Some(struct_name.to_lit_str()),
doc: Vec::new(),
ty: ParseDataType::Struct {
fields: vec![ParseDataField {
name,
doc: Vec::new(),
ty: TypeOrInline::Type(Box::new(ty)),
flatten: false
}],
deny_unknown_fields: attrs.deny_unknown_fields
}
}));
types.push((name, TypeOrInline::Type(Box::new(ty))));
},
Fields::Unnamed(unnamed_fields) => {
return Err(syn::Error::new(
Expand Down Expand Up @@ -231,27 +221,27 @@ pub(super) fn parse_enum(ident: &Ident, inum: &DataEnum, attrs: &ContainerAttrib
// externally tagged (default)
(None, None, false) => {
let struct_name = format!("{ident}::{}::ExtTagWrapper", name.value());
ParseData {
TypeOrInline::Inline(ParseData {
name: Some(struct_name.to_lit_str()),
doc: Vec::new(),
ty: ParseDataType::Struct {
fields: vec![ParseDataField {
name,
doc: Vec::new(),
ty: TypeOrInline::Inline(data),
ty: data,
flatten: false
}],
deny_unknown_fields: true
}
}
})
},
// internally tagged
(Some(tag), None, false) => {
match &mut data {
ParseData {
TypeOrInline::Inline(ParseData {
ty: ParseDataType::Struct { fields, .. },
..
} => fields.push(ParseDataField {
}) => fields.push(ParseDataField {
name: tag.clone(),
doc: Vec::new(),
ty: TypeOrInline::Inline(ParseData {
Expand All @@ -271,7 +261,7 @@ pub(super) fn parse_enum(ident: &Ident, inum: &DataEnum, attrs: &ContainerAttrib
// adjacently tagged
(Some(tag), Some(content), false) => {
let struct_name = format!("{ident}::{}::AdjTagWrapper", name.value());
ParseData {
TypeOrInline::Inline(ParseData {
name: Some(struct_name.to_lit_str()),
doc: Vec::new(),
ty: ParseDataType::Struct {
Expand All @@ -289,13 +279,13 @@ pub(super) fn parse_enum(ident: &Ident, inum: &DataEnum, attrs: &ContainerAttrib
ParseDataField {
name: content.clone(),
doc: Vec::new(),
ty: TypeOrInline::Inline(data),
ty: data,
flatten: false
},
],
deny_unknown_fields: true
}
}
})
},
// untagged
(None, None, true) => data,
Expand All @@ -322,10 +312,13 @@ pub(super) fn parse_enum(ident: &Ident, inum: &DataEnum, attrs: &ContainerAttrib
ty: ParseDataType::Alternatives { mut alts },
..
})
) if alts.len() == 1 => Ok(ParseData {
) if alts.len() == 1 && matches!(alts.first().unwrap(), TypeOrInline::Inline(..)) => Ok(ParseData {
name: Some(ident.to_lit_str()),
doc: attrs.doc.clone(),
ty: alts.remove(0).ty
ty: match alts.remove(0) {
TypeOrInline::Inline(data) => data.ty,
_ => unreachable!() // if condition above
}
}),
// only variants with fields
(None, Some(data)) => Ok(data),
Expand All @@ -336,11 +329,11 @@ pub(super) fn parse_enum(ident: &Ident, inum: &DataEnum, attrs: &ContainerAttrib
// data_types always produces Alternatives
_ => unreachable!()
};
alts.push(ParseData {
alts.push(TypeOrInline::Inline(ParseData {
name: None,
doc: Vec::new(),
ty: data_strings
});
}));
Ok(data_types)
},
// no variants
Expand Down
43 changes: 30 additions & 13 deletions tests/custom_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,30 @@ test_type!(EnumWithOneNewtypeVariant = {
"title": "EnumWithOneNewtypeVariant",
"properties": {
"Success": {
"$ref": "#/components/schemas/EnumWithOneNewtypeVariant__Success"
"$ref": "#/components/schemas/SimpleStruct"
}
},
"required": ["Success"],
"additionalProperties": false
}, {
"SimpleStruct": {
"type": "object",
"title": "SimpleStruct",
"properties": {
"foo": {
"type": "string"
},
"bar": {
"type": "integer"
}
},
"required": ["foo", "bar"]
}
});

#[derive(OpenapiType)]
enum EnumWithFields {
Success { value: isize },
Success(SimpleStruct),
Error { msg: String }
}
test_type!(EnumWithFields = {
Expand All @@ -101,22 +115,12 @@ test_type!(EnumWithFields = {
"$ref": "#/components/schemas/EnumWithFields__Error__ExtTagWrapper"
}]
}, {
"EnumWithFields__Success": {
"title": "EnumWithFields::Success",
"type": "object",
"properties": {
"value": {
"type": "integer"
}
},
"required": ["value"]
},
"EnumWithFields__Success__ExtTagWrapper": {
"title": "EnumWithFields::Success::ExtTagWrapper",
"type": "object",
"properties": {
"Success": {
"$ref": "#/components/schemas/EnumWithFields__Success"
"$ref": "#/components/schemas/SimpleStruct"
}
},
"required": ["Success"],
Expand All @@ -142,6 +146,19 @@ test_type!(EnumWithFields = {
},
"required": ["Error"],
"additionalProperties": false
},
"SimpleStruct": {
"type": "object",
"title": "SimpleStruct",
"properties": {
"foo": {
"type": "string"
},
"bar": {
"type": "integer"
}
},
"required": ["foo", "bar"]
}
});

Expand Down

0 comments on commit 7f01d65

Please sign in to comment.