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