Skip to content

Commit 7f01d65

Browse files
committed
fix newtype variant impl
1 parent 198bdb0 commit 7f01d65

File tree

3 files changed

+65
-54
lines changed

3 files changed

+65
-54
lines changed

derive/src/codegen.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ fn gen_enum(name: Option<&LitStr>, doc: &[String], variants: &[LitStr]) -> Token
141141
}
142142
}
143143

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

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

175175
#({
176176
let visitor = ::openapi_type::AlternativesVisitor::visit_alternative(alt_visitor);
177-
#impls
177+
let visit_type_fn = #fns;
178+
visit_type_fn(visitor);
178179
})*
179180
}
180181
}

derive/src/parser.rs

Lines changed: 31 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub(super) enum ParseDataType {
3737
variants: Vec<LitStr>
3838
},
3939
Alternatives {
40-
alts: Vec<ParseData>
40+
alts: Vec<TypeOrInline>
4141
},
4242
Unit
4343
}
@@ -142,7 +142,7 @@ pub(super) fn parse_struct(ident: &Ident, strukt: &DataStruct, attrs: &Container
142142

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

147147
for v in &inum.variants {
148148
let name = v.ident.to_lit_str();
@@ -151,34 +151,24 @@ pub(super) fn parse_enum(ident: &Ident, inum: &DataEnum, attrs: &ContainerAttrib
151151
let fields = parse_named_fields(named_fields, attrs.rename_all.as_ref())?;
152152
let struct_name = format!("{ident}::{}", name.value());
153153
// TODO add documentation here
154-
types.push((name, ParseData {
155-
name: Some(struct_name.to_lit_str()),
156-
doc: Vec::new(),
157-
ty: ParseDataType::Struct {
158-
fields,
159-
// serde seems to only allow this attribute on the outer
160-
// container, not on a per-variant basis
161-
deny_unknown_fields: attrs.deny_unknown_fields
162-
}
163-
}));
154+
types.push((
155+
name,
156+
TypeOrInline::Inline(ParseData {
157+
name: Some(struct_name.to_lit_str()),
158+
doc: Vec::new(),
159+
ty: ParseDataType::Struct {
160+
fields,
161+
// serde seems to only allow this attribute on the outer
162+
// container, not on a per-variant basis
163+
deny_unknown_fields: attrs.deny_unknown_fields
164+
}
165+
})
166+
));
164167
},
165168
Fields::Unnamed(unnamed_fields) if unnamed_fields.unnamed.len() == 1 => {
166-
let struct_name = format!("{ident}::{}", name.value());
167169
let ty = unnamed_fields.unnamed.first().unwrap().ty.clone();
168170
// TODO add documentation here
169-
types.push((name.clone(), ParseData {
170-
name: Some(struct_name.to_lit_str()),
171-
doc: Vec::new(),
172-
ty: ParseDataType::Struct {
173-
fields: vec![ParseDataField {
174-
name,
175-
doc: Vec::new(),
176-
ty: TypeOrInline::Type(Box::new(ty)),
177-
flatten: false
178-
}],
179-
deny_unknown_fields: attrs.deny_unknown_fields
180-
}
181-
}));
171+
types.push((name, TypeOrInline::Type(Box::new(ty))));
182172
},
183173
Fields::Unnamed(unnamed_fields) => {
184174
return Err(syn::Error::new(
@@ -231,27 +221,27 @@ pub(super) fn parse_enum(ident: &Ident, inum: &DataEnum, attrs: &ContainerAttrib
231221
// externally tagged (default)
232222
(None, None, false) => {
233223
let struct_name = format!("{ident}::{}::ExtTagWrapper", name.value());
234-
ParseData {
224+
TypeOrInline::Inline(ParseData {
235225
name: Some(struct_name.to_lit_str()),
236226
doc: Vec::new(),
237227
ty: ParseDataType::Struct {
238228
fields: vec![ParseDataField {
239229
name,
240230
doc: Vec::new(),
241-
ty: TypeOrInline::Inline(data),
231+
ty: data,
242232
flatten: false
243233
}],
244234
deny_unknown_fields: true
245235
}
246-
}
236+
})
247237
},
248238
// internally tagged
249239
(Some(tag), None, false) => {
250240
match &mut data {
251-
ParseData {
241+
TypeOrInline::Inline(ParseData {
252242
ty: ParseDataType::Struct { fields, .. },
253243
..
254-
} => fields.push(ParseDataField {
244+
}) => fields.push(ParseDataField {
255245
name: tag.clone(),
256246
doc: Vec::new(),
257247
ty: TypeOrInline::Inline(ParseData {
@@ -271,7 +261,7 @@ pub(super) fn parse_enum(ident: &Ident, inum: &DataEnum, attrs: &ContainerAttrib
271261
// adjacently tagged
272262
(Some(tag), Some(content), false) => {
273263
let struct_name = format!("{ident}::{}::AdjTagWrapper", name.value());
274-
ParseData {
264+
TypeOrInline::Inline(ParseData {
275265
name: Some(struct_name.to_lit_str()),
276266
doc: Vec::new(),
277267
ty: ParseDataType::Struct {
@@ -289,13 +279,13 @@ pub(super) fn parse_enum(ident: &Ident, inum: &DataEnum, attrs: &ContainerAttrib
289279
ParseDataField {
290280
name: content.clone(),
291281
doc: Vec::new(),
292-
ty: TypeOrInline::Inline(data),
282+
ty: data,
293283
flatten: false
294284
},
295285
],
296286
deny_unknown_fields: true
297287
}
298-
}
288+
})
299289
},
300290
// untagged
301291
(None, None, true) => data,
@@ -322,10 +312,13 @@ pub(super) fn parse_enum(ident: &Ident, inum: &DataEnum, attrs: &ContainerAttrib
322312
ty: ParseDataType::Alternatives { mut alts },
323313
..
324314
})
325-
) if alts.len() == 1 => Ok(ParseData {
315+
) if alts.len() == 1 && matches!(alts.first().unwrap(), TypeOrInline::Inline(..)) => Ok(ParseData {
326316
name: Some(ident.to_lit_str()),
327317
doc: attrs.doc.clone(),
328-
ty: alts.remove(0).ty
318+
ty: match alts.remove(0) {
319+
TypeOrInline::Inline(data) => data.ty,
320+
_ => unreachable!() // if condition above
321+
}
329322
}),
330323
// only variants with fields
331324
(None, Some(data)) => Ok(data),
@@ -336,11 +329,11 @@ pub(super) fn parse_enum(ident: &Ident, inum: &DataEnum, attrs: &ContainerAttrib
336329
// data_types always produces Alternatives
337330
_ => unreachable!()
338331
};
339-
alts.push(ParseData {
332+
alts.push(TypeOrInline::Inline(ParseData {
340333
name: None,
341334
doc: Vec::new(),
342335
ty: data_strings
343-
});
336+
}));
344337
Ok(data_types)
345338
},
346339
// no variants

tests/custom_types.rs

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -81,16 +81,30 @@ test_type!(EnumWithOneNewtypeVariant = {
8181
"title": "EnumWithOneNewtypeVariant",
8282
"properties": {
8383
"Success": {
84-
"$ref": "#/components/schemas/EnumWithOneNewtypeVariant__Success"
84+
"$ref": "#/components/schemas/SimpleStruct"
8585
}
8686
},
8787
"required": ["Success"],
8888
"additionalProperties": false
89+
}, {
90+
"SimpleStruct": {
91+
"type": "object",
92+
"title": "SimpleStruct",
93+
"properties": {
94+
"foo": {
95+
"type": "string"
96+
},
97+
"bar": {
98+
"type": "integer"
99+
}
100+
},
101+
"required": ["foo", "bar"]
102+
}
89103
});
90104

91105
#[derive(OpenapiType)]
92106
enum EnumWithFields {
93-
Success { value: isize },
107+
Success(SimpleStruct),
94108
Error { msg: String }
95109
}
96110
test_type!(EnumWithFields = {
@@ -101,22 +115,12 @@ test_type!(EnumWithFields = {
101115
"$ref": "#/components/schemas/EnumWithFields__Error__ExtTagWrapper"
102116
}]
103117
}, {
104-
"EnumWithFields__Success": {
105-
"title": "EnumWithFields::Success",
106-
"type": "object",
107-
"properties": {
108-
"value": {
109-
"type": "integer"
110-
}
111-
},
112-
"required": ["value"]
113-
},
114118
"EnumWithFields__Success__ExtTagWrapper": {
115119
"title": "EnumWithFields::Success::ExtTagWrapper",
116120
"type": "object",
117121
"properties": {
118122
"Success": {
119-
"$ref": "#/components/schemas/EnumWithFields__Success"
123+
"$ref": "#/components/schemas/SimpleStruct"
120124
}
121125
},
122126
"required": ["Success"],
@@ -142,6 +146,19 @@ test_type!(EnumWithFields = {
142146
},
143147
"required": ["Error"],
144148
"additionalProperties": false
149+
},
150+
"SimpleStruct": {
151+
"type": "object",
152+
"title": "SimpleStruct",
153+
"properties": {
154+
"foo": {
155+
"type": "string"
156+
},
157+
"bar": {
158+
"type": "integer"
159+
}
160+
},
161+
"required": ["foo", "bar"]
145162
}
146163
});
147164

0 commit comments

Comments
 (0)