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