bitis_macros/
lib.rs

1extern crate proc_macro2;
2
3use proc_macro::TokenStream;
4use quote::{quote};
5use syn::Data;
6use proc_macro2::{Span, Ident};
7use proc_macro2::TokenTree::Literal;
8use regex::Regex;
9
10//#[proc_macro_derive(BiserdiMsg, attributes(biserdi_enum))]
11#[proc_macro_derive(BiserdiMsg)]
12pub fn biserdi_msg(item: TokenStream) -> TokenStream {
13    let input = syn::parse_macro_input!(item as syn::DeriveInput);
14
15    let struct_or_enum_identifier = &input.ident;
16    match &input.data {
17        Data::Struct(syn::DataStruct { fields, .. }) => {
18            let mut bit_serialize_impl = quote!{};
19            let mut bit_deserialize_impl = quote!{};
20            let mut bit_deserialize_impl_init = quote!{};
21            let mut bit_deserialize_impl_size = quote!{0};
22
23            let size_identifier = Ident::new("s".into(), Span::call_site());
24            // let size_identifier = quote::format_ident!("s");
25            let bit_serialize_self_identifier = quote::format_ident!("self");
26
27            for field in fields {
28                let identifier = field.ident.as_ref().unwrap();
29                let ty = field.ty.clone();
30                let temp_identifier = quote::format_ident!("t_{}", identifier);
31
32                bit_serialize_impl.extend(quote!{
33                    #size_identifier += #bit_serialize_self_identifier.#identifier.bit_serialize(biseri)?;
34                });
35                bit_deserialize_impl.extend(quote!{
36                    let #temp_identifier = call_deserialize::<#ty>(version_id, bides)?;
37                });
38                bit_deserialize_impl_init.extend(quote!{
39                    #identifier: #temp_identifier.0,
40                });
41                bit_deserialize_impl_size.extend(quote!{
42                    +#temp_identifier.1
43                });
44            }
45
46            let code = quote! {
47                #[automatically_derived]
48                impl BiserdiTrait for #struct_or_enum_identifier {
49                    fn bit_serialize(self: &Self, biseri: &mut Biseri) -> Option<u64> {
50                        let mut #size_identifier = 0_u64;
51                        #bit_serialize_impl
52                        Some(#size_identifier)
53                    }
54                    fn bit_deserialize(version_id: u16, bides: &mut Bides) -> Option<(Self, u64)> {
55                        fn call_deserialize<T:BiserdiTrait>(version_id: u16, bides: &mut Bides) -> Option<(T, u64)> {
56                            T::bit_deserialize(version_id, bides) }
57                        #bit_deserialize_impl
58                        Some((Self{#bit_deserialize_impl_init}, #bit_deserialize_impl_size))
59                    }
60                }
61            };
62            // println!("{}", code);
63            code
64        },
65        _ => panic!("BiserdiMsg only allowed for Structs")
66    }.into()
67}
68
69#[proc_macro_derive(BiserdiEnum, attributes(biserdi_enum_id_dynbits))]
70pub fn biserdi_enum(item: TokenStream) -> TokenStream {
71    let input = syn::parse_macro_input!(item as syn::DeriveInput);
72
73    let struct_or_enum_identifier = &input.ident;
74    // println!("input: {:?}", input);
75
76    if input.attrs.len() == 0 {
77        panic!("One instance of biserdi_enum_id_dynbits is required with one unsigned integer as attribute (8-bit), e.g. #[biserdi_enum_id_dynbits(4)].")
78    }
79    // println!("meta: {:?}", input.attrs[0].meta);
80
81
82    let v: Vec<_> = input.attrs.iter().filter_map(|attr| {
83        if attr.path().is_ident("biserdi_enum_id_dynbits") {
84            let v = attr.meta.require_list().clone().unwrap().tokens.clone().into_iter()
85                .filter_map(|x| {
86                match x { Literal(v) => Some(v.to_string().parse::<u8>().ok()), _ => None }
87            }).collect::<Vec<_>>();
88            Some(v)
89        } else { None }
90    }).collect::<Vec<_>>().concat();
91    if v.len() != 1 {
92        panic!("One instance of biserdi_enum_id_dynbits is required with one unsigned integer as attribute (8-bit), e.g. #[biserdi_enum_id_dynbits(4)].")
93    }
94    let dyn_bits = v[0];
95
96    match &input.data {
97        Data::Enum(syn::DataEnum { variants, .. }) => {
98            let mut bit_serialize_impl = quote!{};
99            let mut bit_deserialize_impl = quote!{};
100
101            for (id, variant) in variants.iter().enumerate() {
102                let ident = variant.ident.clone();
103                match variant.fields.clone() {
104                    syn::Fields::Named(_) => panic!("Biserdi for enum only allowed witout nested types"),
105                    syn::Fields::Unnamed(_) => panic!("Biserdi for enum only allowed witout nested types"),
106                    syn::Fields::Unit => (),
107                };
108                // println!("ty: {:?}", ty);
109                let id_u32 = id as u32;
110                let id_token = quote! { #id_u32 };
111
112                bit_serialize_impl.extend(quote! {
113                    #struct_or_enum_identifier::#ident => {
114                        DynInteger::<u32, #dyn_bits>::new(#id_token).bit_serialize(biseri)?
115                    },
116                });
117                bit_deserialize_impl.extend(quote! {
118                    #id_token => {
119                        #struct_or_enum_identifier::#ident
120                    },
121                });
122            }
123            let code = quote! {
124                #[automatically_derived]
125                // BiserdiOneOf
126                impl BiserdiTrait for #struct_or_enum_identifier {
127                    fn bit_serialize(self: &Self, biseri: &mut Biseri) -> Option<u64> {
128                        Some(match self {
129                            #bit_serialize_impl
130                        })
131                    }
132                    fn bit_deserialize(version_id: u16, bides: &mut Bides) -> Option<(Self, u64)> {
133                        fn call_deserialize<T:BiserdiTrait>(version_id: u16, bides: &mut Bides) -> Option<(T, u64)> {
134                            T::bit_deserialize(version_id, bides) }
135                        let oo_val = DynInteger::<u32, #dyn_bits>::bit_deserialize(version_id, bides)?;
136                        Some((match oo_val.0.val {
137                            #bit_deserialize_impl
138                            _ => { return None }
139                        }, oo_val.1))
140                    }
141                }
142            };
143            // println!("{}", code);
144            code
145        },
146        _ => panic!("BiserdiEnum only allowed for Enums")
147    }.into()
148}
149
150#[proc_macro_derive(BiserdiOneOf, attributes(biserdi_enum_id_dynbits))]
151pub fn biserdi_one_of(item: TokenStream) -> TokenStream {
152    let input = syn::parse_macro_input!(item as syn::DeriveInput);
153
154    let struct_or_enum_identifier = &input.ident;
155    // println!("input: {:?}", input);
156
157    let v: Vec<_> = input.attrs.iter().filter_map(|attr| {
158        if attr.path().is_ident("biserdi_enum_id_dynbits") {
159            let v = attr.meta.require_list().clone().unwrap().tokens.clone().into_iter()
160                .filter_map(|x| {
161                    match x { Literal(v) => Some(v.to_string().parse::<u8>().ok()), _ => None }
162                }).collect::<Vec<_>>();
163            Some(v)
164        } else { None }
165    }).collect::<Vec<_>>().concat();
166    if v.len() != 1 {
167        panic!("One instance of biserdi_enum_id_dynbits is required with one unsigned integer as attribute (8-bit), e.g. #[biserdi_enum_id_dynbits(4)].")
168    }
169    let dyn_bits = v[0];
170
171    match &input.data {
172        Data::Enum(syn::DataEnum { variants, .. }) => {
173            let mut bit_serialize_impl = quote!{};
174            let mut bit_deserialize_impl = quote!{};
175
176            for (id, variant) in variants.iter().enumerate() {
177                let ident = variant.ident.clone();
178                let ty = match variant.fields.clone() {
179                    syn::Fields::Named(_) => panic!("Biserdi for enum only allowed with unnamed fields"),
180                    syn::Fields::Unnamed(ty) => ty.unnamed.clone(),
181                    syn::Fields::Unit => panic!("Biserdi for enum only allowed with unnamed fields"),
182                };
183                // println!("ty: {:?}", ty);
184                let id_u32 = id as u32;
185                let id_token = quote! { #id_u32 };
186
187                bit_serialize_impl.extend(quote! {
188                    #struct_or_enum_identifier::#ident(v) => {
189                        let s = DynInteger::<u32, #dyn_bits>::new(#id_token).bit_serialize(biseri)?;
190                        s + v.bit_serialize(biseri)?
191                    },
192                });
193                bit_deserialize_impl.extend(quote! {
194                    #id_token => {
195                        let v = call_deserialize::<#ty>(version_id, bides)?;
196                        (#struct_or_enum_identifier::#ident(v.0), v.1 + oo_val.1)
197                    },
198                });
199            }
200            let code = quote! {
201                #[automatically_derived]
202                // BiserdiOneOf
203                impl BiserdiTrait for #struct_or_enum_identifier {
204                    fn bit_serialize(self: &Self, biseri: &mut Biseri) -> Option<u64> {
205                        Some(match self {
206                            #bit_serialize_impl
207                        })
208                    }
209                    fn bit_deserialize(version_id: u16, bides: &mut Bides) -> Option<(Self, u64)> {
210                        fn call_deserialize<T:BiserdiTrait>(version_id: u16, bides: &mut Bides) -> Option<(T, u64)> {
211                            T::bit_deserialize(version_id, bides) }
212                        let oo_val = DynInteger::<u32, #dyn_bits>::bit_deserialize(version_id, bides)?;
213                        Some(match oo_val.0.val {
214                            #bit_deserialize_impl
215                            _ => { return None }
216                        })
217                    }
218                }
219            };
220            // println!("{}", code);
221            code
222        },
223        _ => panic!("BiserdiOneOf only allowed for Enums")
224    }.into()
225}
226
227
228#[proc_macro_derive(BiserdiMsgVersioned)]
229pub fn biserdi_msg_versioned(item: TokenStream) -> TokenStream {
230    let re = Regex::new(r"V([0-9]+)").unwrap();
231
232    let input = syn::parse_macro_input!(item as syn::DeriveInput);
233
234    let struct_or_enum_identifier = &input.ident;
235    match &input.data {
236        Data::Struct(syn::DataStruct { fields, .. }) => {
237            let mut base_ty = None;
238            let mut ext_ty = None;
239            for field in fields {
240                if field.ident.as_ref().unwrap().to_string() == String::from("base") {
241                    base_ty = Some(field.ty.clone());
242                }
243                else if field.ident.as_ref().unwrap().to_string() == String::from("ext") {
244                    ext_ty = Some(field.ty.clone());
245                }
246                else {
247                    panic!("BiserdiMsgVersioned has to have a field 'base' and a field 'ext' and no other.")
248                }
249            }
250            if base_ty.is_none() || ext_ty.is_none() {
251                panic!("BiserdiMsgVersioned has to have a field 'base' and a field 'ext'.")
252            }
253            let code = quote! {
254                #[automatically_derived]
255                impl BiserdiTrait for #struct_or_enum_identifier {
256                    fn bit_serialize(self: &Self, biseri: &mut Biseri) -> Option<u64> {
257                        // send base in any case
258                        let mut total_size = self.base.bit_serialize(biseri)?;
259
260                        // send ext with size
261                        let mut biseri_temp = Biseri::new();
262                        let dyn_msg_size = self.ext.bit_serialize(&mut biseri_temp)?;
263                        biseri_temp.finish_add_data();
264
265                        total_size += DynInteger::<u64, 4>::new(dyn_msg_size).bit_serialize(biseri)?;
266                        total_size += biseri.add_biseri_data(&biseri_temp)?;
267
268                        Some(total_size)
269                    }
270                    fn bit_deserialize(version_id: u16, bides: &mut Bides) -> Option<(Self, u64)> {
271                        fn call_deserialize<T: BiserdiTrait>(version_id: u16, bides: &mut Bides) -> Option<(T, u64)> {
272                            T::bit_deserialize(version_id, bides)
273                        }
274                        let mut total_size = 0;
275
276                        let (base, cur_size) = call_deserialize::<#base_ty>(version_id, bides)?;
277                        total_size += cur_size;
278
279                        let (ext_size, cur_size) = call_deserialize::<DynInteger<u64, 4>>(version_id, bides)?;
280                        total_size += ext_size.val + cur_size;
281                        let (ext, cur_ext_size) = call_deserialize::<#ext_ty>(version_id, bides)?;
282                        if cur_ext_size > ext_size.val { return None; }
283
284                        let skip_bits = ext_size.val - cur_ext_size;
285                        bides.skip_bits(skip_bits);
286
287                        Some((Self{base, ext}, total_size))
288                    }
289                }
290            };
291            // println!("{}", code);
292            code
293        },
294        Data::Enum(syn::DataEnum { variants, .. }) => {
295            let mut bit_serialize_impl = quote! {};
296            let mut bit_deserialize_impl = quote! {};
297
298            for variant in variants.iter() {
299                let ident = variant.ident.clone();
300                if !re.is_match(&ident.to_string()) { panic!("VersionEnums for Biserdi need to have variants in the form of V[0-9]+") }
301
302                let ty = match variant.fields.clone() {
303                    syn::Fields::Named(_) => panic!("Biserdi for enum only allowed with named fields"),
304                    syn::Fields::Unnamed(ty) => ty.unnamed.clone(),
305                    syn::Fields::Unit => panic!("Biserdi for enum only allowed for field with a type"),
306                };
307
308                bit_serialize_impl.extend(quote! {
309                    #struct_or_enum_identifier::#ident(v) => v.bit_serialize(biseri)?, });
310                fn get_capture_num(re: &Regex, str: &String) -> Option<u16>{
311                    re.captures(str)?.get(1)?.as_str().parse::<u16>().ok()
312                }
313                let ver_num = get_capture_num(&re, &ident.to_string()).unwrap();
314                bit_deserialize_impl.extend(quote! {
315                    #ver_num => {
316                        let v = call_deserialize::<#ty>(version_id, bides)?;
317                        (#struct_or_enum_identifier::#ident(v.0), v.1)
318                    },
319                });
320            }
321            let code = quote! {
322                #[automatically_derived]
323                // BiserdiMsgVersioned
324                impl BiserdiTrait for #struct_or_enum_identifier {
325                    fn bit_serialize(self: &Self, biseri: &mut Biseri) -> Option<u64> {
326                        Some(match self {
327                            #bit_serialize_impl
328                        })
329                    }
330                    fn bit_deserialize(version_id: u16, bides: &mut Bides) -> Option<(Self, u64)> {
331                        fn call_deserialize<T:BiserdiTrait>(version_id: u16, bides: &mut Bides) -> Option<(T, u64)> {
332                            T::bit_deserialize(version_id, bides) }
333                        Some(match version_id.clone() {
334                            #bit_deserialize_impl
335                            _ => { return None }
336                        })
337                    }
338                }
339            };
340            // println!("{}", code);
341            code
342        },
343        _ => panic!("BiserdiMsgVersioned only allowed for Structs")
344    }.into()
345}
346
347
348
349#[cfg(test)]
350mod tests {
351    use super::*;
352
353    #[test]
354    fn it_works() {
355
356    }
357}