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