schemars_derive/ast/
mod.rs

1mod from_serde;
2
3use crate::attr::{ContainerAttrs, FieldAttrs, VariantAttrs};
4use crate::idents::{GENERATOR, SCHEMA};
5use from_serde::FromSerde;
6use proc_macro2::TokenStream;
7use serde_derive_internals::ast as serde_ast;
8use serde_derive_internals::{Ctxt, Derive};
9use std::collections::BTreeSet;
10
11pub struct Container<'a> {
12    pub ident: syn::Ident,
13    pub serde_attrs: serde_derive_internals::attr::Container,
14    pub data: Data<'a>,
15    pub generics: syn::Generics,
16    pub attrs: ContainerAttrs,
17    /// A set of type params that are used in a `rename` attribute format string, e.g. `T` and `U`
18    /// in `#[schemars(rename = "StructFor{T}And{U}")]`. This does not include const params.
19    pub rename_type_params: BTreeSet<&'a syn::Ident>,
20    /// A set of type params that are "relevant" to the impl, i.e. excluding params only used in
21    /// `PhantomData` or skipped fields
22    pub relevant_type_params: BTreeSet<&'a syn::Ident>,
23}
24
25pub enum Data<'a> {
26    Enum(Vec<Variant<'a>>),
27    Struct(serde_ast::Style, Vec<Field<'a>>),
28}
29
30pub struct Variant<'a> {
31    pub ident: syn::Ident,
32    pub serde_attrs: serde_derive_internals::attr::Variant,
33    pub style: serde_ast::Style,
34    pub fields: Vec<Field<'a>>,
35    pub original: &'a syn::Variant,
36    pub attrs: VariantAttrs,
37}
38
39pub struct Field<'a> {
40    pub member: syn::Member,
41    pub serde_attrs: serde_derive_internals::attr::Field,
42    pub ty: &'a syn::Type,
43    pub original: &'a syn::Field,
44    pub attrs: FieldAttrs,
45}
46
47impl<'a> Container<'a> {
48    pub fn from_ast(item: &'a syn::DeriveInput) -> syn::Result<Container<'a>> {
49        let ctxt = Ctxt::new();
50        let result = serde_ast::Container::from_ast(&ctxt, item, Derive::Deserialize)
51            .ok_or(())
52            .map(|serde| Self::from_serde(&ctxt, serde));
53
54        ctxt.check()
55            .map(|()| result.expect("from_ast set no errors on Ctxt, so should have returned Ok"))
56    }
57
58    pub fn transparent_field(&'a self) -> Option<&'a Field<'a>> {
59        if self.serde_attrs.transparent() {
60            if let Data::Struct(_, fields) = &self.data {
61                return fields.iter().find(|f| f.serde_attrs.transparent());
62            }
63        }
64
65        None
66    }
67
68    pub fn add_mutators(&self, mutators: &mut Vec<TokenStream>) {
69        self.attrs.common.add_mutators(mutators);
70    }
71
72    pub fn name(&'a self) -> std::borrow::Cow<'a, str> {
73        if self.attrs.rename_format_string.is_none() {
74            if let Some(remote_name) = self.serde_attrs.remote().and_then(|r| r.segments.last()) {
75                return remote_name.ident.to_string().into();
76            }
77        }
78
79        self.serde_attrs.name().deserialize_name().into()
80    }
81}
82
83impl Variant<'_> {
84    pub fn name(&self) -> Name {
85        Name(self.serde_attrs.name())
86    }
87
88    pub fn is_unit(&self) -> bool {
89        matches!(self.style, serde_ast::Style::Unit)
90    }
91
92    pub fn add_mutators(&self, mutators: &mut Vec<TokenStream>) {
93        self.attrs.common.add_mutators(mutators);
94    }
95
96    pub fn with_contract_check(&self, action: TokenStream) -> TokenStream {
97        with_contract_check(
98            self.serde_attrs.skip_deserializing(),
99            self.serde_attrs.skip_serializing(),
100            action,
101        )
102    }
103}
104
105impl Field<'_> {
106    pub fn name(&self) -> Name {
107        Name(self.serde_attrs.name())
108    }
109
110    pub fn add_mutators(&self, mutators: &mut Vec<TokenStream>) {
111        self.attrs.common.add_mutators(mutators);
112        self.attrs.validation.add_mutators(mutators);
113
114        if self.serde_attrs.skip_deserializing() {
115            mutators.push(quote! {
116                #SCHEMA.insert("readOnly".into(), true.into());
117            });
118        }
119        if self.serde_attrs.skip_serializing() {
120            mutators.push(quote! {
121                #SCHEMA.insert("writeOnly".into(), true.into());
122            });
123        }
124    }
125
126    pub fn with_contract_check(&self, action: TokenStream) -> TokenStream {
127        with_contract_check(
128            self.serde_attrs.skip_deserializing(),
129            self.serde_attrs.skip_serializing(),
130            action,
131        )
132    }
133}
134
135pub struct Name<'a>(&'a serde_derive_internals::attr::Name);
136
137impl quote::ToTokens for Name<'_> {
138    fn to_tokens(&self, tokens: &mut TokenStream) {
139        let ser_name = self.0.serialize_name();
140        let de_name = self.0.deserialize_name();
141        if ser_name == de_name {
142            ser_name.to_tokens(tokens);
143        } else {
144            quote! {
145                if #GENERATOR.contract().is_serialize() {
146                    #ser_name
147                } else {
148                    #de_name
149                }
150            }
151            .to_tokens(tokens);
152        }
153    }
154}
155
156fn with_contract_check(
157    skip_deserializing: bool,
158    skip_serializing: bool,
159    action: TokenStream,
160) -> TokenStream {
161    match (skip_deserializing, skip_serializing) {
162        (true, true) => TokenStream::new(),
163        (true, false) => quote! {
164            if #GENERATOR.contract().is_serialize() {
165                #action
166            }
167        },
168        (false, true) => quote! {
169            if #GENERATOR.contract().is_deserialize() {
170                #action
171            }
172        },
173        (false, false) => action,
174    }
175}