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