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