Skip to main content

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}