utoipa_gen/component/
features.rs

1use std::{fmt::Display, mem, str::FromStr};
2
3use proc_macro2::{Ident, Span, TokenStream};
4use proc_macro_error::abort;
5use quote::{quote, ToTokens};
6use syn::{parenthesized, parse::ParseStream, LitFloat, LitInt, LitStr, TypePath};
7
8use crate::{
9    parse_utils,
10    path::parameter::{self, ParameterStyle},
11    schema_type::{SchemaFormat, SchemaType},
12    AnyValue,
13};
14
15use super::{schema, serde::RenameRule, GenericType, TypeTree};
16
17/// Parse `LitInt` from parse stream
18fn parse_integer<T: FromStr + Display>(input: ParseStream) -> syn::Result<T>
19where
20    <T as FromStr>::Err: Display,
21{
22    parse_utils::parse_next(input, || input.parse::<LitInt>()?.base10_parse())
23}
24
25/// Parse any `number`. Tries to parse `LitInt` or `LitFloat` from parse stream.
26fn parse_number<T>(input: ParseStream) -> syn::Result<T>
27where
28    T: FromStr,
29    <T as FromStr>::Err: Display,
30{
31    parse_utils::parse_next(input, || {
32        let lookup = input.lookahead1();
33        if lookup.peek(LitInt) {
34            input.parse::<LitInt>()?.base10_parse()
35        } else if lookup.peek(LitFloat) {
36            input.parse::<LitFloat>()?.base10_parse()
37        } else {
38            Err(lookup.error())
39        }
40    })
41}
42
43pub trait Name {
44    fn get_name() -> &'static str
45    where
46        Self: Sized;
47}
48
49macro_rules! name {
50    ( $ident:ident = $name:literal ) => {
51        impl Name for $ident {
52            fn get_name() -> &'static str {
53                $name
54            }
55        }
56
57        impl Display for $ident {
58            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59                let name = <Self as Name>::get_name();
60                write!(f, "{name}")
61            }
62        }
63    };
64}
65
66/// Define whether [`Feature`] variant is validatable or not
67pub trait Validatable {
68    fn is_validatable(&self) -> bool {
69        false
70    }
71}
72
73pub trait Validate: Validatable {
74    /// Perform validation check against schema type.
75    fn validate(&self, validator: impl Validator);
76}
77
78pub trait Parse {
79    fn parse(input: ParseStream, attribute: Ident) -> syn::Result<Self>
80    where
81        Self: std::marker::Sized;
82}
83
84#[cfg_attr(feature = "debug", derive(Debug))]
85#[derive(Clone)]
86pub enum Feature {
87    Example(Example),
88    Default(Default),
89    Inline(Inline),
90    XmlAttr(XmlAttr),
91    Format(Format),
92    ValueType(ValueType),
93    WriteOnly(WriteOnly),
94    ReadOnly(ReadOnly),
95    Title(Title),
96    Nullable(Nullable),
97    Rename(Rename),
98    RenameAll(RenameAll),
99    Style(Style),
100    AllowReserved(AllowReserved),
101    Explode(Explode),
102    ParameterIn(ParameterIn),
103    IntoParamsNames(Names),
104    MultipleOf(MultipleOf),
105    Maximum(Maximum),
106    Minimum(Minimum),
107    ExclusiveMaximum(ExclusiveMaximum),
108    ExclusiveMinimum(ExclusiveMinimum),
109    MaxLength(MaxLength),
110    MinLength(MinLength),
111    Pattern(Pattern),
112    MaxItems(MaxItems),
113    MinItems(MinItems),
114    MaxProperties(MaxProperties),
115    MinProperties(MinProperties),
116    SchemaWith(SchemaWith),
117    Description(Description),
118    Deprecated(Deprecated),
119    As(As),
120    AdditionalProperties(AdditionalProperties),
121    Required(Required),
122}
123
124impl Feature {
125    pub fn validate(&self, schema_type: &SchemaType, type_tree: &TypeTree) {
126        match self {
127            Feature::MultipleOf(multiple_of) => multiple_of.validate(
128                ValidatorChain::new(&IsNumber(schema_type)).next(&AboveZeroF64(multiple_of.0)),
129            ),
130            Feature::Maximum(maximum) => maximum.validate(IsNumber(schema_type)),
131            Feature::Minimum(minimum) => minimum.validate(IsNumber(schema_type)),
132            Feature::ExclusiveMaximum(exclusive_maximum) => {
133                exclusive_maximum.validate(IsNumber(schema_type))
134            }
135            Feature::ExclusiveMinimum(exclusive_minimum) => {
136                exclusive_minimum.validate(IsNumber(schema_type))
137            }
138            Feature::MaxLength(max_length) => max_length.validate(
139                ValidatorChain::new(&IsString(schema_type)).next(&AboveZeroUsize(max_length.0)),
140            ),
141            Feature::MinLength(min_length) => min_length.validate(
142                ValidatorChain::new(&IsString(schema_type)).next(&AboveZeroUsize(min_length.0)),
143            ),
144            Feature::Pattern(pattern) => pattern.validate(IsString(schema_type)),
145            Feature::MaxItems(max_items) => max_items.validate(
146                ValidatorChain::new(&AboveZeroUsize(max_items.0)).next(&IsVec(type_tree)),
147            ),
148            Feature::MinItems(min_items) => min_items.validate(
149                ValidatorChain::new(&AboveZeroUsize(min_items.0)).next(&IsVec(type_tree)),
150            ),
151            _unsupported_variant => {
152                const SUPPORTED_VARIANTS: [&str; 10] = [
153                    "multiple_of",
154                    "maximum",
155                    "minimum",
156                    "exclusive_maximum",
157                    "exclusive_minimum",
158                    "max_length",
159                    "min_length",
160                    "pattern",
161                    "max_items",
162                    "min_items",
163                ];
164                panic!(
165                    "Unsupported variant: `{variant}` for Validate::validate, expected one of: {variants}",
166                    variant = _unsupported_variant,
167                    variants = SUPPORTED_VARIANTS.join(", ")
168                )
169            }
170        }
171    }
172}
173
174impl ToTokens for Feature {
175    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
176        let feature = match &self {
177            Feature::Default(default) => quote! { .default(#default) },
178            Feature::Example(example) => quote! { .example(Some(#example)) },
179            Feature::XmlAttr(xml) => quote! { .xml(Some(#xml)) },
180            Feature::Format(format) => quote! { .format(Some(#format)) },
181            Feature::WriteOnly(write_only) => quote! { .write_only(Some(#write_only)) },
182            Feature::ReadOnly(read_only) => quote! { .read_only(Some(#read_only)) },
183            Feature::Title(title) => quote! { .title(Some(#title)) },
184            Feature::Nullable(nullable) => quote! { .nullable(#nullable) },
185            Feature::Rename(rename) => rename.to_token_stream(),
186            Feature::Style(style) => quote! { .style(Some(#style)) },
187            Feature::ParameterIn(parameter_in) => quote! { .parameter_in(#parameter_in) },
188            Feature::MultipleOf(multiple_of) => quote! { .multiple_of(Some(#multiple_of)) },
189            Feature::AllowReserved(allow_reserved) => {
190                quote! { .allow_reserved(Some(#allow_reserved)) }
191            }
192            Feature::Explode(explode) => quote! { .explode(Some(#explode)) },
193            Feature::Maximum(maximum) => quote! { .maximum(Some(#maximum)) },
194            Feature::Minimum(minimum) => quote! { .minimum(Some(#minimum)) },
195            Feature::ExclusiveMaximum(exclusive_maximum) => {
196                quote! { .exclusive_maximum(Some(#exclusive_maximum)) }
197            }
198            Feature::ExclusiveMinimum(exclusive_minimum) => {
199                quote! { .exclusive_minimum(Some(#exclusive_minimum)) }
200            }
201            Feature::MaxLength(max_length) => quote! { .max_length(Some(#max_length)) },
202            Feature::MinLength(min_length) => quote! { .min_length(Some(#min_length)) },
203            Feature::Pattern(pattern) => quote! { .pattern(Some(#pattern)) },
204            Feature::MaxItems(max_items) => quote! { .max_items(Some(#max_items)) },
205            Feature::MinItems(min_items) => quote! { .min_items(Some(#min_items)) },
206            Feature::MaxProperties(max_properties) => {
207                quote! { .max_properties(Some(#max_properties)) }
208            }
209            Feature::MinProperties(min_properties) => {
210                quote! { .max_properties(Some(#min_properties)) }
211            }
212            Feature::SchemaWith(schema_with) => schema_with.to_token_stream(),
213            Feature::Description(description) => quote! { .description(Some(#description)) },
214            Feature::Deprecated(deprecated) => quote! { .deprecated(Some(#deprecated)) },
215            Feature::AdditionalProperties(additional_properties) => {
216                quote! { .additional_properties(Some(#additional_properties)) }
217            }
218            Feature::RenameAll(_) => {
219                abort! {
220                    Span::call_site(),
221                    "RenameAll feature does not support `ToTokens`"
222                }
223            }
224            Feature::ValueType(_) => {
225                abort! {
226                    Span::call_site(),
227                    "ValueType feature does not support `ToTokens`";
228                    help = "ValueType is supposed to be used with `TypeTree` in same manner as a resolved struct/field type.";
229                }
230            }
231            Feature::Inline(_) => {
232                // inline feature is ignored by `ToTokens`
233                TokenStream::new()
234            }
235            Feature::IntoParamsNames(_) => {
236                abort! {
237                    Span::call_site(),
238                    "Names feature does not support `ToTokens`";
239                    help = "Names is only used with IntoParams to artificially give names for unnamed struct type `IntoParams`."
240                }
241            }
242            Feature::As(_) => {
243                abort!(Span::call_site(), "As does not support `ToTokens`")
244            }
245            Feature::Required(required) => {
246                let name = <Required as Name>::get_name();
247                quote! { .#name(#required) }
248            }
249        };
250
251        tokens.extend(feature)
252    }
253}
254
255impl Display for Feature {
256    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
257        match self {
258            Feature::Default(default) => default.fmt(f),
259            Feature::Example(example) => example.fmt(f),
260            Feature::XmlAttr(xml) => xml.fmt(f),
261            Feature::Format(format) => format.fmt(f),
262            Feature::WriteOnly(write_only) => write_only.fmt(f),
263            Feature::ReadOnly(read_only) => read_only.fmt(f),
264            Feature::Title(title) => title.fmt(f),
265            Feature::Nullable(nullable) => nullable.fmt(f),
266            Feature::Rename(rename) => rename.fmt(f),
267            Feature::Style(style) => style.fmt(f),
268            Feature::ParameterIn(parameter_in) => parameter_in.fmt(f),
269            Feature::AllowReserved(allow_reserved) => allow_reserved.fmt(f),
270            Feature::Explode(explode) => explode.fmt(f),
271            Feature::RenameAll(rename_all) => rename_all.fmt(f),
272            Feature::ValueType(value_type) => value_type.fmt(f),
273            Feature::Inline(inline) => inline.fmt(f),
274            Feature::IntoParamsNames(names) => names.fmt(f),
275            Feature::MultipleOf(multiple_of) => multiple_of.fmt(f),
276            Feature::Maximum(maximum) => maximum.fmt(f),
277            Feature::Minimum(minimum) => minimum.fmt(f),
278            Feature::ExclusiveMaximum(exclusive_maximum) => exclusive_maximum.fmt(f),
279            Feature::ExclusiveMinimum(exclusive_minimum) => exclusive_minimum.fmt(f),
280            Feature::MaxLength(max_length) => max_length.fmt(f),
281            Feature::MinLength(min_length) => min_length.fmt(f),
282            Feature::Pattern(pattern) => pattern.fmt(f),
283            Feature::MaxItems(max_items) => max_items.fmt(f),
284            Feature::MinItems(min_items) => min_items.fmt(f),
285            Feature::MaxProperties(max_properties) => max_properties.fmt(f),
286            Feature::MinProperties(min_properties) => min_properties.fmt(f),
287            Feature::SchemaWith(schema_with) => schema_with.fmt(f),
288            Feature::Description(description) => description.fmt(f),
289            Feature::Deprecated(deprecated) => deprecated.fmt(f),
290            Feature::As(as_feature) => as_feature.fmt(f),
291            Feature::AdditionalProperties(additional_properties) => additional_properties.fmt(f),
292            Feature::Required(required) => required.fmt(f),
293        }
294    }
295}
296
297impl Validatable for Feature {
298    fn is_validatable(&self) -> bool {
299        match &self {
300            Feature::Default(default) => default.is_validatable(),
301            Feature::Example(example) => example.is_validatable(),
302            Feature::XmlAttr(xml) => xml.is_validatable(),
303            Feature::Format(format) => format.is_validatable(),
304            Feature::WriteOnly(write_only) => write_only.is_validatable(),
305            Feature::ReadOnly(read_only) => read_only.is_validatable(),
306            Feature::Title(title) => title.is_validatable(),
307            Feature::Nullable(nullable) => nullable.is_validatable(),
308            Feature::Rename(rename) => rename.is_validatable(),
309            Feature::Style(style) => style.is_validatable(),
310            Feature::ParameterIn(parameter_in) => parameter_in.is_validatable(),
311            Feature::AllowReserved(allow_reserved) => allow_reserved.is_validatable(),
312            Feature::Explode(explode) => explode.is_validatable(),
313            Feature::RenameAll(rename_all) => rename_all.is_validatable(),
314            Feature::ValueType(value_type) => value_type.is_validatable(),
315            Feature::Inline(inline) => inline.is_validatable(),
316            Feature::IntoParamsNames(names) => names.is_validatable(),
317            Feature::MultipleOf(multiple_of) => multiple_of.is_validatable(),
318            Feature::Maximum(maximum) => maximum.is_validatable(),
319            Feature::Minimum(minimum) => minimum.is_validatable(),
320            Feature::ExclusiveMaximum(exclusive_maximum) => exclusive_maximum.is_validatable(),
321            Feature::ExclusiveMinimum(exclusive_minimum) => exclusive_minimum.is_validatable(),
322            Feature::MaxLength(max_length) => max_length.is_validatable(),
323            Feature::MinLength(min_length) => min_length.is_validatable(),
324            Feature::Pattern(pattern) => pattern.is_validatable(),
325            Feature::MaxItems(max_items) => max_items.is_validatable(),
326            Feature::MinItems(min_items) => min_items.is_validatable(),
327            Feature::MaxProperties(max_properties) => max_properties.is_validatable(),
328            Feature::MinProperties(min_properties) => min_properties.is_validatable(),
329            Feature::SchemaWith(schema_with) => schema_with.is_validatable(),
330            Feature::Description(description) => description.is_validatable(),
331            Feature::Deprecated(deprecated) => deprecated.is_validatable(),
332            Feature::As(as_feature) => as_feature.is_validatable(),
333            Feature::AdditionalProperties(additional_properties) => {
334                additional_properties.is_validatable()
335            }
336            Feature::Required(required) => required.is_validatable(),
337        }
338    }
339}
340
341macro_rules! is_validatable {
342    ( $( $ident:ident => $validatable:literal ),* ) => {
343        $(
344            impl Validatable for $ident {
345                fn is_validatable(&self) -> bool {
346                    $validatable
347                }
348            }
349        )*
350    };
351}
352
353is_validatable! {
354    Default => false,
355    Example => false,
356    XmlAttr => false,
357    Format => false,
358    WriteOnly => false,
359    ReadOnly => false,
360    Title => false,
361    Nullable => false,
362    Rename => false,
363    Style => false,
364    ParameterIn => false,
365    AllowReserved => false,
366    Explode => false,
367    RenameAll => false,
368    ValueType => false,
369    Inline => false,
370    Names => false,
371    MultipleOf => true,
372    Maximum => true,
373    Minimum => true,
374    ExclusiveMaximum => true,
375    ExclusiveMinimum => true,
376    MaxLength => true,
377    MinLength => true,
378    Pattern => true,
379    MaxItems => true,
380    MinItems => true,
381    MaxProperties => false,
382    MinProperties => false,
383    SchemaWith => false,
384    Description => false,
385    Deprecated => false,
386    As => false,
387    AdditionalProperties => false,
388    Required => false
389}
390
391#[derive(Clone)]
392#[cfg_attr(feature = "debug", derive(Debug))]
393pub struct Example(AnyValue);
394
395impl Parse for Example {
396    fn parse(input: syn::parse::ParseStream, _: Ident) -> syn::Result<Self> {
397        parse_utils::parse_next(input, || AnyValue::parse_any(input)).map(Self)
398    }
399}
400
401impl ToTokens for Example {
402    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
403        tokens.extend(self.0.to_token_stream())
404    }
405}
406
407impl From<Example> for Feature {
408    fn from(value: Example) -> Self {
409        Feature::Example(value)
410    }
411}
412
413name!(Example = "example");
414
415#[derive(Clone)]
416#[cfg_attr(feature = "debug", derive(Debug))]
417pub struct Default(pub(crate) Option<AnyValue>);
418
419impl Default {
420    pub fn new_default_trait(struct_ident: Ident, field_ident: syn::Member) -> Self {
421        Self(Some(AnyValue::new_default_trait(struct_ident, field_ident)))
422    }
423}
424
425impl Parse for Default {
426    fn parse(input: syn::parse::ParseStream, _: Ident) -> syn::Result<Self> {
427        if input.peek(syn::Token![=]) {
428            parse_utils::parse_next(input, || AnyValue::parse_any(input)).map(|any| Self(Some(any)))
429        } else {
430            Ok(Self(None))
431        }
432    }
433}
434
435impl ToTokens for Default {
436    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
437        match &self.0 {
438            Some(inner) => tokens.extend(quote! {Some(#inner)}),
439            None => tokens.extend(quote! {None}),
440        }
441    }
442}
443
444impl From<self::Default> for Feature {
445    fn from(value: self::Default) -> Self {
446        Feature::Default(value)
447    }
448}
449
450name!(Default = "default");
451
452#[derive(Clone)]
453#[cfg_attr(feature = "debug", derive(Debug))]
454pub struct Inline(bool);
455
456impl Parse for Inline {
457    fn parse(input: syn::parse::ParseStream, _: Ident) -> syn::Result<Self> {
458        parse_utils::parse_bool_or_true(input).map(Self)
459    }
460}
461
462impl From<bool> for Inline {
463    fn from(value: bool) -> Self {
464        Inline(value)
465    }
466}
467
468impl From<Inline> for Feature {
469    fn from(value: Inline) -> Self {
470        Feature::Inline(value)
471    }
472}
473
474name!(Inline = "inline");
475
476#[derive(Default, Clone)]
477#[cfg_attr(feature = "debug", derive(Debug))]
478pub struct XmlAttr(schema::xml::XmlAttr);
479
480impl XmlAttr {
481    /// Split [`XmlAttr`] for [`GenericType::Vec`] returning tuple of [`XmlAttr`]s where first
482    /// one is for a vec and second one is for object field.
483    pub fn split_for_vec(&mut self, type_tree: &TypeTree) -> (Option<XmlAttr>, Option<XmlAttr>) {
484        if matches!(type_tree.generic_type, Some(GenericType::Vec)) {
485            let mut value_xml = mem::take(self);
486            let vec_xml = schema::xml::XmlAttr::with_wrapped(
487                mem::take(&mut value_xml.0.is_wrapped),
488                mem::take(&mut value_xml.0.wrap_name),
489            );
490
491            (Some(XmlAttr(vec_xml)), Some(value_xml))
492        } else {
493            self.validate_xml(&self.0);
494
495            (None, Some(mem::take(self)))
496        }
497    }
498
499    #[inline]
500    fn validate_xml(&self, xml: &schema::xml::XmlAttr) {
501        if let Some(wrapped_ident) = xml.is_wrapped.as_ref() {
502            abort! {wrapped_ident, "cannot use `wrapped` attribute in non slice field type";
503                help = "Try removing `wrapped` attribute or make your field `Vec`"
504            }
505        }
506    }
507}
508
509impl Parse for XmlAttr {
510    fn parse(input: syn::parse::ParseStream, _: Ident) -> syn::Result<Self> {
511        let xml;
512        parenthesized!(xml in input);
513        xml.parse::<schema::xml::XmlAttr>().map(Self)
514    }
515}
516
517impl ToTokens for XmlAttr {
518    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
519        tokens.extend(self.0.to_token_stream())
520    }
521}
522
523impl From<XmlAttr> for Feature {
524    fn from(value: XmlAttr) -> Self {
525        Feature::XmlAttr(value)
526    }
527}
528
529name!(XmlAttr = "xml");
530
531#[derive(Clone)]
532#[cfg_attr(feature = "debug", derive(Debug))]
533pub struct Format(SchemaFormat<'static>);
534
535impl Parse for Format {
536    fn parse(input: syn::parse::ParseStream, _: Ident) -> syn::Result<Self> {
537        parse_utils::parse_next(input, || input.parse::<SchemaFormat>()).map(Self)
538    }
539}
540
541impl ToTokens for Format {
542    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
543        tokens.extend(self.0.to_token_stream())
544    }
545}
546
547impl From<Format> for Feature {
548    fn from(value: Format) -> Self {
549        Feature::Format(value)
550    }
551}
552
553name!(Format = "format");
554
555#[derive(Clone)]
556#[cfg_attr(feature = "debug", derive(Debug))]
557pub struct ValueType(syn::Type);
558
559impl ValueType {
560    /// Create [`TypeTree`] from current [`syn::Type`].
561    pub fn as_type_tree(&self) -> TypeTree {
562        TypeTree::from_type(&self.0)
563    }
564}
565
566impl Parse for ValueType {
567    fn parse(input: syn::parse::ParseStream, _: Ident) -> syn::Result<Self> {
568        parse_utils::parse_next(input, || input.parse::<syn::Type>()).map(Self)
569    }
570}
571
572impl From<ValueType> for Feature {
573    fn from(value: ValueType) -> Self {
574        Feature::ValueType(value)
575    }
576}
577
578name!(ValueType = "value_type");
579
580#[derive(Clone, Copy)]
581#[cfg_attr(feature = "debug", derive(Debug))]
582pub struct WriteOnly(bool);
583
584impl Parse for WriteOnly {
585    fn parse(input: syn::parse::ParseStream, _: Ident) -> syn::Result<Self> {
586        parse_utils::parse_bool_or_true(input).map(Self)
587    }
588}
589
590impl ToTokens for WriteOnly {
591    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
592        tokens.extend(self.0.to_token_stream())
593    }
594}
595
596impl From<WriteOnly> for Feature {
597    fn from(value: WriteOnly) -> Self {
598        Feature::WriteOnly(value)
599    }
600}
601
602name!(WriteOnly = "write_only");
603
604#[derive(Clone, Copy)]
605#[cfg_attr(feature = "debug", derive(Debug))]
606pub struct ReadOnly(bool);
607
608impl Parse for ReadOnly {
609    fn parse(input: syn::parse::ParseStream, _: Ident) -> syn::Result<Self> {
610        parse_utils::parse_bool_or_true(input).map(Self)
611    }
612}
613
614impl ToTokens for ReadOnly {
615    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
616        tokens.extend(self.0.to_token_stream())
617    }
618}
619
620impl From<ReadOnly> for Feature {
621    fn from(value: ReadOnly) -> Self {
622        Feature::ReadOnly(value)
623    }
624}
625
626name!(ReadOnly = "read_only");
627
628#[derive(Clone)]
629#[cfg_attr(feature = "debug", derive(Debug))]
630pub struct Title(String);
631
632impl Parse for Title {
633    fn parse(input: syn::parse::ParseStream, _: Ident) -> syn::Result<Self> {
634        parse_utils::parse_next_literal_str(input).map(Self)
635    }
636}
637
638impl ToTokens for Title {
639    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
640        tokens.extend(self.0.to_token_stream())
641    }
642}
643
644impl From<Title> for Feature {
645    fn from(value: Title) -> Self {
646        Feature::Title(value)
647    }
648}
649
650name!(Title = "title");
651
652#[derive(Clone, Copy)]
653#[cfg_attr(feature = "debug", derive(Debug))]
654pub struct Nullable(bool);
655
656impl Nullable {
657    pub fn new() -> Self {
658        Self(true)
659    }
660}
661
662impl Parse for Nullable {
663    fn parse(input: syn::parse::ParseStream, _: Ident) -> syn::Result<Self> {
664        parse_utils::parse_bool_or_true(input).map(Self)
665    }
666}
667
668impl ToTokens for Nullable {
669    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
670        tokens.extend(self.0.to_token_stream())
671    }
672}
673
674impl From<Nullable> for Feature {
675    fn from(value: Nullable) -> Self {
676        Feature::Nullable(value)
677    }
678}
679
680name!(Nullable = "nullable");
681
682#[cfg_attr(feature = "debug", derive(Debug))]
683#[derive(Clone)]
684pub struct Rename(String);
685
686impl Rename {
687    pub fn into_value(self) -> String {
688        self.0
689    }
690}
691
692impl Parse for Rename {
693    fn parse(input: syn::parse::ParseStream, _: Ident) -> syn::Result<Self> {
694        parse_utils::parse_next_literal_str(input).map(Self)
695    }
696}
697
698impl ToTokens for Rename {
699    fn to_tokens(&self, tokens: &mut TokenStream) {
700        tokens.extend(self.0.to_token_stream())
701    }
702}
703
704impl From<Rename> for Feature {
705    fn from(value: Rename) -> Self {
706        Feature::Rename(value)
707    }
708}
709
710name!(Rename = "rename");
711
712#[cfg_attr(feature = "debug", derive(Debug))]
713#[derive(Clone)]
714pub struct RenameAll(RenameRule);
715
716impl RenameAll {
717    pub fn as_rename_rule(&self) -> &RenameRule {
718        &self.0
719    }
720}
721
722impl Parse for RenameAll {
723    fn parse(input: syn::parse::ParseStream, _: Ident) -> syn::Result<Self> {
724        let litstr = parse_utils::parse_next(input, || input.parse::<LitStr>())?;
725
726        litstr
727            .value()
728            .parse::<RenameRule>()
729            .map_err(|error| syn::Error::new(litstr.span(), error.to_string()))
730            .map(Self)
731    }
732}
733
734impl From<RenameAll> for Feature {
735    fn from(value: RenameAll) -> Self {
736        Feature::RenameAll(value)
737    }
738}
739
740name!(RenameAll = "rename_all");
741
742#[cfg_attr(feature = "debug", derive(Debug))]
743#[derive(Clone)]
744pub struct Style(ParameterStyle);
745
746impl From<ParameterStyle> for Style {
747    fn from(style: ParameterStyle) -> Self {
748        Self(style)
749    }
750}
751
752impl Parse for Style {
753    fn parse(input: syn::parse::ParseStream, _: Ident) -> syn::Result<Self> {
754        parse_utils::parse_next(input, || input.parse::<ParameterStyle>().map(Self))
755    }
756}
757
758impl ToTokens for Style {
759    fn to_tokens(&self, tokens: &mut TokenStream) {
760        self.0.to_tokens(tokens)
761    }
762}
763
764impl From<Style> for Feature {
765    fn from(value: Style) -> Self {
766        Feature::Style(value)
767    }
768}
769
770name!(Style = "style");
771
772#[cfg_attr(feature = "debug", derive(Debug))]
773#[derive(Clone)]
774pub struct AllowReserved(bool);
775
776impl Parse for AllowReserved {
777    fn parse(input: syn::parse::ParseStream, _: Ident) -> syn::Result<Self> {
778        parse_utils::parse_bool_or_true(input).map(Self)
779    }
780}
781
782impl ToTokens for AllowReserved {
783    fn to_tokens(&self, tokens: &mut TokenStream) {
784        self.0.to_tokens(tokens)
785    }
786}
787
788impl From<AllowReserved> for Feature {
789    fn from(value: AllowReserved) -> Self {
790        Feature::AllowReserved(value)
791    }
792}
793
794name!(AllowReserved = "allow_reserved");
795
796#[cfg_attr(feature = "debug", derive(Debug))]
797#[derive(Clone)]
798pub struct Explode(bool);
799
800impl Parse for Explode {
801    fn parse(input: syn::parse::ParseStream, _: Ident) -> syn::Result<Self> {
802        parse_utils::parse_bool_or_true(input).map(Self)
803    }
804}
805
806impl ToTokens for Explode {
807    fn to_tokens(&self, tokens: &mut TokenStream) {
808        self.0.to_tokens(tokens)
809    }
810}
811
812impl From<Explode> for Feature {
813    fn from(value: Explode) -> Self {
814        Feature::Explode(value)
815    }
816}
817
818name!(Explode = "explode");
819
820#[cfg_attr(feature = "debug", derive(Debug))]
821#[derive(Clone)]
822pub struct ParameterIn(parameter::ParameterIn);
823
824impl Parse for ParameterIn {
825    fn parse(input: syn::parse::ParseStream, _: Ident) -> syn::Result<Self> {
826        parse_utils::parse_next(input, || input.parse::<parameter::ParameterIn>().map(Self))
827    }
828}
829
830impl ToTokens for ParameterIn {
831    fn to_tokens(&self, tokens: &mut TokenStream) {
832        self.0.to_tokens(tokens);
833    }
834}
835
836impl From<ParameterIn> for Feature {
837    fn from(value: ParameterIn) -> Self {
838        Feature::ParameterIn(value)
839    }
840}
841
842name!(ParameterIn = "parameter_in");
843
844/// Specify names of unnamed fields with `names(...) attribute for `IntoParams` derive.
845#[cfg_attr(feature = "debug", derive(Debug))]
846#[derive(Clone)]
847pub struct Names(Vec<String>);
848
849impl Names {
850    pub fn into_values(self) -> Vec<String> {
851        self.0
852    }
853}
854
855impl Parse for Names {
856    fn parse(input: syn::parse::ParseStream, _: Ident) -> syn::Result<Self> {
857        Ok(Self(
858            parse_utils::parse_punctuated_within_parenthesis::<LitStr>(input)?
859                .iter()
860                .map(LitStr::value)
861                .collect(),
862        ))
863    }
864}
865
866impl From<Names> for Feature {
867    fn from(value: Names) -> Self {
868        Feature::IntoParamsNames(value)
869    }
870}
871
872name!(Names = "names");
873
874#[cfg_attr(feature = "debug", derive(Debug))]
875#[derive(Clone)]
876pub struct MultipleOf(f64, Ident);
877
878impl Validate for MultipleOf {
879    fn validate(&self, validator: impl Validator) {
880        if let Err(error) = validator.is_valid() {
881            abort! {self.1, "`multiple_of` error: {}", error;
882                help = "See more details: `http://json-schema.org/draft/2020-12/json-schema-validation.html#name-multipleof`"
883            }
884        };
885    }
886}
887
888impl Parse for MultipleOf {
889    fn parse(input: ParseStream, ident: Ident) -> syn::Result<Self> {
890        parse_number(input).map(|multiple_of| Self(multiple_of, ident))
891    }
892}
893
894impl ToTokens for MultipleOf {
895    fn to_tokens(&self, tokens: &mut TokenStream) {
896        self.0.to_tokens(tokens);
897    }
898}
899
900impl From<MultipleOf> for Feature {
901    fn from(value: MultipleOf) -> Self {
902        Feature::MultipleOf(value)
903    }
904}
905
906name!(MultipleOf = "multiple_of");
907
908#[cfg_attr(feature = "debug", derive(Debug))]
909#[derive(Clone)]
910pub struct Maximum(f64, Ident);
911
912impl Validate for Maximum {
913    fn validate(&self, validator: impl Validator) {
914        if let Err(error) = validator.is_valid() {
915            abort! {self.1, "`maximum` error: {}", error;
916                help = "See more details: `http://json-schema.org/draft/2020-12/json-schema-validation.html#name-maximum`"
917            }
918        }
919    }
920}
921
922impl Parse for Maximum {
923    fn parse(input: ParseStream, ident: Ident) -> syn::Result<Self>
924    where
925        Self: Sized,
926    {
927        parse_number(input).map(|maximum| Self(maximum, ident))
928    }
929}
930
931impl ToTokens for Maximum {
932    fn to_tokens(&self, tokens: &mut TokenStream) {
933        self.0.to_tokens(tokens);
934    }
935}
936
937impl From<Maximum> for Feature {
938    fn from(value: Maximum) -> Self {
939        Feature::Maximum(value)
940    }
941}
942
943name!(Maximum = "maximum");
944
945#[cfg_attr(feature = "debug", derive(Debug))]
946#[derive(Clone)]
947pub struct Minimum(f64, Ident);
948
949impl Minimum {
950    pub fn new(value: f64, span: Span) -> Self {
951        Self(value, Ident::new("empty", span))
952    }
953}
954
955impl Validate for Minimum {
956    fn validate(&self, validator: impl Validator) {
957        if let Err(error) = validator.is_valid() {
958            abort! {self.1, "`minimum` error: {}", error;
959                help = "See more details: `http://json-schema.org/draft/2020-12/json-schema-validation.html#name-minimum`"
960            }
961        }
962    }
963}
964
965impl Parse for Minimum {
966    fn parse(input: ParseStream, ident: Ident) -> syn::Result<Self>
967    where
968        Self: Sized,
969    {
970        parse_number(input).map(|maximum| Self(maximum, ident))
971    }
972}
973
974impl ToTokens for Minimum {
975    fn to_tokens(&self, tokens: &mut TokenStream) {
976        self.0.to_tokens(tokens);
977    }
978}
979
980impl From<Minimum> for Feature {
981    fn from(value: Minimum) -> Self {
982        Feature::Minimum(value)
983    }
984}
985
986name!(Minimum = "minimum");
987
988#[cfg_attr(feature = "debug", derive(Debug))]
989#[derive(Clone)]
990pub struct ExclusiveMaximum(f64, Ident);
991
992impl Validate for ExclusiveMaximum {
993    fn validate(&self, validator: impl Validator) {
994        if let Err(error) = validator.is_valid() {
995            abort! {self.1, "`exclusive_maximum` error: {}", error;
996                help = "See more details: `http://json-schema.org/draft/2020-12/json-schema-validation.html#name-exclusivemaximum`"
997            }
998        }
999    }
1000}
1001
1002impl Parse for ExclusiveMaximum {
1003    fn parse(input: ParseStream, ident: Ident) -> syn::Result<Self>
1004    where
1005        Self: Sized,
1006    {
1007        parse_number(input).map(|max| Self(max, ident))
1008    }
1009}
1010
1011impl ToTokens for ExclusiveMaximum {
1012    fn to_tokens(&self, tokens: &mut TokenStream) {
1013        self.0.to_tokens(tokens);
1014    }
1015}
1016
1017impl From<ExclusiveMaximum> for Feature {
1018    fn from(value: ExclusiveMaximum) -> Self {
1019        Feature::ExclusiveMaximum(value)
1020    }
1021}
1022
1023name!(ExclusiveMaximum = "exclusive_maximum");
1024
1025#[cfg_attr(feature = "debug", derive(Debug))]
1026#[derive(Clone)]
1027pub struct ExclusiveMinimum(f64, Ident);
1028
1029impl Validate for ExclusiveMinimum {
1030    fn validate(&self, validator: impl Validator) {
1031        if let Err(error) = validator.is_valid() {
1032            abort! {self.1, "`exclusive_minimum` error: {}", error;
1033                help = "See more details: `http://json-schema.org/draft/2020-12/json-schema-validation.html#name-exclusiveminimum`"
1034            }
1035        }
1036    }
1037}
1038
1039impl Parse for ExclusiveMinimum {
1040    fn parse(input: ParseStream, ident: Ident) -> syn::Result<Self>
1041    where
1042        Self: Sized,
1043    {
1044        parse_number(input).map(|min| Self(min, ident))
1045    }
1046}
1047
1048impl ToTokens for ExclusiveMinimum {
1049    fn to_tokens(&self, tokens: &mut TokenStream) {
1050        self.0.to_tokens(tokens);
1051    }
1052}
1053
1054impl From<ExclusiveMinimum> for Feature {
1055    fn from(value: ExclusiveMinimum) -> Self {
1056        Feature::ExclusiveMinimum(value)
1057    }
1058}
1059
1060name!(ExclusiveMinimum = "exclusive_minimum");
1061
1062#[cfg_attr(feature = "debug", derive(Debug))]
1063#[derive(Clone)]
1064pub struct MaxLength(usize, Ident);
1065
1066impl Validate for MaxLength {
1067    fn validate(&self, validator: impl Validator) {
1068        if let Err(error) = validator.is_valid() {
1069            abort! {self.1, "`max_length` error: {}", error;
1070                help = "See more details: `http://json-schema.org/draft/2020-12/json-schema-validation.html#name-maxlength`"
1071            }
1072        }
1073    }
1074}
1075
1076impl Parse for MaxLength {
1077    fn parse(input: ParseStream, ident: Ident) -> syn::Result<Self>
1078    where
1079        Self: Sized,
1080    {
1081        parse_integer(input).map(|max_length| Self(max_length, ident))
1082    }
1083}
1084
1085impl ToTokens for MaxLength {
1086    fn to_tokens(&self, tokens: &mut TokenStream) {
1087        self.0.to_tokens(tokens);
1088    }
1089}
1090
1091impl From<MaxLength> for Feature {
1092    fn from(value: MaxLength) -> Self {
1093        Feature::MaxLength(value)
1094    }
1095}
1096
1097name!(MaxLength = "max_length");
1098
1099#[cfg_attr(feature = "debug", derive(Debug))]
1100#[derive(Clone)]
1101pub struct MinLength(usize, Ident);
1102
1103impl Validate for MinLength {
1104    fn validate(&self, validator: impl Validator) {
1105        if let Err(error) = validator.is_valid() {
1106            abort! {self.1, "`min_length` error: {}", error;
1107                help = "See more details: `http://json-schema.org/draft/2020-12/json-schema-validation.html#name-minlength`"
1108            }
1109        }
1110    }
1111}
1112
1113impl Parse for MinLength {
1114    fn parse(input: ParseStream, ident: Ident) -> syn::Result<Self>
1115    where
1116        Self: Sized,
1117    {
1118        parse_integer(input).map(|max_length| Self(max_length, ident))
1119    }
1120}
1121
1122impl ToTokens for MinLength {
1123    fn to_tokens(&self, tokens: &mut TokenStream) {
1124        self.0.to_tokens(tokens);
1125    }
1126}
1127
1128impl From<MinLength> for Feature {
1129    fn from(value: MinLength) -> Self {
1130        Feature::MinLength(value)
1131    }
1132}
1133
1134name!(MinLength = "min_length");
1135
1136#[cfg_attr(feature = "debug", derive(Debug))]
1137#[derive(Clone)]
1138pub struct Pattern(String, Ident);
1139
1140impl Validate for Pattern {
1141    fn validate(&self, validator: impl Validator) {
1142        if let Err(error) = validator.is_valid() {
1143            abort! {self.1, "`pattern` error: {}", error;
1144                help = "See more details: `http://json-schema.org/draft/2020-12/json-schema-validation.html#name-pattern`"
1145            }
1146        }
1147    }
1148}
1149
1150impl Parse for Pattern {
1151    fn parse(input: ParseStream, ident: Ident) -> syn::Result<Self>
1152    where
1153        Self: Sized,
1154    {
1155        parse_utils::parse_next(input, || input.parse::<LitStr>())
1156            .map(|pattern| Self(pattern.value(), ident))
1157    }
1158}
1159
1160impl ToTokens for Pattern {
1161    fn to_tokens(&self, tokens: &mut TokenStream) {
1162        self.0.to_tokens(tokens);
1163    }
1164}
1165
1166impl From<Pattern> for Feature {
1167    fn from(value: Pattern) -> Self {
1168        Feature::Pattern(value)
1169    }
1170}
1171
1172name!(Pattern = "pattern");
1173
1174#[cfg_attr(feature = "debug", derive(Debug))]
1175#[derive(Clone)]
1176pub struct MaxItems(usize, Ident);
1177
1178impl Validate for MaxItems {
1179    fn validate(&self, validator: impl Validator) {
1180        if let Err(error) = validator.is_valid() {
1181            abort! {self.1, "`max_items` error: {}", error;
1182                help = "See more details: `http://json-schema.org/draft/2020-12/json-schema-validation.html#name-maxitems"
1183            }
1184        }
1185    }
1186}
1187
1188impl Parse for MaxItems {
1189    fn parse(input: ParseStream, ident: Ident) -> syn::Result<Self>
1190    where
1191        Self: Sized,
1192    {
1193        parse_number(input).map(|max_items| Self(max_items, ident))
1194    }
1195}
1196
1197impl ToTokens for MaxItems {
1198    fn to_tokens(&self, tokens: &mut TokenStream) {
1199        self.0.to_tokens(tokens);
1200    }
1201}
1202
1203impl From<MaxItems> for Feature {
1204    fn from(value: MaxItems) -> Self {
1205        Feature::MaxItems(value)
1206    }
1207}
1208
1209name!(MaxItems = "max_items");
1210
1211#[cfg_attr(feature = "debug", derive(Debug))]
1212#[derive(Clone)]
1213pub struct MinItems(usize, Ident);
1214
1215impl Validate for MinItems {
1216    fn validate(&self, validator: impl Validator) {
1217        if let Err(error) = validator.is_valid() {
1218            abort! {self.1, "`min_items` error: {}", error;
1219                help = "See more details: `http://json-schema.org/draft/2020-12/json-schema-validation.html#name-minitems"
1220            }
1221        }
1222    }
1223}
1224
1225impl Parse for MinItems {
1226    fn parse(input: ParseStream, ident: Ident) -> syn::Result<Self>
1227    where
1228        Self: Sized,
1229    {
1230        parse_number(input).map(|max_items| Self(max_items, ident))
1231    }
1232}
1233
1234impl ToTokens for MinItems {
1235    fn to_tokens(&self, tokens: &mut TokenStream) {
1236        self.0.to_tokens(tokens);
1237    }
1238}
1239
1240impl From<MinItems> for Feature {
1241    fn from(value: MinItems) -> Self {
1242        Feature::MinItems(value)
1243    }
1244}
1245
1246name!(MinItems = "min_items");
1247
1248#[cfg_attr(feature = "debug", derive(Debug))]
1249#[derive(Clone)]
1250pub struct MaxProperties(usize, Ident);
1251
1252impl Parse for MaxProperties {
1253    fn parse(input: ParseStream, ident: Ident) -> syn::Result<Self>
1254    where
1255        Self: Sized,
1256    {
1257        parse_integer(input).map(|max_properties| Self(max_properties, ident))
1258    }
1259}
1260
1261impl ToTokens for MaxProperties {
1262    fn to_tokens(&self, tokens: &mut TokenStream) {
1263        self.0.to_tokens(tokens);
1264    }
1265}
1266
1267impl From<MaxProperties> for Feature {
1268    fn from(value: MaxProperties) -> Self {
1269        Feature::MaxProperties(value)
1270    }
1271}
1272
1273name!(MaxProperties = "max_properties");
1274
1275#[cfg_attr(feature = "debug", derive(Debug))]
1276#[derive(Clone)]
1277pub struct MinProperties(usize, Ident);
1278
1279impl Parse for MinProperties {
1280    fn parse(input: ParseStream, ident: Ident) -> syn::Result<Self>
1281    where
1282        Self: Sized,
1283    {
1284        parse_integer(input).map(|min_properties| Self(min_properties, ident))
1285    }
1286}
1287
1288impl ToTokens for MinProperties {
1289    fn to_tokens(&self, tokens: &mut TokenStream) {
1290        self.0.to_tokens(tokens);
1291    }
1292}
1293
1294impl From<MinProperties> for Feature {
1295    fn from(value: MinProperties) -> Self {
1296        Feature::MinProperties(value)
1297    }
1298}
1299
1300name!(MinProperties = "min_properties");
1301
1302#[cfg_attr(feature = "debug", derive(Debug))]
1303#[derive(Clone)]
1304pub struct SchemaWith(TypePath);
1305
1306impl Parse for SchemaWith {
1307    fn parse(input: ParseStream, _: Ident) -> syn::Result<Self> {
1308        parse_utils::parse_next(input, || input.parse::<TypePath>().map(Self))
1309    }
1310}
1311
1312impl ToTokens for SchemaWith {
1313    fn to_tokens(&self, tokens: &mut TokenStream) {
1314        let path = &self.0;
1315        tokens.extend(quote! {
1316            #path()
1317        })
1318    }
1319}
1320
1321impl From<SchemaWith> for Feature {
1322    fn from(value: SchemaWith) -> Self {
1323        Feature::SchemaWith(value)
1324    }
1325}
1326
1327name!(SchemaWith = "schema_with");
1328
1329#[cfg_attr(feature = "debug", derive(Debug))]
1330#[derive(Clone)]
1331pub struct Description(String);
1332
1333impl Parse for Description {
1334    fn parse(input: ParseStream, _: Ident) -> syn::Result<Self>
1335    where
1336        Self: std::marker::Sized,
1337    {
1338        parse_utils::parse_next_literal_str(input).map(Self)
1339    }
1340}
1341
1342impl ToTokens for Description {
1343    fn to_tokens(&self, tokens: &mut TokenStream) {
1344        self.0.to_tokens(tokens);
1345    }
1346}
1347
1348impl From<String> for Description {
1349    fn from(value: String) -> Self {
1350        Self(value)
1351    }
1352}
1353
1354impl From<Description> for Feature {
1355    fn from(value: Description) -> Self {
1356        Self::Description(value)
1357    }
1358}
1359
1360name!(Description = "description");
1361
1362/// Deprecated feature parsed from macro attributes.
1363///
1364/// This feature supports only syntax parsed from utoipa specific macro attributes, it does not
1365/// support Rust `#[deprecated]` attribute.
1366#[cfg_attr(feature = "debug", derive(Debug))]
1367#[derive(Clone)]
1368pub struct Deprecated(bool);
1369
1370impl Parse for Deprecated {
1371    fn parse(input: ParseStream, _: Ident) -> syn::Result<Self>
1372    where
1373        Self: std::marker::Sized,
1374    {
1375        parse_utils::parse_bool_or_true(input).map(Self)
1376    }
1377}
1378
1379impl ToTokens for Deprecated {
1380    fn to_tokens(&self, tokens: &mut TokenStream) {
1381        let deprecated: crate::Deprecated = self.0.into();
1382        deprecated.to_tokens(tokens);
1383    }
1384}
1385
1386impl From<Deprecated> for Feature {
1387    fn from(value: Deprecated) -> Self {
1388        Self::Deprecated(value)
1389    }
1390}
1391
1392name!(Deprecated = "deprecated");
1393
1394#[cfg_attr(feature = "debug", derive(Debug))]
1395#[derive(Clone)]
1396pub struct As(pub TypePath);
1397
1398impl Parse for As {
1399    fn parse(input: ParseStream, _: Ident) -> syn::Result<Self>
1400    where
1401        Self: std::marker::Sized,
1402    {
1403        parse_utils::parse_next(input, || input.parse()).map(Self)
1404    }
1405}
1406
1407impl From<As> for Feature {
1408    fn from(value: As) -> Self {
1409        Self::As(value)
1410    }
1411}
1412
1413name!(As = "as");
1414
1415#[cfg_attr(feature = "debug", derive(Debug))]
1416#[derive(Clone)]
1417pub struct AdditionalProperties(bool);
1418
1419impl Parse for AdditionalProperties {
1420    fn parse(input: ParseStream, _: Ident) -> syn::Result<Self>
1421    where
1422        Self: std::marker::Sized,
1423    {
1424        parse_utils::parse_bool_or_true(input).map(Self)
1425    }
1426}
1427
1428impl ToTokens for AdditionalProperties {
1429    fn to_tokens(&self, tokens: &mut TokenStream) {
1430        let additional_properties = &self.0;
1431        tokens.extend(quote!(
1432            utoipa::openapi::schema::AdditionalProperties::FreeForm(
1433                #additional_properties
1434            )
1435        ))
1436    }
1437}
1438
1439name!(AdditionalProperties = "additional_properties");
1440
1441impl From<AdditionalProperties> for Feature {
1442    fn from(value: AdditionalProperties) -> Self {
1443        Self::AdditionalProperties(value)
1444    }
1445}
1446
1447#[derive(Clone)]
1448#[cfg_attr(feature = "debug", derive(Debug))]
1449pub struct Required(pub bool);
1450
1451impl Required {
1452    pub fn is_true(&self) -> bool {
1453        self.0
1454    }
1455}
1456
1457impl Parse for Required {
1458    fn parse(input: ParseStream, _: Ident) -> syn::Result<Self>
1459    where
1460        Self: std::marker::Sized,
1461    {
1462        parse_utils::parse_bool_or_true(input).map(Self)
1463    }
1464}
1465
1466impl ToTokens for Required {
1467    fn to_tokens(&self, tokens: &mut TokenStream) {
1468        self.0.to_tokens(tokens)
1469    }
1470}
1471
1472impl From<crate::Required> for Required {
1473    fn from(value: crate::Required) -> Self {
1474        if value == crate::Required::True {
1475            Self(true)
1476        } else {
1477            Self(false)
1478        }
1479    }
1480}
1481
1482impl From<bool> for Required {
1483    fn from(value: bool) -> Self {
1484        Self(value)
1485    }
1486}
1487
1488impl From<Required> for Feature {
1489    fn from(value: Required) -> Self {
1490        Self::Required(value)
1491    }
1492}
1493
1494name!(Required = "required");
1495
1496pub trait Validator {
1497    fn is_valid(&self) -> Result<(), &'static str>;
1498}
1499
1500pub struct IsNumber<'a>(pub &'a SchemaType<'a>);
1501
1502impl Validator for IsNumber<'_> {
1503    fn is_valid(&self) -> Result<(), &'static str> {
1504        if self.0.is_number() {
1505            Ok(())
1506        } else {
1507            Err("can only be used with `number` type")
1508        }
1509    }
1510}
1511
1512pub struct IsString<'a>(&'a SchemaType<'a>);
1513
1514impl Validator for IsString<'_> {
1515    fn is_valid(&self) -> Result<(), &'static str> {
1516        if self.0.is_string() {
1517            Ok(())
1518        } else {
1519            Err("can only be used with `string` type")
1520        }
1521    }
1522}
1523
1524pub struct IsInteger<'a>(&'a SchemaType<'a>);
1525
1526impl Validator for IsInteger<'_> {
1527    fn is_valid(&self) -> Result<(), &'static str> {
1528        if self.0.is_integer() {
1529            Ok(())
1530        } else {
1531            Err("can only be used with `integer` type")
1532        }
1533    }
1534}
1535
1536pub struct IsVec<'a>(&'a TypeTree<'a>);
1537
1538impl Validator for IsVec<'_> {
1539    fn is_valid(&self) -> Result<(), &'static str> {
1540        if self.0.generic_type == Some(GenericType::Vec) {
1541            Ok(())
1542        } else {
1543            Err("can only be used with `Vec`, `array` or `slice` types")
1544        }
1545    }
1546}
1547
1548pub struct AboveZeroUsize(usize);
1549
1550impl Validator for AboveZeroUsize {
1551    fn is_valid(&self) -> Result<(), &'static str> {
1552        if self.0 != 0 {
1553            Ok(())
1554        } else {
1555            Err("can only be above zero value")
1556        }
1557    }
1558}
1559
1560pub struct AboveZeroF64(f64);
1561
1562impl Validator for AboveZeroF64 {
1563    fn is_valid(&self) -> Result<(), &'static str> {
1564        if self.0 > 0.0 {
1565            Ok(())
1566        } else {
1567            Err("can only be above zero value")
1568        }
1569    }
1570}
1571
1572pub struct ValidatorChain<'c> {
1573    inner: &'c dyn Validator,
1574    next: Option<&'c dyn Validator>,
1575}
1576
1577impl Validator for ValidatorChain<'_> {
1578    fn is_valid(&self) -> Result<(), &'static str> {
1579        self.inner.is_valid().and_then(|_| {
1580            if let Some(validator) = self.next.as_ref() {
1581                validator.is_valid()
1582            } else {
1583                // if there is no next validator consider it valid
1584                Ok(())
1585            }
1586        })
1587    }
1588}
1589
1590impl<'c> ValidatorChain<'c> {
1591    pub fn new(validator: &'c dyn Validator) -> Self {
1592        Self {
1593            inner: validator,
1594            next: None,
1595        }
1596    }
1597
1598    pub fn next(mut self, validator: &'c dyn Validator) -> Self {
1599        self.next = Some(validator);
1600
1601        self
1602    }
1603}
1604
1605macro_rules! parse_features {
1606    ($ident:ident as $( $feature:path ),*) => {
1607        {
1608            fn parse(input: syn::parse::ParseStream) -> syn::Result<Vec<crate::component::features::Feature>> {
1609                let names = [$( <crate::component::features::parse_features!(@as_ident $feature) as crate::component::features::Name>::get_name(), )* ];
1610                let mut features = Vec::<crate::component::features::Feature>::new();
1611                let attributes = names.join(", ");
1612
1613                while !input.is_empty() {
1614                    let ident = input.parse::<syn::Ident>().or_else(|_| {
1615                        input.parse::<syn::Token![as]>().map(|as_| syn::Ident::new("as", as_.span))
1616                    }).map_err(|error| {
1617                        syn::Error::new(
1618                            error.span(),
1619                            format!("unexpected attribute, expected any of: {attributes}, {error}"),
1620                        )
1621                    })?;
1622                    let name = &*ident.to_string();
1623
1624                    $(
1625                        if name == <crate::component::features::parse_features!(@as_ident $feature) as crate::component::features::Name>::get_name() {
1626                            features.push(<$feature as crate::component::features::Parse>::parse(input, ident)?.into());
1627                            if !input.is_empty() {
1628                                input.parse::<syn::Token![,]>()?;
1629                            }
1630                            continue;
1631                        }
1632                    )*
1633
1634                    if !names.contains(&name) {
1635                        return Err(syn::Error::new(ident.span(), format!("unexpected attribute: {name}, expected any of: {attributes}")))
1636                    }
1637                }
1638
1639                Ok(features)
1640            }
1641
1642            parse($ident)?
1643        }
1644    };
1645    (@as_ident $( $tt:tt )* ) => {
1646        $( $tt )*
1647    }
1648}
1649
1650pub(crate) use parse_features;
1651
1652pub trait IsInline {
1653    fn is_inline(&self) -> bool;
1654}
1655
1656impl IsInline for Vec<Feature> {
1657    fn is_inline(&self) -> bool {
1658        self.iter()
1659            .find_map(|feature| match feature {
1660                Feature::Inline(inline) if inline.0 => Some(inline),
1661                _ => None,
1662            })
1663            .is_some()
1664    }
1665}
1666
1667pub trait ToTokensExt {
1668    fn to_token_stream(&self) -> TokenStream;
1669}
1670
1671impl ToTokensExt for Vec<Feature> {
1672    fn to_token_stream(&self) -> TokenStream {
1673        self.iter().fold(TokenStream::new(), |mut tokens, item| {
1674            item.to_tokens(&mut tokens);
1675            tokens
1676        })
1677    }
1678}
1679
1680pub trait FeaturesExt {
1681    fn pop_by(&mut self, op: impl FnMut(&Feature) -> bool) -> Option<Feature>;
1682
1683    fn pop_value_type_feature(&mut self) -> Option<super::features::ValueType>;
1684
1685    /// Pop [`Rename`] feature if exists in [`Vec<Feature>`] list.
1686    fn pop_rename_feature(&mut self) -> Option<Rename>;
1687
1688    /// Pop [`RenameAll`] feature if exists in [`Vec<Feature>`] list.
1689    fn pop_rename_all_feature(&mut self) -> Option<RenameAll>;
1690
1691    /// Extract [`XmlAttr`] feature for given `type_tree` if it has generic type [`GenericType::Vec`]
1692    fn extract_vec_xml_feature(&mut self, type_tree: &TypeTree) -> Option<Feature>;
1693}
1694
1695impl FeaturesExt for Vec<Feature> {
1696    fn pop_by(&mut self, op: impl FnMut(&Feature) -> bool) -> Option<Feature> {
1697        self.iter()
1698            .position(op)
1699            .map(|index| self.swap_remove(index))
1700    }
1701
1702    fn pop_value_type_feature(&mut self) -> Option<super::features::ValueType> {
1703        self.pop_by(|feature| matches!(feature, Feature::ValueType(_)))
1704            .and_then(|feature| match feature {
1705                Feature::ValueType(value_type) => Some(value_type),
1706                _ => None,
1707            })
1708    }
1709
1710    fn pop_rename_feature(&mut self) -> Option<Rename> {
1711        self.pop_by(|feature| matches!(feature, Feature::Rename(_)))
1712            .and_then(|feature| match feature {
1713                Feature::Rename(rename) => Some(rename),
1714                _ => None,
1715            })
1716    }
1717
1718    fn pop_rename_all_feature(&mut self) -> Option<RenameAll> {
1719        self.pop_by(|feature| matches!(feature, Feature::RenameAll(_)))
1720            .and_then(|feature| match feature {
1721                Feature::RenameAll(rename_all) => Some(rename_all),
1722                _ => None,
1723            })
1724    }
1725
1726    fn extract_vec_xml_feature(&mut self, type_tree: &TypeTree) -> Option<Feature> {
1727        self.iter_mut().find_map(|feature| match feature {
1728            Feature::XmlAttr(xml_feature) => {
1729                let (vec_xml, value_xml) = xml_feature.split_for_vec(type_tree);
1730
1731                // replace the original xml attribute with splitted value xml
1732                if let Some(mut xml) = value_xml {
1733                    mem::swap(xml_feature, &mut xml)
1734                }
1735
1736                vec_xml.map(Feature::XmlAttr)
1737            }
1738            _ => None,
1739        })
1740    }
1741}
1742
1743impl FeaturesExt for Option<Vec<Feature>> {
1744    fn pop_by(&mut self, op: impl FnMut(&Feature) -> bool) -> Option<Feature> {
1745        self.as_mut().and_then(|features| features.pop_by(op))
1746    }
1747
1748    fn pop_value_type_feature(&mut self) -> Option<super::features::ValueType> {
1749        self.as_mut()
1750            .and_then(|features| features.pop_value_type_feature())
1751    }
1752
1753    fn pop_rename_feature(&mut self) -> Option<Rename> {
1754        self.as_mut()
1755            .and_then(|features| features.pop_rename_feature())
1756    }
1757
1758    fn pop_rename_all_feature(&mut self) -> Option<RenameAll> {
1759        self.as_mut()
1760            .and_then(|features| features.pop_rename_all_feature())
1761    }
1762
1763    fn extract_vec_xml_feature(&mut self, type_tree: &TypeTree) -> Option<Feature> {
1764        self.as_mut()
1765            .and_then(|features| features.extract_vec_xml_feature(type_tree))
1766    }
1767}
1768
1769macro_rules! pop_feature {
1770    ($features:ident => $value:pat_param) => {{
1771        $features.pop_by(|feature| matches!(feature, $value))
1772    }};
1773}
1774
1775pub(crate) use pop_feature;
1776
1777macro_rules! pop_feature_as_inner {
1778    ( $features:ident => $($value:tt)* ) => {
1779        crate::component::features::pop_feature!($features => $( $value )* )
1780            .map(|f| match f {
1781                $( $value )* => {
1782                    crate::component::features::pop_feature_as_inner!( @as_value $( $value )* )
1783                },
1784                _ => unreachable!()
1785            })
1786    };
1787    ( @as_value $tt:tt :: $tr:tt ( $v:tt ) ) => {
1788        $v
1789    }
1790}
1791
1792pub(crate) use pop_feature_as_inner;
1793
1794pub trait IntoInner<T> {
1795    fn into_inner(self) -> T;
1796}
1797
1798macro_rules! impl_into_inner {
1799    ($ident:ident) => {
1800        impl crate::component::features::IntoInner<Vec<Feature>> for $ident {
1801            fn into_inner(self) -> Vec<Feature> {
1802                self.0
1803            }
1804        }
1805
1806        impl crate::component::features::IntoInner<Option<Vec<Feature>>> for Option<$ident> {
1807            fn into_inner(self) -> Option<Vec<Feature>> {
1808                self.map(crate::component::features::IntoInner::into_inner)
1809            }
1810        }
1811    };
1812}
1813
1814pub(crate) use impl_into_inner;
1815
1816pub trait Merge<T>: IntoInner<Vec<Feature>> {
1817    fn merge(self, from: T) -> Self;
1818}
1819
1820macro_rules! impl_merge {
1821    ( $($ident:ident),* ) => {
1822        $(
1823            impl AsMut<Vec<Feature>> for $ident {
1824                fn as_mut(&mut self) -> &mut Vec<Feature> {
1825                    &mut self.0
1826                }
1827            }
1828
1829            impl crate::component::features::Merge<$ident> for $ident {
1830                fn merge(mut self, from: $ident) -> Self {
1831                    let a = self.as_mut();
1832                    let mut b = from.into_inner();
1833
1834                    a.append(&mut b);
1835
1836                    self
1837                }
1838            }
1839        )*
1840    };
1841}
1842
1843pub(crate) use impl_merge;
1844
1845impl IntoInner<Vec<Feature>> for Vec<Feature> {
1846    fn into_inner(self) -> Vec<Feature> {
1847        self
1848    }
1849}
1850
1851impl Merge<Vec<Feature>> for Vec<Feature> {
1852    fn merge(mut self, mut from: Vec<Feature>) -> Self {
1853        self.append(&mut from);
1854        self
1855    }
1856}