musli_macros/
expander.rs

1use std::collections::BTreeMap;
2
3use proc_macro2::{Span, TokenStream};
4use syn::spanned::Spanned;
5
6use crate::internals::attr::{self, ModeIdent, ModeKind, TypeAttr};
7use crate::internals::build::Build;
8use crate::internals::name::NameAll;
9use crate::internals::tokens::Tokens;
10use crate::internals::{Ctxt, Expansion, Mode, Only, Result};
11
12#[derive(Clone, Copy)]
13pub(crate) enum UnsizedMethod {
14    Default,
15    Bytes,
16}
17
18impl UnsizedMethod {
19    /// Get corresponding decoder method name to use.
20    pub(crate) fn as_method_name(&self) -> syn::Ident {
21        match self {
22            Self::Default => syn::Ident::new("decode_unsized", Span::call_site()),
23            Self::Bytes => syn::Ident::new("decode_unsized_bytes", Span::call_site()),
24        }
25    }
26}
27
28#[derive(Default, Clone, Copy)]
29pub(crate) enum NameMethod {
30    /// Load the tag by value.
31    #[default]
32    Value,
33    /// Load the tag by visit.
34    Unsized(UnsizedMethod),
35}
36
37impl NameMethod {
38    pub(crate) fn name_all(&self) -> Option<NameAll> {
39        match self {
40            Self::Value => None,
41            Self::Unsized(_) => Some(NameAll::Name),
42        }
43    }
44}
45
46pub(crate) struct FieldData<'a> {
47    pub(crate) span: Span,
48    pub(crate) index: usize,
49    pub(crate) attr: attr::Field,
50    pub(crate) ident: Option<&'a syn::Ident>,
51    pub(crate) ty: &'a syn::Type,
52}
53
54pub(crate) struct StructData<'a> {
55    pub(crate) span: Span,
56    pub(crate) name: syn::LitStr,
57    pub(crate) fields: Vec<FieldData<'a>>,
58    pub(crate) kind: StructKind,
59}
60
61pub(crate) struct VariantData<'a> {
62    pub(crate) span: Span,
63    pub(crate) name: syn::LitStr,
64    pub(crate) index: usize,
65    pub(crate) attr: attr::VariantAttr,
66    pub(crate) ident: &'a syn::Ident,
67    pub(crate) fields: Vec<FieldData<'a>>,
68    pub(crate) kind: StructKind,
69}
70
71#[derive(Debug, Clone, Copy)]
72pub(crate) enum StructKind {
73    Indexed(usize),
74    Named,
75    Empty,
76}
77
78pub(crate) struct EnumData<'a> {
79    pub(crate) span: Span,
80    pub(crate) name: syn::LitStr,
81    pub(crate) variants: Vec<VariantData<'a>>,
82}
83
84pub(crate) enum Data<'a> {
85    Struct(StructData<'a>),
86    Enum(EnumData<'a>),
87    Union,
88}
89
90pub(crate) struct Expander<'a> {
91    pub(crate) input: &'a syn::DeriveInput,
92    pub(crate) cx: Ctxt,
93    pub(crate) type_attr: TypeAttr,
94    pub(crate) data: Data<'a>,
95    pub(crate) tokens: Tokens,
96    pub(crate) default: Vec<ModeIdent>,
97}
98
99impl<'a> Expander<'a> {
100    pub(crate) fn new(input: &'a syn::DeriveInput, default_crate: &str) -> Self {
101        fn fields<'a>(cx: &Ctxt, fields: &'a syn::Fields) -> Vec<FieldData<'a>> {
102            fields
103                .iter()
104                .enumerate()
105                .map(|(index, field)| FieldData {
106                    span: field.span(),
107                    index,
108                    attr: attr::field_attrs(cx, &field.attrs),
109                    ident: field.ident.as_ref(),
110                    ty: &field.ty,
111                })
112                .collect()
113        }
114
115        let cx = Ctxt::new();
116        let type_attr = attr::type_attrs(&cx, &input.attrs);
117
118        let data = match &input.data {
119            syn::Data::Struct(st) => Data::Struct(StructData {
120                span: Span::call_site(),
121                name: syn::LitStr::new(&input.ident.to_string(), input.ident.span()),
122                fields: fields(&cx, &st.fields),
123                kind: match &st.fields {
124                    syn::Fields::Unit => StructKind::Empty,
125                    syn::Fields::Unnamed(f) => StructKind::Indexed(f.unnamed.len()),
126                    syn::Fields::Named(..) => StructKind::Named,
127                },
128            }),
129            syn::Data::Enum(en) => {
130                let variants = en
131                    .variants
132                    .iter()
133                    .enumerate()
134                    .map(|(index, variant)| VariantData {
135                        span: variant.span(),
136                        index,
137                        name: syn::LitStr::new(&variant.ident.to_string(), variant.ident.span()),
138                        attr: attr::variant_attrs(&cx, &variant.attrs),
139                        ident: &variant.ident,
140                        fields: fields(&cx, &variant.fields),
141                        kind: match &variant.fields {
142                            syn::Fields::Unit => StructKind::Empty,
143                            syn::Fields::Unnamed(f) => StructKind::Indexed(f.unnamed.len()),
144                            syn::Fields::Named(..) => StructKind::Named,
145                        },
146                    });
147
148                Data::Enum(EnumData {
149                    span: Span::call_site(),
150                    name: syn::LitStr::new(&input.ident.to_string(), input.ident.span()),
151                    variants: variants.collect(),
152                })
153            }
154            syn::Data::Union(..) => Data::Union,
155        };
156
157        let prefix = type_attr.crate_or_default(default_crate);
158
159        let default = vec![
160            ModeIdent {
161                kind: ModeKind::Binary,
162                ident: syn::Ident::new("Binary", Span::call_site()),
163            },
164            ModeIdent {
165                kind: ModeKind::Text,
166                ident: syn::Ident::new("Text", Span::call_site()),
167            },
168        ];
169
170        Self {
171            input,
172            cx,
173            type_attr,
174            data,
175            tokens: Tokens::new(input.ident.span(), prefix),
176            default,
177        }
178    }
179
180    /// Coerce into errors.
181    pub(crate) fn into_errors(self) -> Vec<syn::Error> {
182        self.cx.into_errors()
183    }
184
185    fn setup_builds<'b>(&'b self, modes: &'b [ModeIdent], only: Only) -> Result<Vec<Build<'b>>> {
186        let mut builds = Vec::new();
187
188        let mut missing = BTreeMap::new();
189
190        for default in &self.default {
191            missing.insert(&default.kind, default);
192        }
193
194        for mode_ident in modes {
195            missing.remove(&mode_ident.kind);
196
197            builds.push(crate::internals::build::setup(
198                self,
199                Expansion { mode_ident },
200                only,
201            )?);
202        }
203
204        for (_, mode_ident) in missing {
205            builds.push(crate::internals::build::setup(
206                self,
207                Expansion { mode_ident },
208                only,
209            )?);
210        }
211
212        Ok(builds)
213    }
214
215    /// Expand Encode implementation.
216    pub(crate) fn expand_encode(&self) -> Result<TokenStream> {
217        let modes = self.cx.modes();
218        let builds = self.setup_builds(&modes, Only::Encode)?;
219
220        let mut out = TokenStream::new();
221
222        for build in builds {
223            out.extend(crate::en::expand_insert_entry(build)?);
224        }
225
226        Ok(out)
227    }
228
229    /// Expand Decode implementation.
230    pub(crate) fn expand_decode(&self) -> Result<TokenStream> {
231        let modes = self.cx.modes();
232        let builds = self.setup_builds(&modes, Only::Decode)?;
233
234        let mut out = TokenStream::new();
235
236        for build in builds {
237            out.extend(crate::de::expand_decode_entry(build)?);
238        }
239
240        Ok(out)
241    }
242}
243
244/// A thing that determines how it's tagged.
245pub(crate) trait Taggable {
246    /// The span of the taggable item.
247    fn span(&self) -> Span;
248    /// The rename configuration the taggable item currently has.
249    fn name(&self, mode: Mode<'_>) -> Option<&(Span, syn::Expr)>;
250    /// The index of the taggable item.
251    fn index(&self) -> usize;
252}
253
254/// Expand the given configuration to the appropriate tag expression.
255pub(crate) fn expand_name(
256    taggable: &dyn Taggable,
257    mode: Mode<'_>,
258    name_all: NameAll,
259    ident: Option<&syn::Ident>,
260) -> syn::Expr {
261    let lit = 'out: {
262        if let Some((_, rename)) = taggable.name(mode) {
263            return rename.clone();
264        }
265
266        if let (Some(ident), name_all) = (ident, name_all) {
267            if let Some(name) = name_all.apply(&ident.to_string()) {
268                break 'out syn::LitStr::new(&name, ident.span()).into();
269            }
270        }
271
272        usize_suffixed(taggable.index(), taggable.span()).into()
273    };
274
275    syn::Expr::Lit(syn::ExprLit {
276        attrs: Vec::new(),
277        lit,
278    })
279}
280
281/// Ensure that the given integer is usize-suffixed so that it is treated as the
282/// appropriate type.
283pub(crate) fn usize_suffixed(index: usize, span: Span) -> syn::LitInt {
284    syn::LitInt::new(&format!("{}usize", index), span)
285}
286
287impl Taggable for FieldData<'_> {
288    fn span(&self) -> Span {
289        self.span
290    }
291
292    fn name(&self, mode: Mode<'_>) -> Option<&(Span, syn::Expr)> {
293        self.attr.name(mode)
294    }
295
296    fn index(&self) -> usize {
297        self.index
298    }
299}
300
301impl Taggable for VariantData<'_> {
302    fn span(&self) -> Span {
303        self.span
304    }
305
306    fn name(&self, mode: Mode<'_>) -> Option<&(Span, syn::Expr)> {
307        self.attr.name(mode)
308    }
309
310    fn index(&self) -> usize {
311        self.index
312    }
313}