utoipa_gen/component/schema/
features.rs

1use syn::{
2    parse::{Parse, ParseBuffer, ParseStream},
3    Attribute,
4};
5
6use crate::{
7    component::features::{
8        attributes::{
9            AdditionalProperties, As, Bound, ContentEncoding, ContentMediaType, Deprecated,
10            Description, Discriminator, Example, Examples, Format, Ignore, Inline, NoRecursion,
11            Nullable, ReadOnly, Rename, RenameAll, Required, SchemaWith, Title, ValueType,
12            WriteOnly, XmlAttr,
13        },
14        impl_into_inner, impl_merge, parse_features,
15        validation::{
16            ExclusiveMaximum, ExclusiveMinimum, MaxItems, MaxLength, MaxProperties, Maximum,
17            MinItems, MinLength, MinProperties, Minimum, MultipleOf, Pattern,
18        },
19        Feature, Merge,
20    },
21    Diagnostics,
22};
23
24#[cfg_attr(feature = "debug", derive(Debug))]
25pub struct NamedFieldStructFeatures(Vec<Feature>);
26
27impl Parse for NamedFieldStructFeatures {
28    fn parse(input: ParseStream) -> syn::Result<Self> {
29        Ok(NamedFieldStructFeatures(parse_features!(
30            input as Example,
31            Examples,
32            XmlAttr,
33            Title,
34            RenameAll,
35            MaxProperties,
36            MinProperties,
37            As,
38            crate::component::features::attributes::Default,
39            Deprecated,
40            Description,
41            Bound,
42            NoRecursion
43        )))
44    }
45}
46
47impl_into_inner!(NamedFieldStructFeatures);
48
49#[cfg_attr(feature = "debug", derive(Debug))]
50pub struct UnnamedFieldStructFeatures(Vec<Feature>);
51
52impl Parse for UnnamedFieldStructFeatures {
53    fn parse(input: ParseStream) -> syn::Result<Self> {
54        Ok(UnnamedFieldStructFeatures(parse_features!(
55            input as Example,
56            Examples,
57            crate::component::features::attributes::Default,
58            Title,
59            Format,
60            ValueType,
61            As,
62            Deprecated,
63            Description,
64            ContentEncoding,
65            ContentMediaType,
66            Bound,
67            NoRecursion,
68            Pattern
69        )))
70    }
71}
72
73impl_into_inner!(UnnamedFieldStructFeatures);
74
75pub struct EnumFeatures(Vec<Feature>);
76
77impl Parse for EnumFeatures {
78    fn parse(input: ParseStream) -> syn::Result<Self> {
79        Ok(EnumFeatures(parse_features!(
80            input as Example,
81            Examples,
82            crate::component::features::attributes::Default,
83            Title,
84            RenameAll,
85            As,
86            Deprecated,
87            Description,
88            Bound
89        )))
90    }
91}
92
93impl_into_inner!(EnumFeatures);
94
95pub struct MixedEnumFeatures(Vec<Feature>);
96
97impl Parse for MixedEnumFeatures {
98    fn parse(input: ParseStream) -> syn::Result<Self> {
99        Ok(MixedEnumFeatures(parse_features!(
100            input as Example,
101            Examples,
102            crate::component::features::attributes::Default,
103            Title,
104            RenameAll,
105            As,
106            Deprecated,
107            Description,
108            Discriminator,
109            NoRecursion
110        )))
111    }
112}
113
114impl_into_inner!(MixedEnumFeatures);
115
116pub struct NamedFieldFeatures(Vec<Feature>);
117
118impl Parse for NamedFieldFeatures {
119    fn parse(input: ParseStream) -> syn::Result<Self> {
120        Ok(NamedFieldFeatures(parse_features!(
121            input as Example,
122            Examples,
123            ValueType,
124            Format,
125            crate::component::features::attributes::Default,
126            WriteOnly,
127            ReadOnly,
128            XmlAttr,
129            Inline,
130            Nullable,
131            Rename,
132            MultipleOf,
133            Maximum,
134            Minimum,
135            ExclusiveMaximum,
136            ExclusiveMinimum,
137            MaxLength,
138            MinLength,
139            Pattern,
140            MaxItems,
141            MinItems,
142            SchemaWith,
143            AdditionalProperties,
144            Required,
145            Deprecated,
146            ContentEncoding,
147            ContentMediaType,
148            Ignore,
149            NoRecursion
150        )))
151    }
152}
153
154impl_into_inner!(NamedFieldFeatures);
155
156pub struct EnumNamedFieldVariantFeatures(Vec<Feature>);
157
158impl Parse for EnumNamedFieldVariantFeatures {
159    fn parse(input: ParseStream) -> syn::Result<Self> {
160        Ok(EnumNamedFieldVariantFeatures(parse_features!(
161            input as Example,
162            Examples,
163            crate::component::features::attributes::Default,
164            XmlAttr,
165            Title,
166            Rename,
167            RenameAll,
168            Deprecated,
169            MaxProperties,
170            MinProperties,
171            NoRecursion
172        )))
173    }
174}
175
176impl_into_inner!(EnumNamedFieldVariantFeatures);
177
178pub struct EnumUnnamedFieldVariantFeatures(Vec<Feature>);
179
180impl Parse for EnumUnnamedFieldVariantFeatures {
181    fn parse(input: ParseStream) -> syn::Result<Self> {
182        Ok(EnumUnnamedFieldVariantFeatures(parse_features!(
183            input as Example,
184            Examples,
185            crate::component::features::attributes::Default,
186            Title,
187            Format,
188            ValueType,
189            Rename,
190            Deprecated,
191            NoRecursion
192        )))
193    }
194}
195
196impl_into_inner!(EnumUnnamedFieldVariantFeatures);
197
198pub trait FromAttributes {
199    fn parse_features<T>(&self) -> Result<Option<T>, Diagnostics>
200    where
201        T: Parse + Merge<T>;
202}
203
204impl FromAttributes for &'_ [Attribute] {
205    fn parse_features<T>(&self) -> Result<Option<T>, Diagnostics>
206    where
207        T: Parse + Merge<T>,
208    {
209        parse_schema_features::<T>(self)
210    }
211}
212
213impl FromAttributes for Vec<Attribute> {
214    fn parse_features<T>(&self) -> Result<Option<T>, Diagnostics>
215    where
216        T: Parse + Merge<T>,
217    {
218        parse_schema_features::<T>(self)
219    }
220}
221
222impl_merge!(
223    NamedFieldStructFeatures,
224    UnnamedFieldStructFeatures,
225    EnumFeatures,
226    MixedEnumFeatures,
227    NamedFieldFeatures,
228    EnumNamedFieldVariantFeatures,
229    EnumUnnamedFieldVariantFeatures
230);
231
232pub fn parse_schema_features<T: Sized + Parse + Merge<T>>(
233    attributes: &[Attribute],
234) -> Result<Option<T>, Diagnostics> {
235    Ok(attributes
236        .iter()
237        .filter(|attribute| {
238            attribute
239                .path()
240                .get_ident()
241                .map(|ident| *ident == "schema")
242                .unwrap_or(false)
243        })
244        .map(|attribute| attribute.parse_args::<T>().map_err(Diagnostics::from))
245        .collect::<Result<Vec<T>, Diagnostics>>()?
246        .into_iter()
247        .reduce(|acc, item| acc.merge(item)))
248}
249
250pub fn parse_schema_features_with<
251    T: Merge<T>,
252    P: for<'r> FnOnce(&'r ParseBuffer<'r>) -> syn::Result<T> + Copy,
253>(
254    attributes: &[Attribute],
255    parser: P,
256) -> Result<Option<T>, Diagnostics> {
257    Ok(attributes
258        .iter()
259        .filter(|attribute| {
260            attribute
261                .path()
262                .get_ident()
263                .map(|ident| *ident == "schema")
264                .unwrap_or(false)
265        })
266        .map(|attributes| {
267            attributes
268                .parse_args_with(parser)
269                .map_err(Diagnostics::from)
270        })
271        .collect::<Result<Vec<T>, Diagnostics>>()?
272        .into_iter()
273        .reduce(|acc, item| acc.merge(item)))
274}