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 let mut msg_display_impl = quote!{};
23
24 let size_identifier = Ident::new("s".into(), Span::call_site());
25 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 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 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 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 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 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 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 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 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 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 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 let mut total_size = self.base.bit_serialize(biseri)?;
283
284 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 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 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 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}