Skip to content

Commit 198bdb0

Browse files
committed
first attempt at newtype variant support
1 parent 2032822 commit 198bdb0

File tree

4 files changed

+76
-23
lines changed

4 files changed

+76
-23
lines changed

derive/src/codegen.rs

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,25 +29,13 @@ impl ParseData {
2929
}
3030
}
3131

32-
fn gen_struct(name: Option<&LitStr>, doc: &[String], fields: &[ParseDataField], deny_unknown_fields: bool) -> TokenStream {
33-
let str = path!(::core::primitive::str);
34-
let string = path!(::std::string::String);
35-
let option = path!(::core::option::Option);
36-
37-
let name = match name {
38-
Some(name) => quote!(#option::Some(#name)),
39-
None => quote!(#option::None)
40-
};
41-
let doc = gen_doc_option(doc);
42-
43-
let fields = fields.iter().map(|f| {
44-
let name = &f.name;
45-
let doc = gen_doc_option(&f.doc);
46-
let visit = match &f.ty {
47-
TypeOrInline::Type(ty) => {
32+
impl TypeOrInline {
33+
fn visit_type_fn(&self) -> TokenStream {
34+
match self {
35+
Self::Type(ty) => {
4836
quote_spanned!(ty.span() => <#ty as ::openapi_type::OpenapiType>::visit_type)
4937
},
50-
TypeOrInline::Inline(data) => {
38+
Self::Inline(data) => {
5139
let visit_impl = data.gen_visit_impl();
5240
quote! {
5341
{
@@ -61,7 +49,25 @@ fn gen_struct(name: Option<&LitStr>, doc: &[String], fields: &[ParseDataField],
6149
}
6250
}
6351
}
64-
};
52+
}
53+
}
54+
}
55+
56+
fn gen_struct(name: Option<&LitStr>, doc: &[String], fields: &[ParseDataField], deny_unknown_fields: bool) -> TokenStream {
57+
let str = path!(::core::primitive::str);
58+
let string = path!(::std::string::String);
59+
let option = path!(::core::option::Option);
60+
61+
let name = match name {
62+
Some(name) => quote!(#option::Some(#name)),
63+
None => quote!(#option::None)
64+
};
65+
let doc = gen_doc_option(doc);
66+
67+
let fields = fields.iter().map(|f| {
68+
let name = &f.name;
69+
let doc = gen_doc_option(&f.doc);
70+
let visit = f.ty.visit_type_fn();
6571

6672
if f.flatten {
6773
quote!({

derive/src/parser.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,24 @@ pub(super) fn parse_enum(ident: &Ident, inum: &DataEnum, attrs: &ContainerAttrib
162162
}
163163
}));
164164
},
165+
Fields::Unnamed(unnamed_fields) if unnamed_fields.unnamed.len() == 1 => {
166+
let struct_name = format!("{ident}::{}", name.value());
167+
let ty = unnamed_fields.unnamed.first().unwrap().ty.clone();
168+
// 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+
}));
182+
},
165183
Fields::Unnamed(unnamed_fields) => {
166184
return Err(syn::Error::new(
167185
unnamed_fields.span(),

tests/custom_types.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,22 @@ test_type!(EnumWithOneField = {
7272
}
7373
});
7474

75+
#[derive(OpenapiType)]
76+
enum EnumWithOneNewtypeVariant {
77+
Success(SimpleStruct)
78+
}
79+
test_type!(EnumWithOneNewtypeVariant = {
80+
"type": "object",
81+
"title": "EnumWithOneNewtypeVariant",
82+
"properties": {
83+
"Success": {
84+
"$ref": "#/components/schemas/EnumWithOneNewtypeVariant__Success"
85+
}
86+
},
87+
"required": ["Success"],
88+
"additionalProperties": false
89+
});
90+
7591
#[derive(OpenapiType)]
7692
enum EnumWithFields {
7793
Success { value: isize },

tests/util/test_type.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,18 @@ macro_rules! test_type {
22
($ty:ty = $json:tt) => {
33
paste::paste! {
44
#[test]
5-
fn [< $ty:lower >]() {
5+
fn [< $ty:lower _no_dependencies >]() {
66
let schema = <$ty as OpenapiType>::schema();
7-
let schema_json = serde_json::to_value(&schema.schema).unwrap();
8-
let expected = serde_json::json!($json);
9-
pretty_assertions::assert_eq!(schema_json, expected);
7+
assert!(
8+
schema.dependencies.is_empty(),
9+
"Expected dependencies to be empty, but is {:#?}",
10+
schema.dependencies
11+
);
1012
}
1113
}
1214
};
1315
($ty:ty = $json:tt, {$($dep_name:literal: $dep_json:tt),*}) => {
14-
test_type!($ty = $json);
16+
test_type!(@internal $ty = $json);
1517
paste::paste! {
1618
#[test]
1719
fn [< $ty:lower _dependencies >]() {
@@ -27,4 +29,15 @@ macro_rules! test_type {
2729
}
2830
}
2931
};
32+
(@internal $ty:ty = $json:tt) => {
33+
paste::paste! {
34+
#[test]
35+
fn [< $ty:lower >]() {
36+
let schema = <$ty as OpenapiType>::schema();
37+
let schema_json = serde_json::to_value(&schema.schema).unwrap();
38+
let expected = serde_json::json!($json);
39+
pretty_assertions::assert_eq!(schema_json, expected);
40+
}
41+
}
42+
}
3043
}

0 commit comments

Comments
 (0)