mini_internal/
ser.rs

1use crate::{attr, bound, fallback};
2use proc_macro2::{Span, TokenStream};
3use quote::quote;
4use syn::{
5    parse_quote, Data, DataEnum, DataStruct, DeriveInput, Error, Fields, FieldsNamed, Result,
6};
7
8pub fn derive(input: &DeriveInput) -> TokenStream {
9    match try_expand(input) {
10        Ok(expanded) => expanded,
11        // If there are invalid attributes in the input, expand to a Serialize
12        // impl anyway to minimize spurious secondary errors in other code that
13        // serializes this type.
14        Err(error) => fallback::ser(input, error),
15    }
16}
17
18fn try_expand(input: &DeriveInput) -> Result<TokenStream> {
19    match &input.data {
20        Data::Struct(DataStruct {
21            fields: Fields::Named(fields),
22            ..
23        }) => derive_struct(input, fields),
24        Data::Enum(enumeration) => derive_enum(input, enumeration),
25        Data::Struct(_) => Err(Error::new(
26            Span::call_site(),
27            "currently only structs with named fields are supported",
28        )),
29        Data::Union(_) => Err(Error::new(
30            Span::call_site(),
31            "currently only structs and enums are supported by this derive",
32        )),
33    }
34}
35
36fn derive_struct(input: &DeriveInput, fields: &FieldsNamed) -> Result<TokenStream> {
37    let ident = &input.ident;
38    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
39
40    let fieldname = &fields.named.iter().map(|f| &f.ident).collect::<Vec<_>>();
41    let fieldstr = fields
42        .named
43        .iter()
44        .map(attr::name_of_field)
45        .collect::<Result<Vec<_>>>()?;
46    let index = 0usize..;
47
48    let wrapper_generics = bound::with_lifetime_bound(&input.generics, "'__a");
49    let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
50    let bound = parse_quote!(miniserde::Serialize);
51    let bounded_where_clause = bound::where_clause_with_bound(&input.generics, bound);
52
53    Ok(quote! {
54        #[allow(deprecated, non_upper_case_globals)]
55        const _: () = {
56            impl #impl_generics miniserde::Serialize for #ident #ty_generics #bounded_where_clause {
57                fn begin(&self) -> miniserde::ser::Fragment {
58                    miniserde::ser::Fragment::Map(miniserde::__private::Box::new(__Map {
59                        data: self,
60                        state: 0,
61                    }))
62                }
63            }
64
65            struct __Map #wrapper_impl_generics #where_clause {
66                data: &'__a #ident #ty_generics,
67                state: miniserde::__private::usize,
68            }
69
70            impl #wrapper_impl_generics miniserde::ser::Map for __Map #wrapper_ty_generics #bounded_where_clause {
71                fn next(&mut self) -> miniserde::__private::Option<(miniserde::__private::Cow<miniserde::__private::str>, &dyn miniserde::Serialize)> {
72                    let __state = self.state;
73                    self.state = __state + 1;
74                    match __state {
75                        #(
76                            #index => miniserde::__private::Some((
77                                miniserde::__private::Cow::Borrowed(#fieldstr),
78                                &self.data.#fieldname,
79                            )),
80                        )*
81                        _ => miniserde::__private::None,
82                    }
83                }
84            }
85        };
86    })
87}
88
89fn derive_enum(input: &DeriveInput, enumeration: &DataEnum) -> Result<TokenStream> {
90    if input.generics.lt_token.is_some() || input.generics.where_clause.is_some() {
91        return Err(Error::new(
92            Span::call_site(),
93            "Enums with generics are not supported",
94        ));
95    }
96
97    let ident = &input.ident;
98
99    let var_idents = enumeration
100        .variants
101        .iter()
102        .map(|variant| match variant.fields {
103            Fields::Unit => Ok(&variant.ident),
104            _ => Err(Error::new_spanned(
105                variant,
106                "Invalid variant: only simple enum variants without fields are supported",
107            )),
108        })
109        .collect::<Result<Vec<_>>>()?;
110    let names = enumeration
111        .variants
112        .iter()
113        .map(attr::name_of_variant)
114        .collect::<Result<Vec<_>>>()?;
115
116    Ok(quote! {
117        #[allow(deprecated, non_upper_case_globals)]
118        const _: () = {
119            impl miniserde::Serialize for #ident {
120                fn begin(&self) -> miniserde::ser::Fragment {
121                    match self {
122                        #(
123                            #ident::#var_idents => {
124                                miniserde::ser::Fragment::Str(miniserde::__private::Cow::Borrowed(#names))
125                            }
126                        )*
127                    }
128                }
129            }
130        };
131    })
132}