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                #[automatically_derived]
155                impl std::fmt::Display for #struct_or_enum_identifier {
156                    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
157                        write!(f, "{:?}", self)
158                    }
159                }
160            };
161            // println!("{}", code);
162            code
163        },
164        _ => panic!("BiserdiEnum only allowed for Enums")
165    }.into()
166}
167
168#[proc_macro_derive(BiserdiOneOf, attributes(biserdi_enum_id_dynbits))]
169pub fn biserdi_one_of(item: TokenStream) -> TokenStream {
170    let input = syn::parse_macro_input!(item as syn::DeriveInput);
171
172    let struct_or_enum_identifier = &input.ident;
173    // println!("input: {:?}", input);
174
175    let v: Vec<_> = input.attrs.iter().filter_map(|attr| {
176        if attr.path().is_ident("biserdi_enum_id_dynbits") {
177            let v = attr.meta.require_list().clone().unwrap().tokens.clone().into_iter()
178                .filter_map(|x| {
179                    match x { Literal(v) => Some(v.to_string().parse::<u8>().ok()), _ => None }
180                }).collect::<Vec<_>>();
181            Some(v)
182        } else { None }
183    }).collect::<Vec<_>>().concat();
184    if v.len() != 1 {
185        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)].")
186    }
187    let dyn_bits = v[0];
188
189    match &input.data {
190        Data::Enum(syn::DataEnum { variants, .. }) => {
191            let mut bit_serialize_impl = quote!{};
192            let mut bit_deserialize_impl = quote!{};
193
194            for (id, variant) in variants.iter().enumerate() {
195                let ident = variant.ident.clone();
196                let ty = match variant.fields.clone() {
197                    syn::Fields::Named(_) => panic!("Biserdi for enum only allowed with unnamed fields"),
198                    syn::Fields::Unnamed(ty) => ty.unnamed.clone(),
199                    syn::Fields::Unit => panic!("Biserdi for enum only allowed with unnamed fields"),
200                };
201                // println!("ty: {:?}", ty);
202                let id_u32 = id as u32;
203                let id_token = quote! { #id_u32 };
204
205                bit_serialize_impl.extend(quote! {
206                    #struct_or_enum_identifier::#ident(v) => {
207                        let s = DynInteger::<u32, 32, #dyn_bits>::new(#id_token).bit_serialize(biseri)?;
208                        s + v.bit_serialize(biseri)?
209                    },
210                });
211                bit_deserialize_impl.extend(quote! {
212                    #id_token => {
213                        let v = call_deserialize::<#ty>(version_id, bides)?;
214                        (#struct_or_enum_identifier::#ident(v.0), v.1 + oo_val.1)
215                    },
216                });
217            }
218            let code = quote! {
219                #[automatically_derived]
220                // BiserdiOneOf
221                impl BiserdiTrait for #struct_or_enum_identifier {
222                    fn bit_serialize(self: &Self, biseri: &mut Biseri) -> Option<u64> {
223                        Some(match self {
224                            #bit_serialize_impl
225                        })
226                    }
227                    fn bit_deserialize(version_id: u16, bides: &mut Bides) -> Option<(Self, u64)> {
228                        fn call_deserialize<T:BiserdiTrait>(version_id: u16, bides: &mut Bides) -> Option<(T, u64)> {
229                            T::bit_deserialize(version_id, bides) }
230                        let oo_val = DynInteger::<u32, 32, #dyn_bits>::bit_deserialize(version_id, bides)?;
231                        Some(match oo_val.0.val {
232                            #bit_deserialize_impl
233                            _ => { return None }
234                        })
235                    }
236                }
237                #[automatically_derived]
238                impl std::fmt::Display for #struct_or_enum_identifier {
239                    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
240                        write!(f, "{:?}", self)
241                    }
242                }
243            };
244            // println!("{}", code);
245            code
246        },
247        _ => panic!("BiserdiOneOf only allowed for Enums")
248    }.into()
249}
250
251
252#[proc_macro_derive(BiserdiMsgVersioned)]
253pub fn biserdi_msg_versioned(item: TokenStream) -> TokenStream {
254    let re = Regex::new(r"V([0-9]+)").unwrap();
255
256    let input = syn::parse_macro_input!(item as syn::DeriveInput);
257
258    let struct_or_enum_identifier = &input.ident;
259    match &input.data {
260        Data::Struct(syn::DataStruct { fields, .. }) => {
261            let mut base_ty = None;
262            let mut ext_ty = None;
263            for field in fields {
264                if field.ident.as_ref().unwrap().to_string() == String::from("base") {
265                    base_ty = Some(field.ty.clone());
266                }
267                else if field.ident.as_ref().unwrap().to_string() == String::from("ext") {
268                    ext_ty = Some(field.ty.clone());
269                }
270                else {
271                    panic!("BiserdiMsgVersioned has to have a field 'base' and a field 'ext' and no other.")
272                }
273            }
274            if base_ty.is_none() || ext_ty.is_none() {
275                panic!("BiserdiMsgVersioned has to have a field 'base' and a field 'ext'.")
276            }
277            let code = quote! {
278                #[automatically_derived]
279                impl BiserdiTrait for #struct_or_enum_identifier {
280                    fn bit_serialize(self: &Self, biseri: &mut Biseri) -> Option<u64> {
281                        // send base in any case
282                        let mut total_size = self.base.bit_serialize(biseri)?;
283
284                        // send ext with size
285                        let mut biseri_temp = Biseri::new();
286                        let dyn_msg_size = self.ext.bit_serialize(&mut biseri_temp)?;
287                        biseri_temp.finish_add_data();
288
289                        total_size += DynInteger::<u64, 64, 4>::new(dyn_msg_size).bit_serialize(biseri)?;
290                        total_size += biseri.add_biseri_data(&biseri_temp)?;
291
292                        Some(total_size)
293                    }
294                    fn bit_deserialize(version_id: u16, bides: &mut Bides) -> Option<(Self, u64)> {
295                        fn call_deserialize<T: BiserdiTrait>(version_id: u16, bides: &mut Bides) -> Option<(T, u64)> {
296                            T::bit_deserialize(version_id, bides)
297                        }
298                        let mut total_size = 0;
299
300                        let (base, cur_size) = call_deserialize::<#base_ty>(version_id, bides)?;
301                        total_size += cur_size;
302
303                        let (ext_size, cur_size) = call_deserialize::<DynInteger<u64, 64, 4>>(version_id, bides)?;
304                        total_size += ext_size.val + cur_size;
305                        let (ext, cur_ext_size) = call_deserialize::<#ext_ty>(version_id, bides)?;
306                        if cur_ext_size > ext_size.val { return None; }
307
308                        let skip_bits = ext_size.val - cur_ext_size;
309                        bides.skip_bits(skip_bits);
310
311                        Some((Self{base, ext}, total_size))
312                    }
313                }
314            };
315            // println!("{}", code);
316            code
317        },
318        Data::Enum(syn::DataEnum { variants, .. }) => {
319            let mut bit_serialize_impl = quote! {};
320            let mut bit_deserialize_impl = quote! {};
321
322            for variant in variants.iter() {
323                let ident = variant.ident.clone();
324                if !re.is_match(&ident.to_string()) { panic!("VersionEnums for Biserdi need to have variants in the form of V[0-9]+") }
325
326                let ty = match variant.fields.clone() {
327                    syn::Fields::Named(_) => panic!("Biserdi for enum only allowed with named fields"),
328                    syn::Fields::Unnamed(ty) => ty.unnamed.clone(),
329                    syn::Fields::Unit => panic!("Biserdi for enum only allowed for field with a type"),
330                };
331
332                bit_serialize_impl.extend(quote! {
333                    #struct_or_enum_identifier::#ident(v) => v.bit_serialize(biseri)?, });
334                fn get_capture_num(re: &Regex, str: &String) -> Option<u16>{
335                    re.captures(str)?.get(1)?.as_str().parse::<u16>().ok()
336                }
337                let ver_num = get_capture_num(&re, &ident.to_string()).unwrap();
338                bit_deserialize_impl.extend(quote! {
339                    #ver_num => {
340                        let v = call_deserialize::<#ty>(version_id, bides)?;
341                        (#struct_or_enum_identifier::#ident(v.0), v.1)
342                    },
343                });
344            }
345            let code = quote! {
346                #[automatically_derived]
347                // BiserdiMsgVersioned
348                impl BiserdiTrait for #struct_or_enum_identifier {
349                    fn bit_serialize(self: &Self, biseri: &mut Biseri) -> Option<u64> {
350                        Some(match self {
351                            #bit_serialize_impl
352                        })
353                    }
354                    fn bit_deserialize(version_id: u16, bides: &mut Bides) -> Option<(Self, u64)> {
355                        fn call_deserialize<T:BiserdiTrait>(version_id: u16, bides: &mut Bides) -> Option<(T, u64)> {
356                            T::bit_deserialize(version_id, bides) }
357                        Some(match version_id.clone() {
358                            #bit_deserialize_impl
359                            _ => { return None }
360                        })
361                    }
362                }
363            };
364            // println!("{}", code);
365            code
366        },
367        _ => panic!("BiserdiMsgVersioned only allowed for Structs")
368    }.into()
369}
370
371
372
373#[cfg(test)]
374mod tests {
375    use super::*;
376
377    #[test]
378    fn it_works() {
379
380    }
381}