1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use proc_macro::{self, TokenStream};
use quote::quote;
use syn::{Data, DeriveInput, Fields, FieldsNamed, FieldsUnnamed, Ident};

#[proc_macro_derive(Serialize)]
pub fn serialize_derive(input: TokenStream) -> TokenStream {
    let ast: syn::DeriveInput = syn::parse(input).unwrap();

    match impl_serialize(ast) {
        Ok(ts) => ts,
        Err(e) => compile_error(&e),
    }
}

///Implement Serialize for a struct
fn impl_serialize(value: DeriveInput) -> Result<TokenStream, String> {
    let name = value.ident;
    let r#impl = match value.data {
        Data::Struct(s) => match s.fields {
            Fields::Named(fields) => impl_serialize_for_struct_with_named_fields(name, fields),
            Fields::Unnamed(fields) => impl_serialize_for_struct_with_unnamed_fields(name, fields),
            Fields::Unit => impl_serialize_for_unit_struct(name),
        },
        _ => return Err("Expected struct".to_string()),
    };
    Ok(r#impl)
}

fn impl_serialize_for_struct_with_named_fields(name: Ident, fields: FieldsNamed) -> TokenStream {
    let mut hashmap = Vec::new();
    hashmap.push(quote! {
        let mut fields = std::collections::hash_map::HashMap::new();
    });
    hashmap.append(
        &mut fields
            .named
            .into_iter()
            .map(|field| {
                let field = field.ident.unwrap();
                quote! {
                    fields.insert(stringify!(#field).to_string(), self.#field.serialize());
                }
            })
            .collect::<Vec<_>>(),
    );

    let gen = quote! {
        impl my_serde_json_library::Serialize for #name {
            fn serialize(&self) -> my_serde_json_library::Value {
                #(#hashmap)*
                my_serde_json_library::Value::Object(fields)
            }
        }
    };

    gen.into()
}

fn impl_serialize_for_struct_with_unnamed_fields(
    name: Ident,
    fields: FieldsUnnamed,
) -> TokenStream {
    let mut hashmap = Vec::new();
    hashmap.push(quote! {
        let mut fields = std::collections::hash_map::HashMap::new();
    });
    hashmap.append(
        &mut fields
            .unnamed
            .into_iter()
            .enumerate()
            .map(|(i, _)| {
                let index = syn::Index::from(i);
                quote! {
                    fields.insert(stringify!(#index).to_string(), self.#index.serialize());
                }
            })
            .collect::<Vec<_>>(),
    );

    let gen = quote! {
        impl my_serde_json_library::Serialize for #name {
            fn serialize(&self) -> my_serde_json_library::Value {
                #(#hashmap)*
                my_serde_json_library::Value::Object(fields)
            }
        }
    };

    gen.into()
}

fn impl_serialize_for_unit_struct(name: Ident) -> TokenStream {
    let hashmap = quote! {
        let mut fields = std::collections::hash_map::HashMap::new();
    };

    let gen = quote! {
        impl my_serde_json_library::Serialize for #name {
            fn serialize(&self) -> my_serde_json_library::Value {
                #hashmap
                my_serde_json_library::Value::Object(fields)
            }
        }
    };

    gen.into()
}

fn compile_error(error: &str) -> TokenStream {
    format!("compile_error!(\"{error}\");").parse().unwrap()
}