antelope_client_macros/
lib.rs1use 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 let input = parse_macro_input!(input as DeriveInput);
9
10 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 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 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}