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 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}