musli_macros/
expander.rs

1use std::borrow::Cow;
2use std::collections::BTreeMap;
3
4use proc_macro2::{Span, TokenStream};
5use syn::parse::{Parse, ParseStream};
6use syn::spanned::Spanned;
7
8use crate::internals::attr::{self, ModeIdent, ModeKind, TypeAttr};
9use crate::internals::{Build, Ctxt, Expansion, Mode, NameAll, Only, Parameters, Result, Tokens};
10
11#[derive(Clone, Copy)]
12pub(crate) enum UnsizedMethod {
13    Default,
14    Bytes,
15}
16
17impl UnsizedMethod {
18    /// Get corresponding decoder method name to use.
19    pub(crate) fn as_method_name(&self) -> syn::Ident {
20        match self {
21            Self::Default => syn::Ident::new("decode_unsized", Span::call_site()),
22            Self::Bytes => syn::Ident::new("decode_unsized_bytes", Span::call_site()),
23        }
24    }
25}
26
27pub(crate) struct Name<'a, T> {
28    pub(crate) span: Option<Span>,
29    pub(crate) value: &'a T,
30    pub(crate) ty: syn::Type,
31    pub(crate) method: NameMethod,
32    pub(crate) format_with: Option<&'a (Span, syn::Path)>,
33}
34
35impl<T> Name<'_, T> {
36    pub(crate) fn expr(&self, ident: syn::Ident) -> syn::Expr {
37        match self.method {
38            NameMethod::Unsized(..) => syn::parse_quote!(#ident),
39            NameMethod::Sized => syn::parse_quote!(&#ident),
40        }
41    }
42
43    pub(crate) fn ty(&self) -> Cow<'_, syn::Type> {
44        match self.method {
45            NameMethod::Unsized(..) => {
46                let ty = &self.ty;
47                Cow::Owned(syn::parse_quote!(&#ty))
48            }
49            NameMethod::Sized => Cow::Borrowed(&self.ty),
50        }
51    }
52
53    pub(crate) fn name_format(&self, value: &syn::Ident) -> syn::Expr {
54        match self.format_with {
55            Some((_, path)) => syn::parse_quote!(#path(&#value)),
56            None => syn::parse_quote!(&#value),
57        }
58    }
59}
60
61#[derive(Default, Clone, Copy)]
62pub(crate) enum NameMethod {
63    /// Load the tag by value.
64    #[default]
65    Sized,
66    /// Load the tag by visit.
67    Unsized(UnsizedMethod),
68}
69
70impl NameMethod {
71    pub(crate) fn name_all(&self) -> Option<NameAll> {
72        match self {
73            Self::Sized => None,
74            Self::Unsized(_) => Some(NameAll::Name),
75        }
76    }
77}
78
79impl Parse for NameMethod {
80    fn parse(input: ParseStream<'_>) -> Result<Self, syn::Error> {
81        let string: syn::LitStr = input.parse()?;
82        let s = string.value();
83
84        match s.as_str() {
85            "sized" => Ok(Self::Sized),
86            "unsized" => Ok(Self::Unsized(UnsizedMethod::Default)),
87            "unsized_bytes" => Ok(Self::Unsized(UnsizedMethod::Bytes)),
88            _ => Err(syn::Error::new_spanned(
89                string,
90                "#[musli(name(method = ..))]: Bad value, expected one of \"value\", \"unsized\", \"unsized_bytes\"",
91            )),
92        }
93    }
94}
95
96pub(crate) struct FieldData<'a> {
97    pub(crate) span: Span,
98    pub(crate) index: usize,
99    pub(crate) attr: attr::Field,
100    pub(crate) ident: Option<&'a syn::Ident>,
101    pub(crate) ty: &'a syn::Type,
102}
103
104pub(crate) struct StructData<'a> {
105    pub(crate) name: syn::LitStr,
106    pub(crate) fields: Vec<FieldData<'a>>,
107    pub(crate) kind: StructKind,
108}
109
110pub(crate) struct VariantData<'a> {
111    pub(crate) span: Span,
112    pub(crate) name: syn::LitStr,
113    pub(crate) index: usize,
114    pub(crate) attr: attr::VariantAttr,
115    pub(crate) ident: &'a syn::Ident,
116    pub(crate) fields: Vec<FieldData<'a>>,
117    pub(crate) kind: StructKind,
118}
119
120#[derive(Debug, Clone, Copy)]
121pub(crate) enum StructKind {
122    Indexed(usize),
123    Named,
124    Empty,
125}
126
127pub(crate) struct EnumData<'a> {
128    pub(crate) name: syn::LitStr,
129    pub(crate) variants: Vec<VariantData<'a>>,
130}
131
132pub(crate) enum Data<'a> {
133    Struct(StructData<'a>),
134    Enum(EnumData<'a>),
135    Union,
136}
137
138pub(crate) struct Expander<'a> {
139    pub(crate) input: &'a syn::DeriveInput,
140    pub(crate) cx: Ctxt,
141    pub(crate) type_attr: TypeAttr,
142    pub(crate) data: Data<'a>,
143    pub(crate) prefix: syn::Path,
144    pub(crate) default: Vec<ModeIdent>,
145}
146
147impl<'a> Expander<'a> {
148    pub(crate) fn new(input: &'a syn::DeriveInput, default_crate: &str) -> Self {
149        fn fields<'a>(cx: &Ctxt, fields: &'a syn::Fields) -> Vec<FieldData<'a>> {
150            fields
151                .iter()
152                .enumerate()
153                .map(|(index, field)| FieldData {
154                    span: field.span(),
155                    index,
156                    attr: attr::field_attrs(cx, &field.attrs),
157                    ident: field.ident.as_ref(),
158                    ty: &field.ty,
159                })
160                .collect()
161        }
162
163        let cx = Ctxt::new();
164        let type_attr = attr::type_attrs(&cx, &input.attrs);
165
166        let data = match &input.data {
167            syn::Data::Struct(st) => Data::Struct(StructData {
168                name: syn::LitStr::new(&input.ident.to_string(), input.ident.span()),
169                fields: fields(&cx, &st.fields),
170                kind: match &st.fields {
171                    syn::Fields::Unit => StructKind::Empty,
172                    syn::Fields::Unnamed(f) => StructKind::Indexed(f.unnamed.len()),
173                    syn::Fields::Named(..) => StructKind::Named,
174                },
175            }),
176            syn::Data::Enum(en) => {
177                let variants = en
178                    .variants
179                    .iter()
180                    .enumerate()
181                    .map(|(index, variant)| VariantData {
182                        span: variant.span(),
183                        index,
184                        name: syn::LitStr::new(&variant.ident.to_string(), variant.ident.span()),
185                        attr: attr::variant_attrs(&cx, &variant.attrs),
186                        ident: &variant.ident,
187                        fields: fields(&cx, &variant.fields),
188                        kind: match &variant.fields {
189                            syn::Fields::Unit => StructKind::Empty,
190                            syn::Fields::Unnamed(f) => StructKind::Indexed(f.unnamed.len()),
191                            syn::Fields::Named(..) => StructKind::Named,
192                        },
193                    });
194
195                Data::Enum(EnumData {
196                    name: syn::LitStr::new(&input.ident.to_string(), input.ident.span()),
197                    variants: variants.collect(),
198                })
199            }
200            syn::Data::Union(..) => Data::Union,
201        };
202
203        let prefix = type_attr.crate_or_default(default_crate);
204
205        let default = vec![
206            ModeIdent {
207                kind: ModeKind::Binary,
208                path: syn::Path::from(syn::PathSegment::from(syn::Ident::new(
209                    "Binary",
210                    Span::call_site(),
211                ))),
212            },
213            ModeIdent {
214                kind: ModeKind::Text,
215                path: syn::Path::from(syn::PathSegment::from(syn::Ident::new(
216                    "Text",
217                    Span::call_site(),
218                ))),
219            },
220        ];
221
222        Self {
223            input,
224            cx,
225            type_attr,
226            data,
227            prefix,
228            default,
229        }
230    }
231
232    pub(crate) fn tokens(&self) -> Tokens<'_> {
233        Tokens::new(&self.prefix)
234    }
235
236    /// Coerce into errors.
237    pub(crate) fn into_errors(self) -> Vec<syn::Error> {
238        self.cx.into_errors()
239    }
240
241    fn setup_builds<'b>(
242        &'b self,
243        modes: &'b [ModeIdent],
244        tokens: &'b Tokens<'b>,
245        only: Only,
246    ) -> Result<Vec<Build<'b>>> {
247        let mut builds = Vec::new();
248
249        let mut missing = BTreeMap::new();
250
251        for default in &self.default {
252            missing.insert(&default.kind, default);
253        }
254
255        let (lt, lt_exists) = 'out: {
256            if let Some(lt) = self.input.generics.lifetimes().next() {
257                break 'out (lt.lifetime.clone(), true);
258            }
259
260            (syn::Lifetime::new("'__de", Span::call_site()), false)
261        };
262
263        let (allocator_ident, allocator_exists) = 'out: {
264            for p in self.input.generics.type_params() {
265                if p.ident == "A" {
266                    break 'out (p.ident.clone(), true);
267                }
268            }
269
270            (
271                self.cx.type_with_span_permanent("__A", Span::call_site()),
272                false,
273            )
274        };
275
276        let p = Parameters {
277            lt,
278            lt_exists,
279            allocator_ident,
280            allocator_exists,
281        };
282
283        for mode_ident in modes {
284            missing.remove(&mode_ident.kind);
285
286            let expansion = Expansion { mode_ident };
287
288            let mode = expansion.as_mode(tokens, only);
289            let p = self.decorate(&p, &mode);
290
291            builds.push(crate::internals::build::setup(
292                self, expansion, mode, tokens, p,
293            )?);
294        }
295
296        for (_, mode_ident) in missing {
297            let expansion = Expansion { mode_ident };
298
299            let mode = expansion.as_mode(tokens, only);
300            let p = self.decorate(&p, &mode);
301
302            builds.push(crate::internals::build::setup(
303                self, expansion, mode, tokens, p,
304            )?);
305        }
306
307        Ok(builds)
308    }
309
310    fn decorate(&self, p: &Parameters, mode: &Mode<'_>) -> Parameters {
311        let (lt, lt_exists) = 'out: {
312            let list = self.type_attr.decode_bounds_lifetimes(mode);
313
314            if let [_, rest @ ..] = list {
315                for &(span, _) in rest {
316                    self.cx
317                        .error_span(span, "More than one decoder lifetime bound is specified");
318                }
319            }
320
321            if let Some((_, ty)) = list.first() {
322                break 'out (ty, false);
323            }
324
325            (&p.lt, p.lt_exists)
326        };
327
328        let (allocator_ident, allocator_exists) = 'out: {
329            let list = self.type_attr.decode_bounds_types(mode);
330
331            if let [_, rest @ ..] = list {
332                for &(span, _) in rest {
333                    self.cx
334                        .error_span(span, "More than one decoder allocator bound is specified");
335                }
336            }
337
338            if let Some((_, ty)) = list.first() {
339                break 'out (ty, false);
340            }
341
342            (&p.allocator_ident, p.allocator_exists)
343        };
344
345        Parameters {
346            lt: lt.clone(),
347            lt_exists,
348            allocator_ident: allocator_ident.clone(),
349            allocator_exists,
350        }
351    }
352
353    /// Expand Encode implementation.
354    pub(crate) fn expand_encode(&self) -> Result<TokenStream> {
355        let modes = self.cx.modes();
356        let tokens = self.tokens();
357        let builds = self.setup_builds(&modes, &tokens, Only::Encode)?;
358
359        let mut out = TokenStream::new();
360
361        for build in builds {
362            out.extend(crate::en::expand_encode_entry(&build)?);
363        }
364
365        Ok(out)
366    }
367
368    /// Expand Decode implementation.
369    pub(crate) fn expand_decode(&self) -> Result<TokenStream> {
370        let modes = self.cx.modes();
371        let tokens = self.tokens();
372        let builds = self.setup_builds(&modes, &tokens, Only::Decode)?;
373
374        let mut out = TokenStream::new();
375
376        for build in builds {
377            out.extend(crate::de::expand_decode_entry(&build)?);
378        }
379
380        Ok(out)
381    }
382}
383
384/// A thing that determines how it's tagged.
385pub(crate) trait Taggable {
386    /// The span of the taggable item.
387    fn span(&self) -> Span;
388    /// The rename configuration the taggable item currently has.
389    fn name(&self, mode: &Mode<'_>) -> Option<&(Span, syn::Expr)>;
390    /// The index of the taggable item.
391    fn index(&self) -> usize;
392}
393
394/// Expand the given configuration to the appropriate tag expression.
395pub(crate) fn expand_name(
396    taggable: &dyn Taggable,
397    mode: &Mode<'_>,
398    name_all: NameAll,
399    ident: Option<&syn::Ident>,
400) -> (syn::Expr, Option<Span>) {
401    let lit = 'out: {
402        if let Some(&(span, ref rename)) = taggable.name(mode) {
403            return (rename.clone(), Some(span));
404        }
405
406        if let (Some(ident), name_all) = (ident, name_all) {
407            let ident = ident.to_string();
408            let ident = ident.trim_start_matches("r#");
409
410            if let Some(name) = name_all.apply(ident) {
411                break 'out syn::LitStr::new(&name, ident.span()).into();
412            }
413        }
414
415        usize_suffixed(taggable.index(), taggable.span()).into()
416    };
417
418    let expr = syn::Expr::Lit(syn::ExprLit {
419        attrs: Vec::new(),
420        lit,
421    });
422
423    (expr, None)
424}
425
426/// Ensure that the given integer is usize-suffixed so that it is treated as the
427/// appropriate type.
428pub(crate) fn usize_suffixed(index: usize, span: Span) -> syn::LitInt {
429    syn::LitInt::new(&format!("{index}usize"), span)
430}
431
432impl Taggable for FieldData<'_> {
433    fn span(&self) -> Span {
434        self.span
435    }
436
437    fn name(&self, mode: &Mode<'_>) -> Option<&(Span, syn::Expr)> {
438        self.attr.name(mode)
439    }
440
441    fn index(&self) -> usize {
442        self.index
443    }
444}
445
446impl Taggable for VariantData<'_> {
447    fn span(&self) -> Span {
448        self.span
449    }
450
451    fn name(&self, mode: &Mode<'_>) -> Option<&(Span, syn::Expr)> {
452        self.attr.name_expr(mode)
453    }
454
455    fn index(&self) -> usize {
456        self.index
457    }
458}