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)]
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 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 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 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 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 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 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 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 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 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 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 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 let mut total_size = self.base.bit_serialize(biseri)?;
259
260 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 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 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 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}