antelope_client_macros/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, DeriveInput, Fields};
4
5#[proc_macro_derive(StructPacker)]
6pub fn struct_packer_macro(input: TokenStream) -> TokenStream {
7    // Parse the input tokens into a syntax tree
8    let input = parse_macro_input!(input as DeriveInput);
9
10    // Build the trait implementation
11    let name = input.ident;
12    let fields = match input.data {
13        syn::Data::Struct(s) => match s.fields {
14            Fields::Named(fields) => fields.named,
15            Fields::Unnamed(fields) => fields.unnamed,
16            Fields::Unit => panic!("Unit structs are not supported"),
17        },
18        _ => panic!("StructPacker can only be derived for structs"),
19    };
20
21    let size_fields = fields.iter().map(|f| {
22        let field_name = &f.ident;
23        quote! {
24            _size += self.#field_name.size();
25        }
26    });
27
28    let pack_fields = fields.iter().map(|f| {
29        let field_name = &f.ident;
30        quote! {
31            self.#field_name.pack(enc);
32        }
33    });
34
35    let unpack_fields = fields.iter().map(|f| {
36        let field_name = &f.ident;
37        quote! {
38            dec.unpack(&mut self.#field_name);
39        }
40    });
41
42    let expanded = quote! {
43        // Generate the code to be added
44        impl Packer for #name {
45            fn size(&self) -> usize {
46                let mut _size: usize = 0;
47                #(#size_fields)*
48                _size
49            }
50
51            fn pack(&self, enc: &mut Encoder) -> usize {
52                let pos = enc.get_size();
53                #(#pack_fields)*
54                enc.get_size() - pos
55            }
56
57            fn unpack(&mut self, data: &[u8]) -> usize {
58                let mut dec = Decoder::new(data);
59                #(#unpack_fields)*
60                dec.get_pos()
61            }
62        }
63    };
64
65    // Return the generated implementation
66    TokenStream::from(expanded)
67}
68
69
70#[proc_macro_derive(EnumPacker)]
71pub fn enum_packer_macro(input: TokenStream) -> TokenStream {
72    let input = parse_macro_input!(input as DeriveInput);
73    let name = &input.ident;
74
75    let gen = match input.data {
76        syn::Data::Enum(data_enum) => {
77            let size_variants = data_enum.variants.iter().enumerate().map(|(_i, variant)| {
78                let variant_ident = &variant.ident;
79                match &variant.fields {
80                    Fields::Unnamed(fields) => {
81                        if fields.unnamed.len() != 1 {
82                            panic!("Each variant must have exactly one field implementing the Packer trait.");
83                        }
84                        quote! {
85                            #name::#variant_ident(x) => { _size = 1 + x.size(); }
86                        }
87                    },
88                    _ => panic!("Only unnamed fields are supported"),
89                }
90            });
91
92            let pack_variants = data_enum.variants.iter().enumerate().map(|(i, variant)| {
93                let variant_ident = &variant.ident;
94                quote! {
95                    #name::#variant_ident(x) => {
96                        let mut i: u8 = #i as u8;
97                        i.pack(enc);
98                        x.pack(enc);
99                    }
100                }
101            });
102
103            let unpack_variants = data_enum.variants.iter().enumerate().map(|(i, variant)| {
104                let variant_ident = &variant.ident;
105                let variant_type = &variant.fields;
106                let variant_default = match variant_type {
107                    Fields::Unnamed(fields) => {
108                        let ty = &fields.unnamed.first().unwrap().ty;
109                        quote! {
110                            let mut v: #ty = Default::default();
111                            dec.unpack(&mut v);
112                            *self = #name::#variant_ident(v);
113                        }
114                    },
115                    _ => panic!("Only unnamed fields are supported"),
116                };
117                quote! {
118                    #i => {
119                        #variant_default
120                    }
121                }
122            });
123
124            let default_variant = &data_enum.variants[0];
125            let default_variant_ident = &default_variant.ident;
126
127
128            quote! {
129                impl Default for #name {
130                    #[doc = r""]
131                    #[inline]
132                    fn default() -> Self {
133                        #name::#default_variant_ident(Default::default())
134                    }
135                }
136
137                impl ::antelope::serializer::Packer for #name {
138                    fn size(&self) -> usize {
139                        let mut _size: usize = 0;
140                        match self {
141                            #( #size_variants ),*
142                        }
143                        _size
144                    }
145
146                    fn pack(&self, enc: &mut ::antelope::chain::Encoder) -> usize {
147                        let pos = enc.get_size();
148                        match self {
149                            #( #pack_variants ),*
150                        }
151                        enc.get_size() - pos
152                    }
153
154                    fn unpack<'a>(&mut self, data: &'a [u8]) -> usize {
155                        let mut dec = ::antelope::chain::Decoder::new(data);
156                        let mut variant_type_index: u8 = 0;
157                        dec.unpack(&mut variant_type_index);
158                        let variant_type_index = variant_type_index as usize;
159                        match variant_type_index {
160                            #( #unpack_variants ),*
161                            _ => { panic!("bad variant index!"); }
162                        }
163                        dec.get_pos()
164                    }
165                }
166            }
167        },
168        _ => panic!("EnumPacker can only be derived for enums"),
169    };
170
171    TokenStream::from(gen)
172}