1extern crate proc_macro;
2
3use quote::{format_ident, quote};
4use syn::{
5 Attribute, Data, DeriveInput, Fields, Lit, PathArguments, Type, parse_macro_input,
6 punctuated::Punctuated, token::Comma,
7};
8
9#[proc_macro_derive(
10 ToBytes,
11 attributes(
12 bits,
13 dyn_int,
14 dyn_length,
15 key_dyn_length,
16 val_dyn_length,
17 toggles,
18 toggled_by,
19 length_for,
20 length_by,
21 variant_for,
22 variant_by,
23 multi_enum,
24 no_discriminator,
25 )
26)]
27pub fn generate_code_to_bytes(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
28 generate_code_binary_serializer(false, input)
29}
30
31#[proc_macro_derive(
32 FromBytes,
33 attributes(
34 bits,
35 dyn_int,
36 key_dyn_length,
37 val_dyn_length,
38 dyn_length,
39 toggles,
40 toggled_by,
41 length_for,
42 length_by,
43 variant_for,
44 variant_by,
45 multi_enum,
46 no_discriminator
47 )
48)]
49pub fn generate_code_from_bytes(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
50 generate_code_binary_serializer(true, input)
51}
52
53fn generate_code_binary_serializer(
54 read: bool,
55 input: proc_macro::TokenStream,
56) -> proc_macro::TokenStream {
57 let ast = parse_macro_input!(input as DeriveInput);
59
60 match ast.data {
61 Data::Struct(ref data) => generate_struct_serializer(read, &ast, data),
62 Data::Enum(ref data) => generate_enum_serializer(read, &ast, data),
63 _ => panic!("ToBytes can only be used on structs"),
64 }
65}
66
67fn generate_field_serializer(
68 read: bool,
69 field_ident: &proc_macro2::Ident,
70 field_type: &syn::Type,
71 field: &syn::Field,
72 is_enum: bool,
73) -> proc_macro2::TokenStream {
74 let single_ident_type_name = if let Type::Path(path) = field_type {
75 if path.path.segments.len() == 1 {
76 Some(path.path.segments[0].ident.to_string())
77 } else {
78 None
79 }
80 } else {
81 None
82 };
83
84 let mut toggle_key = None;
85 let mut variant_keys: Vec<String> = Vec::new();
87 let mut length_keys: Vec<String> = Vec::new();
88 let mut toggled_by = None;
89 let mut variant_by = None;
90 let mut length_by = None;
91 let mut is_dynamic_int = false;
92 let mut has_dynamic_length = false;
93 let mut bits_count = None;
94 let mut key_dyn_length = false;
95 let mut val_dyn_length = false;
96 let mut multi_enum = false;
97
98 for attr in field.attrs.iter() {
100 let ident = attr.path().get_ident().map(|i| i.clone().to_string());
101 match ident.as_deref() {
102 Some("dyn_int") => is_dynamic_int = true,
103 Some("dyn_length") => has_dynamic_length = true,
104 Some("key_dyn_length") => key_dyn_length = true,
105 Some("val_dyn_length") => val_dyn_length = true,
106 Some("multi_enum") => multi_enum = true,
107 Some("toggles") => toggle_key = get_string_value_from_attribute(attr),
108 Some("variant_for") => {
109 if let Some(v) = get_string_value_from_attribute(attr) {
110 variant_keys.push(v);
111 }
112 }
113 Some("length_for") => {
114 if let Some(v) = get_string_value_from_attribute(attr) {
115 length_keys.push(v);
116 }
117 }
118 Some("toggled_by") => toggled_by = get_string_value_from_attribute(attr),
119 Some("variant_by") => variant_by = get_string_value_from_attribute(attr),
120 Some("length_by") => length_by = get_string_value_from_attribute(attr),
121 Some("bits") => bits_count = get_int_value_from_attribute(attr).map(|b| b as u8),
122 _ => {} }
124 }
125
126 let val_reference = if matches!(single_ident_type_name, Some(s) if s == String::from("RefCell"))
127 {
128 if read {
129 quote! {
130 *#field_ident.borrow()
131 }
132 } else {
133 quote! {
134 *_p_val.borrow()
135 }
136 }
137 } else {
138 if read {
139 quote! {
140 _p_val
141 }
142 } else {
143 quote! {
144 *_p_val
145 }
146 }
147 };
148
149 let toggles = if let Some(key) = toggle_key {
151 quote! {
152 _p_config.set_toggle(#key, #val_reference);
153 }
154 } else {
155 quote! {}
156 };
157
158 let length_calls: Vec<proc_macro2::TokenStream> = length_keys
160 .iter()
161 .map(|k| quote! { _p_config.set_length(#k, #val_reference as usize); })
162 .collect();
163
164 let length = if !length_calls.is_empty() {
165 quote! { #(#length_calls)* }
166 } else {
167 quote! {}
168 };
169
170 let variant_calls: Vec<proc_macro2::TokenStream> = variant_keys
172 .iter()
173 .map(|k| quote! { _p_config.set_variant(#k, #val_reference as u8); })
174 .collect();
175
176 let variant = if !variant_calls.is_empty() {
177 quote! { #(#variant_calls)* }
178 } else {
179 quote! {}
180 };
181
182 let f_ident = if is_enum {
184 quote! { #field_ident }
185 } else {
186 quote! { &self.#field_ident }
187 };
188
189 let before = if read {
190 quote! {}
191 } else {
192 quote! {
193 let _p_val = #f_ident;
194 #toggles
195 #length
196 #variant
197 }
198 };
199
200 let after = if read {
201 quote! {
202 let #field_ident = _p_val;
203 #toggles
204 #length
205 #variant
206 }
207 } else {
208 quote! {}
209 };
210
211 let handle_field = generate_code_for_handling_field(
212 read,
213 field_type,
214 field_ident,
215 bits_count,
216 toggled_by,
217 variant_by,
218 length_by,
219 is_dynamic_int,
220 has_dynamic_length,
221 key_dyn_length,
222 val_dyn_length,
223 multi_enum,
224 false,
225 0,
226 );
227
228 quote! {
229 #before
230 #handle_field
231 #after
232 }
233}
234
235fn generate_struct_serializer(
236 read: bool,
237 ast: &DeriveInput,
238 data_struct: &syn::DataStruct,
239) -> proc_macro::TokenStream {
240 let fields = &data_struct.fields;
241 let struct_name = &ast.ident;
242
243 let field_serializations = fields.iter().map(|field| {
245 generate_field_serializer(
246 read,
247 &field
248 .ident
249 .as_ref()
250 .expect("binary-codec does not support fields without a name"),
251 &field.ty,
252 field,
253 false,
254 )
255 });
256
257 let error_type = generate_error_type(read);
258 let serializer_code = if read {
259 let vars = fields.iter().map(|f| f.ident.as_ref().unwrap());
260
261 quote! {
263 impl<T : Clone> binary_codec::BinaryDeserializer<T> for #struct_name {
264 fn read_bytes(
265 stream: &mut binary_codec::BitStreamReader,
266 config: Option<&mut binary_codec::SerializerConfig<T>>,
267 ) -> Result<Self, #error_type> {
268 let mut _new_config = binary_codec::SerializerConfig::new(None);
269 let _p_config = config.unwrap_or(&mut _new_config);
270 let _p_stream = stream;
271
272 #(#field_serializations)*
273
274 Ok(Self {
275 #(#vars),*
276 })
277 }
278 }
279 }
280 } else {
281 quote! {
283 impl<T : Clone> binary_codec::BinarySerializer<T> for #struct_name {
284 fn write_bytes(
285 &self,
286 stream: &mut binary_codec::BitStreamWriter,
287 config: Option<&mut binary_codec::SerializerConfig<T>>,
288 ) -> Result<(), #error_type> {
289 let mut _new_config = binary_codec::SerializerConfig::new(None);
290 let _p_config = config.unwrap_or(&mut _new_config);
291 let _p_stream = stream;
292
293 #(#field_serializations)*
294 Ok(())
295 }
296 }
297 }
298 };
299
300 serializer_code.into()
301}
302
303fn generate_enum_serializer(
304 read: bool,
305 ast: &DeriveInput,
306 data_enum: &syn::DataEnum,
307) -> proc_macro::TokenStream {
308 let enum_name = &ast.ident;
309 let error_type = generate_error_type(read);
310
311 let mut no_disc_prefix = false;
312
313 for attr in ast.attrs.iter() {
315 if attr.path().is_ident("no_discriminator") {
317 no_disc_prefix = true;
318 }
319 }
320
321 let mut configure_functions = Vec::new();
322
323 let mut disc_values: Vec<u8> = Vec::with_capacity(data_enum.variants.len());
326 let mut last_val: Option<u8> = None;
327 for variant in data_enum.variants.iter() {
328 let val = if let Some((_, expr)) = &variant.discriminant {
329 match expr {
330 syn::Expr::Lit(syn::ExprLit { lit: Lit::Int(lit_int), .. }) => {
331 lit_int.base10_parse::<u8>().expect("Invalid discriminant integer")
332 }
333 _ => panic!("Discriminant must be an integer literal"),
334 }
335 } else {
336 match last_val {
337 Some(v) => v + 1,
338 None => 0,
339 }
340 };
341
342 if val > u8::from(u8::MAX) {
343 panic!("Discriminant value too large (must fit in u8)");
344 }
345
346 disc_values.push(val);
347 last_val = Some(val);
348 }
349
350 let disc_variants = data_enum
352 .variants
353 .iter()
354 .enumerate()
355 .map(|(i, variant)| {
356 let var_ident = &variant.ident;
357 let disc_value = disc_values[i];
358
359 for attr in variant.attrs.iter() {
360 if attr.path().is_ident("toggled_by") {
361 let field = get_string_value_from_attribute(attr)
362 .expect("toggled_by for multi_enum should have a value");
363 configure_functions.push(quote! {
364 _p_config.configure_multi_disc(stringify!(#enum_name), #disc_value, #field);
365 });
366 }
367 }
368
369 match &variant.fields {
370 Fields::Unit => quote! {
371 Self::#var_ident => #disc_value
372 },
373 Fields::Unnamed(_) => quote! {
374 Self::#var_ident(..) => #disc_value
375 },
376 Fields::Named(_) => quote! {
377 Self::#var_ident { .. } => #disc_value
378 },
379 }
380 })
381 .collect::<Vec<_>>();
382
383 let serialization_variants = data_enum.variants.iter().enumerate().map(|(i, variant)| {
385 let var_ident = &variant.ident;
386 let disc_value = disc_values[i];
387 let fields = &variant.fields;
388
389 let write_disc = if no_disc_prefix {
392 quote! {}
393 } else {
394 quote! {
395 let _p_disc: u8 = #disc_value;
396 _p_stream.write_fixed_int(_p_disc);
397 }
398 };
399
400 match fields {
401 Fields::Unit => {
402 if read {
403 quote! {
404 #disc_value => {
405 Ok(Self::#var_ident)
406 }
407 }
408 } else {
409 quote! {
410 Self::#var_ident => {
411 #write_disc
412 }
413 }
414 }
415 }
416 Fields::Unnamed(fields_unnamed) => {
417 let field_count = fields_unnamed.unnamed.len();
418 let idents: Vec<_> = (0..field_count).map(|i| format_ident!("f{}", i)).collect();
419 let ident_refs: Vec<&syn::Ident> = idents.iter().collect();
420 let field_serializations =
421 generate_enum_field_serializations(read, &ident_refs, &fields_unnamed.unnamed);
422 if read {
423 quote! {
424 #disc_value => {
425 #(#field_serializations)*
426 Ok(Self::#var_ident(#(#idents),*))
427 }
428 }
429 } else {
430 quote! {
431 Self::#var_ident(#(#idents),*) => {
432 #write_disc
433 #(#field_serializations)*
434 }
435 }
436 }
437 }
438 Fields::Named(fields_named) => {
439 let field_idents: Vec<_> = fields_named
440 .named
441 .iter()
442 .map(|f| f.ident.as_ref().unwrap())
443 .collect();
444
445 let field_serializations =
446 generate_enum_field_serializations(read, &field_idents, &fields_named.named);
447
448 if read {
449 quote! {
450 #disc_value => {
451 #(#field_serializations)*
452 Ok(Self::#var_ident { #(#field_idents),* })
453 }
454 }
455 } else {
456 quote! {
457 Self::#var_ident { #(#field_idents),* } => {
458 #write_disc
459 #(#field_serializations)*
460 }
461 }
462 }
463 }
464 }
465 });
466
467 if read {
468 quote! {
469 impl #enum_name {
470 pub fn configure_multi_disc<T : Clone>(config: &mut binary_codec::SerializerConfig<T>) {
471 let _p_config = config;
472 #(#configure_functions)*
473 }
474 }
475
476 impl<T : Clone> binary_codec::BinaryDeserializer<T> for #enum_name {
477 fn read_bytes(
478 stream: &mut binary_codec::BitStreamReader,
479 config: Option<&mut binary_codec::SerializerConfig<T>>,
480 ) -> Result<Self, #error_type> {
481 let mut _new_config = binary_codec::SerializerConfig::new(None);
482 let _p_config = config.unwrap_or(&mut _new_config);
483 let _p_stream = stream;
484
485 let _p_disc = if let Some(disc) = _p_config.discriminator.take() {
486 disc
487 } else {
488 _p_stream.read_fixed_int()?
489 };
490
491 match _p_disc {
492 #(#serialization_variants,)*
493 _ => Err(#error_type::UnknownDiscriminant(_p_disc)),
494 }
495 }
496 }
497 }
498 .into()
499 } else {
500 quote! {
501 impl<T : Clone> binary_codec::BinarySerializer<T> for #enum_name {
502 fn write_bytes(
503 &self,
504 stream: &mut binary_codec::BitStreamWriter,
505 config: Option<&mut binary_codec::SerializerConfig<T>>,
506 ) -> Result<(), #error_type> {
507 let mut _new_config = binary_codec::SerializerConfig::new(None);
508 let _p_config = config.unwrap_or(&mut _new_config);
509 #(#configure_functions)*
510 let _p_stream = stream;
511
512 match self {
513 #(#serialization_variants)*
514 }
515
516 Ok(())
517 }
518 }
519
520 impl #enum_name {
521 pub fn get_discriminator(&self) -> u8 {
522 match self {
523 #(#disc_variants,)*
524 }
525 }
526 }
527 }
528 .into()
529 }
530}
531
532fn generate_enum_field_serializations(
533 read: bool,
534 idents: &Vec<&syn::Ident>,
535 fields: &Punctuated<syn::Field, Comma>,
536) -> Vec<proc_macro2::TokenStream> {
537 let field_serializations = fields.iter().enumerate().map(|(i, f)| {
538 let field_type = &f.ty;
539 let field_ident = &idents[i];
540
541 generate_field_serializer(read, &field_ident, field_type, f, true)
542 });
543 field_serializations.collect()
544}
545
546fn generate_code_for_handling_field(
547 read: bool,
548 field_type: &Type,
549 field_name: &syn::Ident,
550 bits_count: Option<u8>,
551 toggled_by: Option<String>,
552 variant_by: Option<String>,
553 length_by: Option<String>,
554 is_dynamic_int: bool,
555 has_dynamic_length: bool,
556 key_dyn_length: bool,
557 val_dyn_length: bool,
558 multi_enum: bool,
559 direct_collection_child: bool,
560 level: usize,
561) -> proc_macro2::TokenStream {
562 if let Type::Path(path) = field_type {
563 let path = &path.path;
564
565 if let Some(ident) = path.get_ident() {
566 let ident_name = ident.to_string();
567
568 match ident_name.as_str() {
570 "bool" => {
571 if read {
572 quote! { let _p_val = _p_stream.read_bit()?;}
573 } else {
574 quote! { _p_stream.write_bit(*_p_val); }
575 }
576 }
577 "i8" => {
578 if let Some(bits_count) = bits_count.as_ref() {
579 if *bits_count < 1 || *bits_count > 7 {
580 panic!("Bits count should be between 1 and 7");
581 }
582
583 if read {
584 quote! { let _p_val = binary_codec::ZigZag::to_signed(_p_stream.read_small(#bits_count)?); }
585 } else {
586 quote! { _p_stream.write_small(binary_codec::ZigZag::to_unsigned(*_p_val), #bits_count); }
587 }
588 } else {
589 if read {
590 quote! { let _p_val = _p_stream.read_fixed_int()?; }
591 } else {
592 quote! { _p_stream.write_fixed_int(*_p_val); }
593 }
594 }
595 }
596 "u8" => {
597 if let Some(bits_count) = bits_count.as_ref() {
598 if *bits_count < 1 || *bits_count > 7 {
599 panic!("Bits count should be between 1 and 7");
600 }
601
602 if read {
603 quote! { let _p_val = _p_stream.read_small(#bits_count)?; }
604 } else {
605 quote! { _p_stream.write_small(*_p_val, #bits_count); }
606 }
607 } else {
608 if read {
609 quote! { let _p_val = _p_stream.read_byte()?; }
610 } else {
611 quote! { _p_stream.write_byte(*_p_val); }
612 }
613 }
614 }
615 "u16" | "u32" | "u64" | "u128" => {
616 if is_dynamic_int {
617 let dynint: proc_macro2::TokenStream = generate_dynint(read);
618 if read {
619 quote! {
620 #dynint
621 let _p_val = _p_dyn as #ident;
622 }
623 } else {
624 quote! {
625 let _p_dyn = *_p_val as u128;
626 #dynint
627 }
628 }
629 } else {
630 if read {
631 quote! { let _p_val = _p_stream.read_fixed_int()?; }
632 } else {
633 quote! { _p_stream.write_fixed_int(*_p_val); }
634 }
635 }
636 }
637 "i16" | "i32" | "i64" | "i128" => {
638 if is_dynamic_int {
639 let dynint: proc_macro2::TokenStream = generate_dynint(read);
640 if read {
641 quote! {
642 #dynint
643 let _p_val: #ident = binary_codec::ZigZag::to_signed(_p_dyn);
644 }
645 } else {
646 quote! {
647 let _p_dyn = binary_codec::ZigZag::to_unsigned(*_p_val) as u128;
648 #dynint
649 }
650 }
651 } else {
652 if read {
653 quote! { let _p_val = _p_stream.read_fixed_int()?; }
654 } else {
655 quote! { _p_stream.write_fixed_int(*_p_val); }
656 }
657 }
658 }
659 "String" => {
660 let size_key = generate_size_key(length_by, has_dynamic_length).1;
661
662 if read {
663 quote! {
664 let _p_val = binary_codec::utils::read_string(_p_stream, #size_key, _p_config)?;
665 }
666 } else {
667 quote! {
668 binary_codec::utils::write_string(_p_val, #size_key, _p_stream, _p_config)?;
669 }
670 }
671 }
672 _ => {
673 let size_key = generate_size_key(length_by, has_dynamic_length).1;
674
675 let variant_code = if variant_by.is_some() {
676 quote! {
677 _p_config.discriminator = _p_config.get_variant(#variant_by);
678 }
679 } else if multi_enum {
680 let config_multi = if !direct_collection_child {
681 quote! { #ident::configure_multi_disc(_p_config); }
682 } else {
683 quote! {}
684 };
685
686 quote! {
687 #config_multi
688 _p_config.discriminator = _p_config.get_next_multi_disc(stringify!(#field_name), #ident_name);
689 }
690 } else {
691 quote! {
692 _p_config.discriminator = None;
693 }
694 };
695
696 if read {
697 quote! {
698 #variant_code
699 let _p_val = binary_codec::utils::read_object(_p_stream, #size_key, _p_config)?;
700 }
701 } else {
702 quote! {
703 #variant_code
704 binary_codec::utils::write_object(_p_val, #size_key, _p_stream, _p_config)?;
705 }
706 }
707 }
708 }
709 } else {
710 if path.segments.len() == 1 {
712 let ident = &path.segments[0].ident;
713 let ident_name = ident.to_string();
714
715 match ident_name.as_ref() {
716 "RefCell" => {
717 let inner_type = get_inner_type(path).expect("Option missing inner type");
718 let handle = generate_code_for_handling_field(
719 read,
720 inner_type,
721 field_name,
722 bits_count,
723 None,
724 variant_by,
725 length_by,
726 is_dynamic_int,
727 has_dynamic_length,
728 key_dyn_length,
729 val_dyn_length,
730 multi_enum,
731 false,
732 level + 1,
733 );
734
735 if read {
736 quote! {
737 #handle
738 let _p_val = RefCell::new(_p_val);
739 }
740 } else {
741 quote! {
742 let _p_val = &*_p_val.borrow();
743 #handle
744 }
745 }
746 }
747 "Option" => {
748 let inner_type = get_inner_type(path).expect("Option missing inner type");
749 let handle = generate_code_for_handling_field(
750 read,
751 inner_type,
752 field_name,
753 bits_count,
754 None,
755 variant_by,
756 length_by,
757 is_dynamic_int,
758 has_dynamic_length,
759 key_dyn_length,
760 val_dyn_length,
761 multi_enum,
762 false,
763 level + 1,
764 );
765 let option_name: syn::Ident = format_ident!("__option_{}", level);
766
767 if let Some(toggled_by) = toggled_by {
768 let toggled_by = quote! {
770 _p_config.get_toggle(#toggled_by).unwrap_or(false)
771 };
772
773 if read {
774 quote! {
775 let mut #option_name: Option<#inner_type> = None;
776 if #toggled_by {
777 #handle
778 #option_name = Some(_p_val);
779 }
780 let _p_val = #option_name;
781 }
782 } else {
783 quote! {
784 if #toggled_by {
785 let _p_val = _p_val.as_ref().expect("Expected Some value, because toggled_by field is true");
786 #handle
787 }
788 }
789 }
790 } else {
791 if read {
793 quote! {
794 let mut #option_name: Option<#inner_type> = None;
795 if _p_stream.bytes_left() > 0 {
796 #handle
797 #option_name = Some(_p_val);
798 }
799 let _p_val = #option_name;
800 }
801 } else {
802 quote! {
803 if let Some(_p_val) = _p_val.as_ref() {
804 #handle
805 }
806 }
807 }
808 }
809 }
810 "Vec" => {
811 let vec_name = format_ident!("__val_{}", level);
812 let inner_type = get_inner_type(path).expect("Vec missing inner type");
813
814 if let Type::Path(inner_path) = inner_type {
816 if let Some(inner_ident) = inner_path.path.get_ident() {
817 if inner_ident == "u8" {
818 let (has_size, size_key) = generate_size_key(length_by, has_dynamic_length);
819
820 if read {
821 if has_size || multi_enum {
822 let len_code = if multi_enum {
824 quote! {
825 let _p_len = _p_config.get_multi_disc_size("u8");
827 }
828 } else {
829 quote! {
830 let _p_len = binary_codec::utils::get_read_size(_p_stream, #size_key, _p_config)?;
831 }
832 };
833
834 quote! {
835 #len_code
836 let _p_val = _p_stream.read_bytes(_p_len)?.to_vec();
837 }
838 } else {
839 quote! {
841 let _p_len = _p_stream.bytes_left();
842 let _p_val = _p_stream.read_bytes(_p_len)?.to_vec();
843 }
844 }
845 } else {
846 let write_size = if has_size {
848 quote! {
849 let _p_len = _p_val.len();
850 binary_codec::utils::write_size(_p_len, #size_key, _p_stream, _p_config)?;
851 }
852 } else {
853 quote! {}
854 };
855
856 quote! {
857 #write_size
858 _p_stream.write_bytes(_p_val);
859 }
860 }
861 } else {
862 let handle = generate_code_for_handling_field(
864 read,
865 inner_type,
866 field_name,
867 bits_count,
868 None,
869 None,
870 None,
871 is_dynamic_int,
872 val_dyn_length,
873 false,
874 false,
875 multi_enum,
876 true,
877 level + 1,
878 );
879
880 let (has_size, size_key) = generate_size_key(length_by, has_dynamic_length);
881
882 let write_code = quote! {
883 for _p_val in _p_val {
884 #handle
885 }
886 };
887
888 if has_size || (read && multi_enum) {
889 if read {
890 let len_code = if multi_enum && let Type::Path(path) = inner_type {
891 let enum_ident = path
892 .path
893 .get_ident()
894 .expect("Expected ident for multi_enum inner type");
895 quote! {
896 #enum_ident::configure_multi_disc(_p_config);
897 let _p_len = _p_config.get_multi_disc_size(stringify!(#enum_ident));
898 }
899 } else {
900 quote! {
901 let _p_len = binary_codec::utils::get_read_size(_p_stream, #size_key, _p_config)?;
902 }
903 };
904
905 quote! {
906 #len_code
907 let mut #vec_name = Vec::<#inner_type>::with_capacity(_p_len);
908 for _ in 0.._p_len {
909 #handle
910 #vec_name.push(_p_val);
911 }
912 let _p_val = #vec_name;
913 }
914 } else {
915 quote! {
916 let _p_len = _p_val.len();
917 binary_codec::utils::write_size(_p_len, #size_key, _p_stream, _p_config)?;
918 #write_code
919 }
920 }
921 } else {
922 if read {
923 quote! {
924 let mut #vec_name = Vec::<#inner_type>::new();
925 while _p_stream.bytes_left() > 0 {
926 #handle
927 #vec_name.push(_p_val);
928 }
929 let _p_val = #vec_name;
930 }
931 } else {
932 quote! {
933 #write_code
934 }
935 }
936 }
937 }
938 } else {
939 panic!("Unsupported inner type for Vec");
940 }
941 } else {
942 panic!("Unsupported inner type for Vec");
943 }
944 }
945 "HashMap" => {
946 let (key_type, value_type) =
947 get_two_types(path).expect("Failed to get HashMap types");
948
949 let handle_key = generate_code_for_handling_field(
950 read,
951 key_type,
952 field_name,
953 None,
954 None,
955 None,
956 None,
957 is_dynamic_int,
958 key_dyn_length,
959 false,
960 false,
961 false,
962 false,
963 level + 1,
964 );
965
966 let handle_value = generate_code_for_handling_field(
967 read,
968 value_type,
969 field_name,
970 None,
971 None,
972 None,
973 None,
974 is_dynamic_int,
975 val_dyn_length,
976 false,
977 false,
978 false,
979 false,
980 level + 1,
981 );
982
983 let (has_size, size_key) = generate_size_key(length_by, has_dynamic_length);
984
985 let write_code = quote! {
986 for (key, value) in _p_val {
987 let _p_val = key;
988 #handle_key
989 let _p_val = value;
990 #handle_value
991 }
992 };
993
994 if read {
995 if has_size {
996 quote! {
997 let _p_len = binary_codec::utils::get_read_size(_p_stream, #size_key, _p_config)?;
998 let mut _p_map = std::collections::HashMap::<#key_type, #value_type>::with_capacity(_p_len);
999 for _ in 0.._p_len {
1000 let _p_key;
1001 #handle_key
1002 _p_key = _p_val;
1003 let _p_value;
1004 #handle_value
1005 _p_value = _p_val;
1006 _p_map.insert(_p_key, _p_value);
1007 }
1008 let _p_val = _p_map;
1009 }
1010 } else {
1011 quote! {
1012 let mut _p_map = std::collections::HashMap::<#key_type, #value_type>::new();
1013 while _p_stream.bytes_left() > 0 {
1014 let _p_key;
1015 #handle_key
1016 _p_key = _p_val;
1017 let _p_value;
1018 #handle_value
1019 _p_value = _p_val;
1020 _p_map.insert(_p_key, _p_value);
1021 }
1022 let _p_val = _p_map;
1023 }
1024 }
1025 } else {
1026 if has_size {
1027 quote! {
1028 let _p_len = _p_val.len();
1029 binary_codec::utils::write_size(_p_len, #size_key, _p_stream, _p_config)?;
1030 #write_code
1031 }
1032 } else {
1033 quote! {
1034 #write_code
1035 }
1036 }
1037 }
1038 }
1039 _ => {
1040 panic!("Type not implemented")
1041 }
1042 }
1043 } else {
1044 panic!("Multi-segment paths are not supported");
1045 }
1046 }
1047 } else if let Type::Array(array) = field_type {
1048 let len: usize = if let syn::Expr::Lit(ref arr_len_lit) = array.len {
1049 if let Lit::Int(ref lit_int) = arr_len_lit.lit {
1050 lit_int
1051 .base10_parse()
1052 .expect("Failed to parse literal to usize")
1053 } else {
1054 panic!("Expected an int to determine array length");
1055 }
1056 } else {
1057 panic!("Expected literal to determine array length");
1058 };
1059
1060 let array_type = &*array.elem;
1061 if let Type::Path(at_path) = array_type {
1063 if let Some(at_ident) = at_path.path.get_ident() {
1064 if at_ident == "u8" {
1065 if read {
1066 quote! {
1067 let _p_slice = _p_stream.read_bytes(#len)?;
1068 let _p_val = <[u8; #len]>::try_from(_p_slice).expect("Failed to convert slice to array");
1069 }
1070 } else {
1071 quote! {
1072 _p_stream.write_bytes(_p_val);
1073 }
1074 }
1075 } else {
1076 let handle = generate_code_for_handling_field(
1077 read,
1078 array_type,
1079 field_name,
1080 bits_count,
1081 None,
1082 None,
1083 None,
1084 is_dynamic_int,
1085 val_dyn_length,
1086 false,
1087 false,
1088 false,
1089 true,
1090 level + 1,
1091 );
1092
1093 let array_name = format_ident!("__val_{}", level);
1094
1095 if read {
1096 quote! {
1097 let mut #array_name = Vec::<#array_type>::with_capacity(#len);
1098 for _ in 0..#len {
1099 #handle;
1100 #array_name.push(_p_val);
1101 }
1102 let _p_val = TryInto::<[#array_type; #len]>::try_into(#array_name).expect("Failed to convert Vec to array");
1103 }
1104 } else {
1105 quote! {
1106 for _p_val in _p_val {
1107 #handle
1108 }
1109 }
1110 }
1111 }
1112 } else {
1113 let handle = generate_code_for_handling_field(
1115 read,
1116 array_type,
1117 field_name,
1118 bits_count,
1119 None,
1120 None,
1121 None,
1122 is_dynamic_int,
1123 val_dyn_length,
1124 false,
1125 false,
1126 false,
1127 true,
1128 level + 1,
1129 );
1130
1131 let array_name = format_ident!("__val_{}", level);
1132
1133 if read {
1134 quote! {
1135 let mut #array_name = Vec::<#array_type>::with_capacity(#len);
1136 for _ in 0..#len {
1137 #handle;
1138 #array_name.push(_p_val);
1139 }
1140 let _p_val = TryInto::<[#array_type; #len]>::try_into(#array_name).expect("Failed to convert Vec to array");
1141 }
1142 } else {
1143 quote! {
1144 for _p_val in _p_val {
1145 #handle
1146 }
1147 }
1148 }
1149 }
1150 } else {
1151 panic!("Unsupported array element type");
1152 }
1153 } else {
1154 panic!("Field type of '{:?}' not supported", field_name);
1155 }
1156}
1157
1158fn generate_error_type(read: bool) -> proc_macro2::TokenStream {
1159 if read {
1160 quote! { binary_codec::DeserializationError }
1161 } else {
1162 quote! { binary_codec::SerializationError }
1163 }
1164}
1165
1166fn generate_size_key(
1167 length_by: Option<String>,
1168 has_dynamic_length: bool,
1169) -> (bool, proc_macro2::TokenStream) {
1170 if let Some(length_by) = length_by.as_ref() {
1171 (true, quote! { Some(#length_by) })
1172 } else if has_dynamic_length {
1173 (true, quote! { Some("__dynamic") })
1174 } else {
1175 (false, quote! { None })
1176 }
1177}
1178
1179fn get_string_value_from_attribute(attr: &Attribute) -> Option<String> {
1180 match &attr.meta {
1181 syn::Meta::Path(_) => None,
1182 syn::Meta::List(list_value) => {
1183 for token in list_value.tokens.clone().into_iter() {
1185 if let proc_macro2::TokenTree::Literal(lit) = token {
1186 return Some(lit.to_string().trim_matches('"').to_string());
1187 }
1188 }
1189
1190 None
1191 }
1192 syn::Meta::NameValue(name_value) => {
1193 if let syn::Expr::Lit(lit_expr) = &name_value.value {
1194 if let Lit::Str(lit_str) = &lit_expr.lit {
1195 return Some(lit_str.value());
1196 }
1197 }
1198
1199 None
1200 }
1201 }
1202}
1203
1204fn get_int_value_from_attribute(attr: &Attribute) -> Option<i32> {
1205 match &attr.meta {
1206 syn::Meta::Path(_) => None,
1207 syn::Meta::List(list_value) => {
1208 for token in list_value.tokens.clone().into_iter() {
1210 if let proc_macro2::TokenTree::Literal(lit) = token {
1211 if let Ok(val) = lit.to_string().parse::<i32>() {
1212 return Some(val);
1213 }
1214 }
1215 }
1216
1217 None
1218 }
1219 syn::Meta::NameValue(name_value) => {
1220 if let syn::Expr::Lit(lit_expr) = &name_value.value {
1221 if let Lit::Int(lit_int) = &lit_expr.lit {
1222 return Some(lit_int.base10_parse().expect("Not a valid int value"));
1223 }
1224 }
1225
1226 None
1227 }
1228 }
1229}
1230
1231fn get_inner_type(path: &syn::Path) -> Option<&syn::Type> {
1232 if let Some(PathArguments::AngleBracketed(args)) =
1233 path.segments.last().map(|seg| &seg.arguments)
1234 {
1235 if let Some(arg) = args.args.first() {
1236 if let syn::GenericArgument::Type(inner_type) = arg {
1237 return Some(inner_type);
1238 }
1239 }
1240 }
1241
1242 None
1243}
1244
1245fn get_two_types(path: &syn::Path) -> Option<(&syn::Type, &syn::Type)> {
1246 if let Some(PathArguments::AngleBracketed(args)) =
1247 path.segments.last().map(|seg| &seg.arguments)
1248 {
1249 let mut types = args.args.iter().filter_map(|arg| {
1250 if let syn::GenericArgument::Type(inner_type) = arg {
1251 Some(inner_type)
1252 } else {
1253 None
1254 }
1255 });
1256
1257 if let (Some(t1), Some(t2)) = (types.next(), types.next()) {
1258 return Some((t1, t2));
1259 }
1260 }
1261
1262 None
1263}
1264
1265fn generate_dynint(read: bool) -> proc_macro2::TokenStream {
1266 if read {
1267 quote! {
1268 let _p_dyn = _p_stream.read_dyn_int()?;
1269 }
1270 } else {
1271 quote! {
1272 _p_stream.write_dyn_int(_p_dyn);
1273 }
1274 }
1275}