Skip to main content

sia_derive/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{Data, DeriveInput, Fields, parse_macro_input};
4
5#[proc_macro_derive(SiaEncode)]
6pub fn derive_sia_encode(input: TokenStream) -> TokenStream {
7    let input = parse_macro_input!(input as DeriveInput);
8    let name = &input.ident;
9
10    let encode_impl = match &input.data {
11        Data::Struct(data) => {
12            let fields = match &data.fields {
13                Fields::Named(fields) => {
14                    let encodes = fields.named.iter().filter_map(|f| match f.vis {
15                        syn::Visibility::Public(_) => {
16                            let name = &f.ident;
17                            Some(quote! { self.#name.encode(w)?; })
18                        }
19                        _ => None,
20                    });
21                    quote! { #(#encodes)* }
22                }
23                Fields::Unnamed(fields) => {
24                    let encodes = fields.unnamed.iter().enumerate().map(|(i, _)| {
25                        let index = syn::Index::from(i);
26                        quote! { self.#index.encode(w)?; }
27                    });
28                    quote! { #(#encodes)* }
29                }
30                Fields::Unit => quote! {},
31            };
32            quote! {
33                #fields
34                Ok(())
35            }
36        }
37        Data::Enum(_) => panic!("enums not supported"),
38        Data::Union(_) => panic!("unions not supported"),
39    };
40
41    let expanded = quote! {
42        impl SiaEncodable for #name {
43            fn encode<W: std::io::Write>(&self, w: &mut W) -> sia::encoding::Result<()> {
44                #encode_impl
45            }
46        }
47    };
48
49    TokenStream::from(expanded)
50}
51
52#[proc_macro_derive(SiaDecode)]
53pub fn derive_sia_decode(input: TokenStream) -> TokenStream {
54    let input = parse_macro_input!(input as DeriveInput);
55    let name = &input.ident;
56
57    let decode_impl = match &input.data {
58        Data::Struct(data) => match &data.fields {
59            Fields::Named(fields) => {
60                let decodes = fields.named.iter().filter_map(|f| match f.vis {
61                    syn::Visibility::Public(_) => {
62                        let name = &f.ident;
63                        let ty = &f.ty;
64                        Some(quote! { #name: <#ty>::decode(r)?, })
65                    }
66                    _ => None,
67                });
68                quote! {
69                    Ok(Self {
70                        #(#decodes)*
71                    })
72                }
73            }
74            Fields::Unnamed(fields) => {
75                let decodes = fields.unnamed.iter().map(|f| {
76                    let ty = &f.ty;
77                    quote! { <#ty>::decode(r)?, }
78                });
79                quote! {
80                    Ok(Self(#(#decodes)*))
81                }
82            }
83            Fields::Unit => quote! { Ok(Self) },
84        },
85        Data::Enum(_) => panic!("enums not supported"),
86        Data::Union(_) => panic!("unions not supported"),
87    };
88
89    let expanded = quote! {
90        impl SiaDecodable for #name {
91            fn decode<R: std::io::Read>(r: &mut R) -> sia::encoding::Result<Self> {
92                #decode_impl
93            }
94        }
95    };
96    TokenStream::from(expanded)
97}
98
99#[proc_macro_derive(V1SiaEncode)]
100pub fn derive_v1_sia_encode(input: TokenStream) -> TokenStream {
101    let input = parse_macro_input!(input as DeriveInput);
102    let name = &input.ident;
103
104    let encode_impl = match &input.data {
105        Data::Struct(data) => {
106            let fields = match &data.fields {
107                Fields::Named(fields) => {
108                    let encodes = fields.named.iter().map(|f| {
109                        let name = &f.ident;
110                        quote! { self.#name.encode_v1(enc)?; }
111                    });
112                    quote! { #(#encodes)* }
113                }
114                Fields::Unnamed(fields) => {
115                    let encodes = fields.unnamed.iter().enumerate().map(|(i, _)| {
116                        let index = syn::Index::from(i);
117                        quote! { self.#index.encode_v1(enc)?; }
118                    });
119                    quote! { #(#encodes)* }
120                }
121                Fields::Unit => quote! {},
122            };
123            quote! {
124                #fields
125                Ok(())
126            }
127        }
128        Data::Enum(_) => panic!("enums not supported"),
129        Data::Union(_) => panic!("unions not supported"),
130    };
131
132    let expanded = quote! {
133        impl V1SiaEncodable for #name {
134            fn encode_v1<W: std::io::Write>(&self, enc: &mut W) -> crate::encoding::Result<()> {
135                #encode_impl
136            }
137        }
138    };
139    TokenStream::from(expanded)
140}
141
142#[proc_macro_derive(V1SiaDecode)]
143pub fn derive_v1_sia_decode(input: TokenStream) -> TokenStream {
144    let input = parse_macro_input!(input as DeriveInput);
145    let name = &input.ident;
146
147    let decode_impl = match &input.data {
148        Data::Struct(data) => match &data.fields {
149            Fields::Named(fields) => {
150                let decodes = fields.named.iter().map(|f| {
151                    let name = &f.ident;
152                    let ty = &f.ty;
153                    quote! { #name: <#ty>::decode_v1(r)?, }
154                });
155                quote! {
156                    Ok(Self {
157                        #(#decodes)*
158                    })
159                }
160            }
161            Fields::Unnamed(fields) => {
162                let decodes = fields.unnamed.iter().map(|f| {
163                    let ty = &f.ty;
164                    quote! { <#ty>::decode_v1(r)?, }
165                });
166                quote! {
167                    Ok(Self(#(#decodes)*))
168                }
169            }
170            Fields::Unit => quote! { Ok(Self) },
171        },
172        Data::Enum(_) => panic!("enums not supported"),
173        Data::Union(_) => panic!("unions not supported"),
174    };
175
176    let expanded = quote! {
177        impl V1SiaDecodable for #name {
178            fn decode_v1<R: std::io::Read>(r: &mut R) -> crate::encoding::Result<Self> {
179                #decode_impl
180            }
181        }
182    };
183    TokenStream::from(expanded)
184}
185
186#[proc_macro_derive(AsyncSiaEncode)]
187pub fn derive_async_sia_encode(input: TokenStream) -> TokenStream {
188    let input = parse_macro_input!(input as DeriveInput);
189    let name = &input.ident;
190
191    let encode_impl = match &input.data {
192        Data::Struct(data) => {
193            let fields = match &data.fields {
194                Fields::Named(fields) => {
195                    let encodes = fields.named.iter().filter_map(|f| match f.vis {
196                        syn::Visibility::Public(_) => {
197                            let name = &f.ident;
198                            Some(quote! { self.#name.encode_async(e).await?; })
199                        }
200                        _ => None,
201                    });
202                    quote! { #(#encodes)* }
203                }
204                Fields::Unnamed(fields) => {
205                    let encodes = fields.unnamed.iter().enumerate().map(|(i, _)| {
206                        let index = syn::Index::from(i);
207                        quote! { self.#index.encode_async(e).await?; }
208                    });
209                    quote! { #(#encodes)* }
210                }
211                Fields::Unit => quote! {},
212            };
213            quote! {
214                #fields
215                Ok(())
216            }
217        }
218        Data::Enum(_) => panic!("enums not supported"),
219        Data::Union(_) => panic!("unions not supported"),
220    };
221
222    let expanded = quote! {
223        impl AsyncSiaEncodable for #name {
224            async fn encode_async<E: crate::encoding_async::AsyncEncoder>(&self, e: &mut E) -> Result<(), E::Error> {
225                #encode_impl
226            }
227        }
228    };
229
230    TokenStream::from(expanded)
231}
232
233#[proc_macro_derive(AsyncSiaDecode)]
234pub fn derive_async_sia_decode(input: TokenStream) -> TokenStream {
235    let input = parse_macro_input!(input as DeriveInput);
236    let name = &input.ident;
237
238    let decode_impl = match &input.data {
239        Data::Struct(data) => match &data.fields {
240            Fields::Named(fields) => {
241                let decodes = fields.named.iter().filter_map(|f| match f.vis {
242                    syn::Visibility::Public(_) => {
243                        let name = &f.ident;
244                        let ty = &f.ty;
245                        Some(quote! { #name: <#ty>::decode_async(d).await?, })
246                    }
247                    _ => None,
248                });
249                quote! {
250                    Ok(Self {
251                        #(#decodes)*
252                    })
253                }
254            }
255            Fields::Unnamed(fields) => {
256                let decodes = fields.unnamed.iter().map(|f| {
257                    let ty = &f.ty;
258                    quote! { <#ty>::decode_async(d).await?, }
259                });
260                quote! {
261                    Ok(Self(#(#decodes)*))
262                }
263            }
264            Fields::Unit => quote! { Ok(Self) },
265        },
266        Data::Enum(_) => panic!("enums not supported"),
267        Data::Union(_) => panic!("unions not supported"),
268    };
269
270    let expanded = quote! {
271        impl AsyncSiaDecodable for #name {
272            async fn decode_async<D: crate::encoding_async::AsyncDecoder>(d: &mut D) -> Result<Self, D::Error> {
273                #decode_impl
274            }
275        }
276    };
277    TokenStream::from(expanded)
278}