maestro_symphony_macros/lib.rs
1extern crate proc_macro;
2use proc_macro::TokenStream;
3use quote::{format_ident, quote};
4use syn::{Data, DeriveInput, Fields, parse_macro_input};
5
6#[proc_macro_derive(Encode)]
7pub fn encode_derive(input: TokenStream) -> TokenStream {
8 let input = parse_macro_input!(input as DeriveInput);
9 let name = input.ident; // The name of the struct, e.g., `Cursor`
10
11 let encode_impl =
12 match input.data {
13 Data::Struct(data) => {
14 let fields = match data.fields {
15 Fields::Named(fields) => fields.named,
16 Fields::Unnamed(_) => {
17 return syn::Error::new_spanned(
18 name,
19 "Tuple structs are not yet supported for Encode",
20 )
21 .to_compile_error()
22 .into();
23 }
24 Fields::Unit => {
25 return syn::Error::new_spanned(
26 name,
27 "Unit structs are not yet supported for Encode",
28 )
29 .to_compile_error()
30 .into();
31 }
32 };
33
34 let encoding = fields.iter().map(|f| {
35 let field_name = &f.ident;
36 quote! {
37 encoder = encoder.append(&self.#field_name);
38 }
39 });
40
41 quote! {
42 impl crate::storage::encdec::Encode for #name {
43 fn encode(&self) -> Vec<u8> {
44 let mut encoder = crate::storage::encdec::EncodeBuilder::new();
45
46 #(#encoding)*
47
48 encoder.build()
49 }
50 }
51 }
52 }
53 Data::Enum(data_enum) => {
54 let variant_encodings = data_enum.variants.iter().enumerate().map(
55 |(index, variant)| {
56 let variant_name = &variant.ident;
57 let variant_index = index as u8; // Encode as first byte
58
59 match &variant.fields {
60 Fields::Unit => {
61 // Unit variant, like `Bitcoin`.
62 quote! {
63 Self::#variant_name => vec![#variant_index]
64 }
65 }
66 Fields::Unnamed(fields) => {
67 // Tuple variant, like `Rune((u64, u32))`.
68 let field_names: Vec<_> = (0..fields.unnamed.len())
69 .map(|i| format_ident!("field{}", i))
70 .collect();
71
72 quote! {
73 Self::#variant_name((#(#field_names),*)) => {
74 vec![vec![#variant_index], #(#field_names.encode()),*].concat()
75 }
76 }
77 }
78 Fields::Named(fields) => {
79 // Struct-like variant, like `SomeVariant { a: A, b: B }`.
80 let field_names: Vec<_> = fields.named.iter()
81 .map(|f| f.ident.as_ref().unwrap())
82 .collect();
83
84 quote! {
85 Self::#variant_name { #(#field_names),* } => {
86 vec![vec![#variant_index], #(#field_names.encode()),*].concat()
87 }
88 }
89 }
90 }
91 });
92
93 quote! {
94 impl crate::storage::encdec::Encode for #name {
95 fn encode(&self) -> Vec<u8> {
96 match self {
97 #(#variant_encodings),*
98 }
99 }
100 }
101 }
102 }
103 _ => {
104 return syn::Error::new_spanned(name, "Encode only supports structs and enums")
105 .to_compile_error()
106 .into();
107 }
108 };
109
110 encode_impl.into()
111}
112
113#[proc_macro_derive(Decode)]
114pub fn decode_derive(input: TokenStream) -> TokenStream {
115 let input = parse_macro_input!(input as DeriveInput);
116 let name = input.ident; // The name of the struct, e.g., `Cursor`
117
118 let decode_impl = match input.data {
119 Data::Struct(data) => {
120 let fields = match data.fields {
121 Fields::Named(fields) => fields.named,
122 Fields::Unnamed(_) => {
123 return syn::Error::new_spanned(
124 &name,
125 "Tuple structs are not yet supported for Decode",
126 )
127 .to_compile_error()
128 .into();
129 }
130 Fields::Unit => {
131 return syn::Error::new_spanned(
132 &name,
133 "Unit structs are not yet supported for Decode",
134 )
135 .to_compile_error()
136 .into();
137 }
138 };
139
140 // Collect field names for struct reconstruction
141 let field_names: Vec<_> = fields.iter().map(|f| &f.ident).collect();
142 let field_decodes = fields.iter().map(|f| {
143 let field_name = &f.ident;
144 let field_ty = &f.ty;
145
146 quote! {
147 let (#field_name, rest) = <#field_ty as crate::storage::encdec::Decode>::decode(bytes)?;
148 bytes = rest; // Update the slice to the remaining bytes after decoding
149 }
150 });
151
152 quote! {
153 impl crate::storage::encdec::Decode for #name {
154 fn decode(bytes: &[u8]) -> crate::DecodingResult<Self> {
155 let mut bytes = bytes; // Mutable reference to slice
156
157 #(#field_decodes)*
158 Ok((Self {
159 #(#field_names: #field_names),*
160 }, bytes))
161 }
162 }
163 }
164 }
165 Data::Enum(data_enum) => {
166 // Match the first byte and decode the corresponding variant.
167 let variant_decodings =
168 data_enum
169 .variants
170 .iter()
171 .enumerate()
172 .map(|(index, variant)| {
173 let variant_name = &variant.ident;
174 let variant_index = index as u8; // Variant index, which was encoded as the first byte
175
176 // Use `quote!` to generate the literal for the variant index
177 let variant_index_literal = quote! { #variant_index };
178
179 match &variant.fields {
180 Fields::Unit => {
181 // Unit variant, like `Bitcoin`, no fields to decode
182 quote! {
183 #variant_index_literal => {
184 Ok((Self::#variant_name, bytes))
185 }
186 }
187 }
188 Fields::Unnamed(fields) => {
189 // Tuple variant, like `Rune((u64, u32))`
190 let field_names: Vec<_> = (0..fields.unnamed.len())
191 .map(|i| format_ident!("field{}", i))
192 .collect();
193
194 // Dealing with the fields' decoding
195 let field_decodes = fields.unnamed.iter().enumerate().map(|(i, _)| {
196 let field_ty = &fields.unnamed[i].ty;
197 let field_name = &field_names[i];
198 quote! {
199 let (#field_name, bytes) = <#field_ty as crate::storage::encdec::Decode>::decode(bytes)?;
200 }
201 });
202
203 quote! {
204 #variant_index_literal => {
205 #(#field_decodes)*
206 Ok((Self::#variant_name(#(#field_names),*), bytes))
207 }
208 }
209 }
210 Fields::Named(fields) => {
211 // Struct-like variant, like `SomeVariant { a: A, b: B }`
212 let field_names: Vec<_> = fields
213 .named
214 .iter()
215 .map(|f| f.ident.as_ref().unwrap())
216 .collect();
217
218 let field_decodes = fields.named.iter().map(|f| {
219 let field_ty = &f.ty;
220 let field_name = &f.ident;
221 quote! {
222 let (#field_name, bytes) = <#field_ty as crate::storage::encdec::Decode>::decode(bytes)?;
223 }
224 });
225
226 quote! {
227 #variant_index_literal => {
228 #(#field_decodes)*
229 Ok((Self::#variant_name { #(#field_names),* }, bytes))
230 }
231 }
232 }
233 }
234 });
235
236 // Wrap the implementation into the final output for the `Decode` trait
237 quote! {
238 impl crate::storage::encdec::Decode for #name {
239 fn decode(bytes: &[u8]) -> crate::DecodingResult<Self> {
240 if bytes.is_empty() {
241 return Err(crate::DecodingError::MalformedInput("enum insufficient bytes".to_string(), bytes.to_vec()))
242 }
243
244 let kind = bytes[0];
245 let bytes = &bytes[1..];
246 match kind {
247 // For each variant, match the index byte and decode accordingly
248 #(#variant_decodings)*
249 _ => Err(crate::DecodingError::InvalidEnumKind(bytes.to_vec())),
250 }
251 }
252 }
253 }
254 }
255 _ => {
256 return syn::Error::new_spanned(name, "Decode only supports structs and enums")
257 .to_compile_error()
258 .into();
259 }
260 };
261
262 decode_impl.into()
263}