Skip to main content

stwo_cairo_serialize_derive/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, Data, DeriveInput, Fields};
4
5#[proc_macro_derive(CairoSerialize)]
6pub fn derive_cairo_serialize(input: TokenStream) -> TokenStream {
7    // Parse the input tokens into a syntax tree.
8    let input = parse_macro_input!(input as DeriveInput);
9
10    let struct_name = input.ident;
11    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
12
13    // Extract the fields of the struct.
14    let fields = match input.data {
15        Data::Struct(ref data_struct) => match &data_struct.fields {
16            Fields::Named(ref fields_named) => &fields_named.named,
17            Fields::Unnamed(_) | Fields::Unit => {
18                return syn::Error::new_spanned(
19                    struct_name,
20                    "CairoSerialize can only be derived for structs with named fields.",
21                )
22                .to_compile_error()
23                .into();
24            }
25        },
26        _ => {
27            return syn::Error::new_spanned(
28                struct_name,
29                "CairoSerialize can only be derived for structs.",
30            )
31            .to_compile_error()
32            .into();
33        }
34    };
35
36    // Generate code to serialize each field in the order they appear.
37    let serialize_body = fields.iter().map(|f| {
38        let field_name = &f.ident;
39        quote! {
40            CairoSerialize::serialize(&self.#field_name, output);
41        }
42    });
43
44    // Implement `CairoSerialize` for the type.
45    let expanded = quote! {
46        impl #impl_generics ::stwo_cairo_serialize::CairoSerialize for #struct_name #ty_generics #where_clause {
47            fn serialize(&self, output: &mut Vec<::starknet_ff::FieldElement>) {
48                #(#serialize_body)*
49            }
50        }
51    };
52
53    TokenStream::from(expanded)
54}
55
56#[proc_macro_derive(CairoDeserialize)]
57pub fn derive_cairo_deserialize(input: TokenStream) -> TokenStream {
58    // Parse the input tokens into a syntax tree.
59    let input = parse_macro_input!(input as DeriveInput);
60
61    let struct_name = input.ident;
62    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
63
64    // Extract the fields of the struct.
65    let fields = match input.data {
66        Data::Struct(ref data_struct) => match &data_struct.fields {
67            Fields::Named(ref fields_named) => &fields_named.named,
68            Fields::Unnamed(_) | Fields::Unit => {
69                return syn::Error::new_spanned(
70                    struct_name,
71                    "CairoDeserialize can only be derived for structs with named fields.",
72                )
73                .to_compile_error()
74                .into();
75            }
76        },
77        _ => {
78            return syn::Error::new_spanned(
79                struct_name,
80                "CairoDeserialize can only be derived for structs.",
81            )
82            .to_compile_error()
83            .into();
84        }
85    };
86
87    // Generate code to serialize each field in the order they appear.
88    let deserialize_body = fields.iter().map(|f| {
89        let field_name = &f.ident;
90        quote! {
91            #field_name: ::stwo_cairo_serialize::CairoDeserialize::deserialize(data),
92        }
93    });
94
95    // Implement `CairoSerialize` for the type.
96    let expanded = quote! {
97        impl #impl_generics ::stwo_cairo_serialize::CairoDeserialize for #struct_name #ty_generics #where_clause {
98            fn deserialize<'a>(
99                data: &mut impl Iterator<Item = &'a ::starknet_ff::FieldElement>,
100            ) -> Self {
101                Self{ #(#deserialize_body)* }
102            }
103        }
104    };
105
106    TokenStream::from(expanded)
107}