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