derse_derive/
lib.rs

1//! This crate provides procedural macros for automatically deriving serialization and deserialization implementations for custom types.
2//! It leverages the `derse` crate for serialization and deserialization functionalities.
3
4use proc_macro::TokenStream;
5use quote::quote;
6use syn::{
7    parse_macro_input, Data, DataEnum, DataStruct, DeriveInput, Fields, Lifetime, LifetimeParam,
8};
9
10/// Derives the `Serialize` trait for structs and enums.
11///
12/// This macro generates an implementation of the `Serialize` trait for the given type.
13/// It supports both structs and enums, handling named, unnamed, and unit fields.
14#[proc_macro_derive(Serialize)]
15pub fn derse_serialize_derive(input: TokenStream) -> TokenStream {
16    let ast = parse_macro_input!(input as DeriveInput);
17    let krate = get_crate_name();
18    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
19
20    let struct_type = &ast.ident;
21    let statements = match ast.data {
22        Data::Struct(DataStruct { fields, .. }) => {
23            let mut idents = fields
24                .iter()
25                .enumerate()
26                .map(|(i, f)| {
27                    let index = syn::Index::from(i);
28                    f.ident
29                        .as_ref()
30                        .map_or(quote! {#index}, |ident| quote! {#ident})
31                })
32                .collect::<Vec<_>>();
33            idents.reverse();
34            quote! { #( self.#idents.serialize_to(serializer)?; )* }
35        }
36        Data::Enum(DataEnum { variants, .. }) => {
37            let mut match_statements = Vec::new();
38            for variant in variants {
39                let ident = &variant.ident;
40                let name = ident.to_string();
41                let match_statement = match variant.fields {
42                    Fields::Named(fields) => {
43                        let mut idents = fields.named.iter().map(|f| &f.ident).collect::<Vec<_>>();
44                        let list = quote! { #(#idents, )* };
45                        idents.reverse();
46                        quote! {
47                            Self::#ident { #list } => {
48                                #( #idents.serialize_to(serializer)?; )*
49                                #name.serialize_to(serializer)?;
50                            }
51                        }
52                    }
53                    Fields::Unnamed(fields) => {
54                        let mut idents = fields
55                            .unnamed
56                            .iter()
57                            .enumerate()
58                            .map(|(i, _)| {
59                                syn::Ident::new(&format!("v{i}"), proc_macro2::Span::call_site())
60                            })
61                            .collect::<Vec<_>>();
62                        let list = quote! { #(#idents, )* };
63                        idents.reverse();
64                        quote! {
65                            Self::#ident ( #list ) => {
66                                #( #idents.serialize_to(serializer)?; )*
67                                #name.serialize_to(serializer)?;
68                            }
69                        }
70                    }
71                    Fields::Unit => quote! {
72                        Self::#ident => {
73                            #name.serialize_to(serializer)?;
74                        }
75                    },
76                };
77                match_statements.push(match_statement);
78            }
79            quote! {
80                match self {
81                    #(#match_statements)*
82                }
83            }
84        }
85        _ => panic!("only struct and enum are supported"),
86    };
87
88    quote! {
89        impl #impl_generics #krate::Serialize for #struct_type #ty_generics #where_clause {
90            fn serialize_to<Serializer: #krate::Serializer>(&self, serializer: &mut Serializer) -> #krate::Result<()> {
91                let start = serializer.len();
92                #statements
93                let len = serializer.len() - start;
94                #krate::VarInt64(len as u64).serialize_to(serializer)
95            }
96        }
97    }.into()
98}
99
100/// Derives the `Deserialize` trait for structs and enums.
101///
102/// This macro generates an implementation of the `Deserialize` trait for the given type.
103/// It supports both structs and enums, handling named, unnamed, and unit fields.
104#[proc_macro_derive(Deserialize)]
105pub fn derse_deserialize_derive(input: TokenStream) -> TokenStream {
106    let ast = parse_macro_input!(input as DeriveInput);
107    let krate = get_crate_name();
108
109    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
110    let mut generics = ast.generics.clone();
111    let (impl_generics, lifetime) = if let Some(lifetime) = ast.generics.lifetimes().next().cloned()
112    {
113        (impl_generics, quote! { #lifetime })
114    } else {
115        let lifetime = Lifetime::new("'derse", proc_macro2::Span::call_site());
116        let lifetime_param = LifetimeParam::new(lifetime.clone());
117        let generic_param = syn::GenericParam::Lifetime(lifetime_param);
118        generics.params.insert(0, generic_param);
119        let (impl_generics, _, _) = generics.split_for_impl();
120        (impl_generics, quote! { #lifetime })
121    };
122
123    let struct_type = &ast.ident;
124    let struct_name = struct_type.to_string();
125    let deserialize_statements = match ast.data {
126        Data::Struct(DataStruct { fields, .. }) => {
127            let statements = fields
128                .iter()
129                .map(|f| {
130                    let statement = quote! {
131                        if buf.is_empty() {
132                            Default::default()
133                        } else {
134                            derse::Deserialize::deserialize_from(buf)?
135                        }
136                    };
137                    f.ident
138                        .as_ref()
139                        .map_or(statement.clone(), |ident| quote! {#ident: #statement})
140                })
141                .collect::<Vec<_>>();
142            match fields {
143                Fields::Named(_) => quote! { let result = Self { #(#statements, )* }; },
144                Fields::Unnamed(_) => quote! { let result = Self ( #(#statements, )* ); },
145                Fields::Unit => quote! { let result = Self; },
146            }
147        }
148        Data::Enum(DataEnum { variants, .. }) => {
149            let mut match_statements = Vec::new();
150            for variant in variants {
151                let ident = &variant.ident;
152                let variant_name = ident.to_string();
153                let statements = variant
154                    .fields
155                    .iter()
156                    .map(|f| {
157                        let statement = quote! {
158                            if buf.is_empty() {
159                                Default::default()
160                            } else {
161                                derse::Deserialize::deserialize_from(buf)?
162                            }
163                        };
164                        f.ident
165                            .as_ref()
166                            .map_or(statement.clone(), |ident| quote! {#ident: #statement})
167                    })
168                    .collect::<Vec<_>>();
169                let match_statement = match variant.fields {
170                    Fields::Named(_) => {
171                        quote! { #variant_name => Self::#ident { #(#statements, )* }, }
172                    }
173                    Fields::Unnamed(_) => {
174                        quote! { #variant_name => Self::#ident ( #(#statements, )* ), }
175                    }
176                    Fields::Unit => quote! { #variant_name => Self::#ident, },
177                };
178                match_statements.push(match_statement);
179            }
180            quote! {
181                let ty = <&str>::deserialize_from(buf)?;
182                let result = match ty {
183                    #(#match_statements)*
184                    _ => return Err(derse::Error::InvalidType(format!("{}::{}", #struct_name, ty))),
185                };
186            }
187        }
188        _ => panic!("only struct and enum are supported"),
189    };
190
191    quote! {
192        impl #impl_generics #krate::DetailedDeserialize<#lifetime> for #struct_type #ty_generics #where_clause {
193            fn deserialize_len<Deserializer: #krate::Deserializer<#lifetime>>(buf: &mut Deserializer) -> #krate::Result<usize> {
194                use #krate::Deserialize;
195                Ok(#krate::VarInt64::deserialize_from(buf)?.0 as usize)
196            }
197
198            fn deserialize_fields<Deserializer: #krate::Deserializer<#lifetime>>(buf: &mut Deserializer) -> #krate::Result<Self>
199            where
200                Self: Sized,
201            {
202                use #krate::Deserialize;
203                #deserialize_statements
204                Ok(result)
205            }
206        }
207
208        impl #impl_generics #krate::Deserialize<#lifetime> for #struct_type #ty_generics #where_clause {
209            fn deserialize_from<Deserializer: #krate::Deserializer<#lifetime>>(buf: &mut Deserializer) -> #krate::Result<Self>
210            where
211                Self: Sized,
212            {
213                use #krate::DetailedDeserialize;
214                let len = Self::deserialize_len(buf)?;
215                let mut buf = buf.advance(len)?;
216                Self::deserialize_fields(&mut buf)
217            }
218        }
219    }.into()
220}
221
222pub(crate) fn get_crate_name() -> proc_macro2::TokenStream {
223    let found_crate = proc_macro_crate::crate_name("derse").unwrap_or_else(|err| {
224        eprintln!("Warning: {}\n    => defaulting to `crate`", err,);
225        proc_macro_crate::FoundCrate::Itself
226    });
227
228    match found_crate {
229        proc_macro_crate::FoundCrate::Itself => quote! { crate },
230        proc_macro_crate::FoundCrate::Name(name) => {
231            let ident = syn::Ident::new(&name, proc_macro2::Span::call_site());
232            quote! { ::#ident }
233        }
234    }
235}