tiny_serde_derive/
lib.rs

1use proc_macro::{self, TokenStream};
2use quote::quote;
3use syn::{Data, DeriveInput, Fields, FieldsNamed, FieldsUnnamed, Ident};
4
5#[proc_macro_derive(Serialize)]
6pub fn serialize_derive(input: TokenStream) -> TokenStream {
7    let ast: syn::DeriveInput = syn::parse(input).unwrap();
8
9    match impl_serialize(ast) {
10        Ok(ts) => ts,
11        Err(e) => compile_error(&e),
12    }
13}
14
15///Implement Serialize for a struct
16fn impl_serialize(value: DeriveInput) -> Result<TokenStream, String> {
17    let name = value.ident;
18    let r#impl = match value.data {
19        Data::Struct(s) => match s.fields {
20            Fields::Named(fields) => impl_serialize_for_struct_with_named_fields(name, fields),
21            Fields::Unnamed(fields) => impl_serialize_for_struct_with_unnamed_fields(name, fields),
22            Fields::Unit => impl_serialize_for_unit_struct(name),
23        },
24        _ => return Err("Expected struct".to_string()),
25    };
26    Ok(r#impl)
27}
28
29fn impl_serialize_for_struct_with_named_fields(name: Ident, fields: FieldsNamed) -> TokenStream {
30    let mut hashmap = Vec::new();
31    hashmap.push(quote! {
32        let mut fields = std::collections::hash_map::HashMap::new();
33    });
34    hashmap.append(
35        &mut fields
36            .named
37            .into_iter()
38            .map(|field| {
39                let field = field.ident.unwrap();
40                quote! {
41                    fields.insert(stringify!(#field).to_string(), self.#field.serialize());
42                }
43            })
44            .collect::<Vec<_>>(),
45    );
46
47    let gen = quote! {
48        impl my_serde_json_library::Serialize for #name {
49            fn serialize(&self) -> my_serde_json_library::Value {
50                #(#hashmap)*
51                my_serde_json_library::Value::Object(fields)
52            }
53        }
54    };
55
56    gen.into()
57}
58
59fn impl_serialize_for_struct_with_unnamed_fields(
60    name: Ident,
61    fields: FieldsUnnamed,
62) -> TokenStream {
63    let mut hashmap = Vec::new();
64    hashmap.push(quote! {
65        let mut fields = std::collections::hash_map::HashMap::new();
66    });
67    hashmap.append(
68        &mut fields
69            .unnamed
70            .into_iter()
71            .enumerate()
72            .map(|(i, _)| {
73                let index = syn::Index::from(i);
74                quote! {
75                    fields.insert(stringify!(#index).to_string(), self.#index.serialize());
76                }
77            })
78            .collect::<Vec<_>>(),
79    );
80
81    let gen = quote! {
82        impl my_serde_json_library::Serialize for #name {
83            fn serialize(&self) -> my_serde_json_library::Value {
84                #(#hashmap)*
85                my_serde_json_library::Value::Object(fields)
86            }
87        }
88    };
89
90    gen.into()
91}
92
93fn impl_serialize_for_unit_struct(name: Ident) -> TokenStream {
94    let hashmap = quote! {
95        let mut fields = std::collections::hash_map::HashMap::new();
96    };
97
98    let gen = quote! {
99        impl my_serde_json_library::Serialize for #name {
100            fn serialize(&self) -> my_serde_json_library::Value {
101                #hashmap
102                my_serde_json_library::Value::Object(fields)
103            }
104        }
105    };
106
107    gen.into()
108}
109
110fn compile_error(error: &str) -> TokenStream {
111    format!("compile_error!(\"{error}\");").parse().unwrap()
112}