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_key = None;
86 let mut length_key = None;
87 let mut toggled_by = None;
88 let mut variant_by = None;
89 let mut length_by = None;
90 let mut is_dynamic_int = false;
91 let mut has_dynamic_length = false;
92 let mut bits_count = None;
93 let mut key_dyn_length = false;
94 let mut val_dyn_length = false;
95 let mut multi_enum = false;
96
97 for attr in field.attrs.iter() {
99 let ident = attr.path().get_ident().map(|i| i.clone().to_string());
100 match ident.as_deref() {
101 Some("dyn_int") => is_dynamic_int = true,
102 Some("dyn_length") => has_dynamic_length = true,
103 Some("key_dyn_length") => key_dyn_length = true,
104 Some("val_dyn_length") => val_dyn_length = true,
105 Some("multi_enum") => multi_enum = true,
106 Some("toggles") => toggle_key = get_string_value_from_attribute(attr),
107 Some("variant_for") => variant_key = get_string_value_from_attribute(attr),
108 Some("length_for") => length_key = get_string_value_from_attribute(attr),
109 Some("toggled_by") => toggled_by = get_string_value_from_attribute(attr),
110 Some("variant_by") => variant_by = get_string_value_from_attribute(attr),
111 Some("length_by") => length_by = get_string_value_from_attribute(attr),
112 Some("bits") => bits_count = get_int_value_from_attribute(attr).map(|b| b as u8),
113 _ => {} }
115 }
116
117 let val_reference = if matches!(single_ident_type_name, Some(s) if s == String::from("RefCell"))
118 {
119 if read {
120 quote! {
121 *#field_ident.borrow()
122 }
123 } else {
124 quote! {
125 *_p_val.borrow()
126 }
127 }
128 } else {
129 if read {
130 quote! {
131 _p_val
132 }
133 } else {
134 quote! {
135 *_p_val
136 }
137 }
138 };
139
140 let toggles = if let Some(key) = toggle_key {
142 quote! {
143 _p_config.set_toggle(#key, #val_reference);
144 }
145 } else {
146 quote! {}
147 };
148
149 let length = if let Some(key) = length_key {
151 quote! {
152 _p_config.set_length(#key, #val_reference as usize);
153 }
154 } else {
155 quote! {}
156 };
157
158 let variant = if let Some(key) = variant_key {
160 quote! {
161 _p_config.set_variant(#key, #val_reference as u8);
162 }
163 } else {
164 quote! {}
165 };
166
167 let f_ident = if is_enum {
169 quote! { #field_ident }
170 } else {
171 quote! { &self.#field_ident }
172 };
173
174 let before = if read {
175 quote! {}
176 } else {
177 quote! {
178 let _p_val = #f_ident;
179 #toggles
180 #length
181 #variant
182 }
183 };
184
185 let after = if read {
186 quote! {
187 let #field_ident = _p_val;
188 #toggles
189 #length
190 #variant
191 }
192 } else {
193 quote! {}
194 };
195
196 let handle_field = generate_code_for_handling_field(
197 read,
198 field_type,
199 field_ident,
200 bits_count,
201 toggled_by,
202 variant_by,
203 length_by,
204 is_dynamic_int,
205 has_dynamic_length,
206 key_dyn_length,
207 val_dyn_length,
208 multi_enum,
209 false,
210 0
211 );
212
213 quote! {
214 #before
215 #handle_field
216 #after
217 }
218}
219
220fn generate_struct_serializer(
221 read: bool,
222 ast: &DeriveInput,
223 data_struct: &syn::DataStruct,
224) -> proc_macro::TokenStream {
225 let fields = &data_struct.fields;
226 let struct_name = &ast.ident;
227
228 let field_serializations = fields.iter().map(|field| {
230 generate_field_serializer(
231 read,
232 &field
233 .ident
234 .as_ref()
235 .expect("binary-codec does not support fields without a name"),
236 &field.ty,
237 field,
238 false
239 )
240 });
241
242 let error_type = generate_error_type(read);
243 let serializer_code = if read {
244 let vars = fields.iter().map(|f| f.ident.as_ref().unwrap());
245
246 quote! {
248 impl<T : Clone> binary_codec::BinaryDeserializer<T> for #struct_name {
249 fn deserialize_bytes(bytes: &[u8], config: Option<&mut binary_codec::SerializerConfig<T>>) -> Result<Self, #error_type> {
250 let mut _new_config = binary_codec::SerializerConfig::new(None);
251 let _p_config = config.unwrap_or(&mut _new_config);
252 let _p_bytes = bytes;
253
254 #(#field_serializations)*
255
256 Ok(Self {
257 #(#vars),*
258 })
259 }
260 }
261 }
262 } else {
263 quote! {
265 impl<T : Clone> binary_codec::BinarySerializer<T> for #struct_name {
266 fn serialize_bytes(&self, config: Option<&mut binary_codec::SerializerConfig<T>>) -> Result<Vec<u8>, #error_type> {
267 let mut bytes = Vec::new();
268 Self::write_bytes(self, &mut bytes, config)?;
269 Ok(bytes)
270 }
271
272 fn write_bytes(&self, buffer: &mut Vec<u8>, config: Option<&mut binary_codec::SerializerConfig<T>>) -> Result<(), #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_bytes = buffer;
276
277 #(#field_serializations)*
278 Ok(())
279 }
280 }
281 }
282 };
283
284 serializer_code.into()
285}
286
287fn generate_enum_serializer(
288 read: bool,
289 ast: &DeriveInput,
290 data_enum: &syn::DataEnum,
291) -> proc_macro::TokenStream {
292 let enum_name = &ast.ident;
293 let error_type = generate_error_type(read);
294
295 let mut no_disc_prefix = false;
296
297 for attr in ast.attrs.iter() {
299 if attr.path().is_ident("no_discriminator") {
301 no_disc_prefix = true;
302 }
303 }
304
305 let mut configure_functions = Vec::new();
306
307 let disc_variants = data_enum
309 .variants
310 .iter()
311 .enumerate()
312 .map(|(i, variant)| {
313 let var_ident = &variant.ident;
314 let disc_value = i as u8;
315
316 for attr in variant.attrs.iter() {
317 if attr.path().is_ident("toggled_by") {
318 let field = get_string_value_from_attribute(attr)
319 .expect("toggled_by for multi_enum should have a value");
320 configure_functions.push(quote! {
321 _p_config.configure_multi_disc(stringify!(#enum_name), #disc_value, #field);
322 });
323 }
324 }
325
326 match &variant.fields {
327 Fields::Unit => quote! {
328 Self::#var_ident => #disc_value
329 },
330 Fields::Unnamed(_) => quote! {
331 Self::#var_ident(..) => #disc_value
332 },
333 Fields::Named(_) => quote! {
334 Self::#var_ident { .. } => #disc_value
335 },
336 }
337 })
338 .collect::<Vec<_>>();
339
340 let serialization_variants = data_enum.variants.iter().enumerate().map(|(i, variant)| {
342 let var_ident = &variant.ident;
343 let disc_value = i as u8; let fields = &variant.fields;
345
346 let write_disc = if no_disc_prefix {
349 quote! {}
350 } else {
351 quote! {
352 let _p_disc: u8 = #disc_value;
353 binary_codec::fixed_int::FixedInt::write(_p_disc, _p_bytes, _p_config)?;
354 }
355 };
356
357 match fields {
358 Fields::Unit => {
359 if read {
360 quote! {
361 #disc_value => {
362 Ok(Self::#var_ident)
363 }
364 }
365 } else {
366 quote! {
367 Self::#var_ident => {
368 #write_disc
369 }
370 }
371 }
372 }
373 Fields::Unnamed(fields_unnamed) => {
374 let field_count = fields_unnamed.unnamed.len();
375 let idents: Vec<_> = (0..field_count).map(|i| format_ident!("f{}", i)).collect();
376 let ident_refs: Vec<&syn::Ident> = idents.iter().collect();
377 let field_serializations =
378 generate_enum_field_serializations(read, &ident_refs, &fields_unnamed.unnamed);
379 if read {
380 quote! {
381 #disc_value => {
382 #(#field_serializations)*
383 Ok(Self::#var_ident(#(#idents),*))
384 }
385 }
386 } else {
387 quote! {
388 Self::#var_ident(#(#idents),*) => {
389 #write_disc
390 #(#field_serializations)*
391 }
392 }
393 }
394 }
395 Fields::Named(fields_named) => {
396 let field_idents: Vec<_> = fields_named
397 .named
398 .iter()
399 .map(|f| f.ident.as_ref().unwrap())
400 .collect();
401
402 let field_serializations =
403 generate_enum_field_serializations(read, &field_idents, &fields_named.named);
404
405 if read {
406 quote! {
407 #disc_value => {
408 #(#field_serializations)*
409 Ok(Self::#var_ident { #(#field_idents),* })
410 }
411 }
412 } else {
413 quote! {
414 Self::#var_ident { #(#field_idents),* } => {
415 #write_disc
416 #(#field_serializations)*
417 }
418 }
419 }
420 }
421 }
422 });
423
424 if read {
425 quote! {
426 impl #enum_name {
427 pub fn configure_multi_disc<T : Clone>(config: &mut binary_codec::SerializerConfig<T>) {
428 let _p_config = config;
429 #(#configure_functions)*
430 }
431 }
432
433 impl<T : Clone> binary_codec::BinaryDeserializer<T> for #enum_name {
434 fn deserialize_bytes(bytes: &[u8], config: Option<&mut binary_codec::SerializerConfig<T>>) -> Result<Self, #error_type> {
435 let mut _new_config = binary_codec::SerializerConfig::new(None);
436 let _p_config = config.unwrap_or(&mut _new_config);
437 let _p_bytes = bytes;
438
439 let _p_disc = if let Some(disc) = _p_config.discriminator.take() {
440 disc
441 } else {
442 binary_codec::fixed_int::FixedInt::read(_p_bytes, _p_config)?
443 };
444
445 match _p_disc {
446 #(#serialization_variants,)*
447 _ => Err(#error_type::UnknownDiscriminant(_p_disc)),
448 }
449 }
450 }
451 }
452 .into()
453 } else {
454 quote! {
455 impl<T : Clone> binary_codec::BinarySerializer<T> for #enum_name {
456 fn serialize_bytes(&self, config: Option<&mut binary_codec::SerializerConfig<T>>) -> Result<Vec<u8>, #error_type> {
457 let mut bytes = Vec::new();
458 Self::write_bytes(self, &mut bytes, config)?;
459 Ok(bytes)
460 }
461
462 fn write_bytes(&self, buffer: &mut Vec<u8>, config: Option<&mut binary_codec::SerializerConfig<T>>) -> Result<(), #error_type> {
463 let mut _new_config = binary_codec::SerializerConfig::new(None);
464 let _p_config = config.unwrap_or(&mut _new_config);
465 #(#configure_functions)*
466 let _p_bytes = buffer;
467
468 match self {
469 #(#serialization_variants)*
470 }
471
472 Ok(())
473 }
474 }
475
476 impl #enum_name {
477 pub fn get_discriminator(&self) -> u8 {
478 match self {
479 #(#disc_variants,)*
480 }
481 }
482 }
483 }
484 .into()
485 }
486}
487
488fn generate_enum_field_serializations(
489 read: bool,
490 idents: &Vec<&syn::Ident>,
491 fields: &Punctuated<syn::Field, Comma>,
492) -> Vec<proc_macro2::TokenStream> {
493 let field_serializations = fields.iter().enumerate().map(|(i, f)| {
494 let field_type = &f.ty;
495 let field_ident = &idents[i];
496
497 generate_field_serializer(read, &field_ident, field_type, f, true)
498 });
499 field_serializations.collect()
500}
501
502fn generate_code_for_handling_field(
503 read: bool,
504 field_type: &Type,
505 field_name: &syn::Ident,
506 bits_count: Option<u8>,
507 toggled_by: Option<String>,
508 variant_by: Option<String>,
509 length_by: Option<String>,
510 is_dynamic_int: bool,
511 has_dynamic_length: bool,
512 key_dyn_length: bool,
513 val_dyn_length: bool,
514 multi_enum: bool,
515 direct_collection_child: bool,
516 level: usize,
517) -> proc_macro2::TokenStream {
518 if let Type::Path(path) = field_type {
519 let path = &path.path;
520
521 if let Some(ident) = path.get_ident() {
522 let ident_name = ident.to_string();
523
524 match ident_name.as_str() {
526 "bool" => {
527 if read {
528 quote! { let _p_val = binary_codec::dynamics::read_bool(_p_bytes, _p_config)?; }
529 } else {
530 quote! { binary_codec::dynamics::write_bool(*_p_val, _p_bytes, _p_config)?; }
531 }
532 }
533 "i8" => {
534 if let Some(bits_count) = bits_count.as_ref() {
535 if *bits_count < 1 || *bits_count > 7 {
536 panic!("Bits count should be between 1 and 7");
537 }
538
539 if read {
540 quote! { let _p_val = binary_codec::dynamics::read_small_dynamic_signed(_p_bytes, _p_config, #bits_count)?; }
541 } else {
542 quote! { binary_codec::dynamics::write_small_dynamic_signed(*_p_val, _p_bytes, _p_config, #bits_count)?; }
543 }
544 } else {
545 if read {
546 quote! {
547 let _p_val = binary_codec::dynamics::read_zigzag(_p_bytes, _p_config)?;
548 }
549 } else {
550 quote! {
551 binary_codec::dynamics::write_zigzag(*_p_val, _p_bytes, _p_config)?;
552 }
553 }
554 }
555 }
556 "u8" => {
557 if let Some(bits_count) = bits_count.as_ref() {
558 if *bits_count < 1 || *bits_count > 7 {
559 panic!("Bits count should be between 1 and 7");
560 }
561
562 if read {
563 quote! { let _p_val = binary_codec::dynamics::read_small_dynamic_unsigned(_p_bytes, _p_config, #bits_count)?; }
564 } else {
565 quote! { binary_codec::dynamics::write_small_dynamic_unsigned(*_p_val, _p_bytes, _p_config, #bits_count)?; }
566 }
567 } else {
568 if read {
569 quote! {
570 let _p_val = binary_codec::fixed_int::FixedInt::read(_p_bytes, _p_config)?;
571 }
572 } else {
573 quote! {
574 binary_codec::fixed_int::FixedInt::write(*_p_val, _p_bytes, _p_config)?;
575 }
576 }
577 }
578 }
579 "u16" | "u32" | "u64" | "u128" => {
580 if is_dynamic_int {
581 let dynint: proc_macro2::TokenStream = generate_dynint(read);
582 if read {
583 quote! {
584 #dynint
585 let _p_val = _p_dyn as #ident;
586 }
587 } else {
588 quote! {
589 let _p_dyn = *_p_val as u128;
590 #dynint
591 }
592 }
593 } else {
594 if read {
595 quote! {
596 let _p_val = binary_codec::fixed_int::FixedInt::read(_p_bytes, _p_config)?;
597 }
598 } else {
599 quote! {
600 binary_codec::fixed_int::FixedInt::write(*_p_val, _p_bytes, _p_config)?;
601 }
602 }
603 }
604 }
605 "i16" | "i32" | "i64" | "i128" => {
606 if is_dynamic_int {
607 let dynint: proc_macro2::TokenStream = generate_dynint(read);
608 if read {
609 quote! {
610 #dynint
611 let _p_val: #ident = binary_codec::fixed_int::ZigZag::to_signed(_p_dyn);
612 }
613 } else {
614 quote! {
615 let _p_dyn = binary_codec::fixed_int::ZigZag::to_unsigned(*_p_val) as u128;
616 #dynint
617 }
618 }
619 } else {
620 if read {
621 quote! {
622 let _p_val = binary_codec::fixed_int::read_zigzag(_p_bytes, _p_config)?;
623 }
624 } else {
625 quote! {
626 binary_codec::fixed_int::write_zigzag(*_p_val, _p_bytes, _p_config)?;
627 }
628 }
629 }
630 }
631 "String" => {
632 let size_key = generate_size_key(length_by, has_dynamic_length).1;
633
634 if read {
635 quote! {
636 let _p_val = binary_codec::variable::read_string(_p_bytes, #size_key, _p_config)?;
637 }
638 } else {
639 quote! {
640 binary_codec::variable::write_string(_p_val, #size_key, _p_bytes, _p_config)?;
641 }
642 }
643 }
644 _ => {
645 let size_key = generate_size_key(length_by, has_dynamic_length).1;
646
647 let variant_code = if variant_by.is_some() {
648 quote! {
649 _p_config.discriminator = _p_config.get_variant(#variant_by);
650 }
651 } else if multi_enum {
652 let config_multi = if !direct_collection_child {
653 quote! { #ident::configure_multi_disc(_p_config); }
654 } else {
655 quote! {}
656 };
657
658 quote! {
659 #config_multi
660 _p_config.discriminator = _p_config.get_next_multi_disc(stringify!(#field_name), #ident_name);
661 }
662 } else {
663 quote! {
664 _p_config.discriminator = None;
665 }
666 };
667
668 if read {
669 quote! {
670 #variant_code
671 let _p_val = binary_codec::variable::read_object(_p_bytes, #size_key, _p_config)?;
672 }
673 } else {
674 quote! {
675 #variant_code
676 binary_codec::variable::write_object(_p_val, #size_key, _p_bytes, _p_config)?;
677 }
678 }
679 }
680 }
681 } else {
682 if path.segments.len() == 1 {
684 let ident = &path.segments[0].ident;
685 let ident_name = ident.to_string();
686
687 match ident_name.as_ref() {
688 "RefCell" => {
689 let inner_type = get_inner_type(path).expect("Option missing inner type");
690 let handle = generate_code_for_handling_field(
691 read,
692 inner_type,
693 field_name,
694 bits_count,
695 None,
696 variant_by,
697 length_by,
698 is_dynamic_int,
699 has_dynamic_length,
700 key_dyn_length,
701 val_dyn_length,
702 multi_enum,
703 false,
704 level + 1,
705 );
706
707 if read {
708 quote! {
709 #handle
710 let _p_val = RefCell::new(_p_val);
711 }
712 } else {
713 quote! {
714 let _p_val = &*_p_val.borrow();
715 #handle
716 }
717 }
718 }
719 "Option" => {
720 let inner_type = get_inner_type(path).expect("Option missing inner type");
721 let handle = generate_code_for_handling_field(
722 read,
723 inner_type,
724 field_name,
725 bits_count,
726 None,
727 variant_by,
728 length_by,
729 is_dynamic_int,
730 has_dynamic_length,
731 key_dyn_length,
732 val_dyn_length,
733 multi_enum,
734 false,
735 level + 1,
736 );
737 let option_name: syn::Ident = format_ident!("__option_{}", level);
738
739 if let Some(toggled_by) = toggled_by {
740 let toggled_by = quote! {
742 _p_config.get_toggle(#toggled_by).unwrap_or(false)
743 };
744
745 if read {
746 quote! {
747 let mut #option_name: Option<#inner_type> = None;
748 if #toggled_by {
749 #handle
750 #option_name = Some(_p_val);
751 }
752 let _p_val = #option_name;
753 }
754 } else {
755 quote! {
756 if #toggled_by {
757 let _p_val = _p_val.as_ref().expect("Expected Some value, because toggled_by field is true");
758 #handle
759 }
760 }
761 }
762 } else {
763 if read {
765 quote! {
766 let mut #option_name: Option<#inner_type> = None;
767 if _p_config.next_reset_bits_pos() < _p_bytes.len() {
768 #handle
769 #option_name = Some(_p_val);
770 }
771 let _p_val = #option_name;
772 }
773 } else {
774 quote! {
775 if let Some(_p_val) = _p_val.as_ref() {
776 #handle
777 }
778 }
779 }
780 }
781 }
782 "Vec" => {
783 let vec_name = format_ident!("__val_{}", level);
784 let inner_type = get_inner_type(path).expect("Vec missing inner type");
785
786 let handle = generate_code_for_handling_field(
787 read,
788 inner_type,
789 field_name,
790 bits_count,
791 None,
792 None,
793 None,
794 is_dynamic_int,
795 val_dyn_length,
796 false,
797 false,
798 multi_enum,
799 true,
800 level + 1,
801 );
802
803 let (has_size, size_key) = generate_size_key(length_by, has_dynamic_length);
804
805 let write_code = quote! {
806 for _p_val in _p_val {
807 #handle
808 }
809 };
810
811 if has_size || (read && multi_enum) {
812 if read {
813 let len_code = if multi_enum && let Type::Path(path) = inner_type {
814 let enum_ident = path
815 .path
816 .get_ident()
817 .expect("Expected ident for multi_enum inner type");
818 quote! {
819 #enum_ident::configure_multi_disc(_p_config);
820 let _p_len = _p_config.get_multi_disc_size(stringify!(#enum_ident));
821 }
822 } else {
823 quote! {
824 let _p_len = binary_codec::utils::get_read_size(_p_bytes, #size_key, _p_config)?;
825 }
826 };
827
828 quote! {
829 #len_code
830 let mut #vec_name = Vec::<#inner_type>::with_capacity(_p_len);
831 for _ in 0.._p_len {
832 #handle
833 #vec_name.push(_p_val);
834 }
835 let _p_val = #vec_name;
836 }
837 } else {
838 quote! {
839 let _p_len = _p_val.len();
840 binary_codec::utils::write_size(_p_len, #size_key, _p_bytes, _p_config)?;
841 #write_code
842 }
843 }
844 } else {
845 if read {
846 quote! {
847 let mut #vec_name = Vec::<#inner_type>::new();
848 while _p_config.next_reset_bits_pos() < _p_bytes.len() {
849 #handle
850 #vec_name.push(_p_val);
851 }
852 let _p_val = #vec_name;
853 }
854 } else {
855 quote! {
856 #write_code
857 }
858 }
859 }
860 }
861 "HashMap" => {
862 let (key_type, value_type) =
863 get_two_types(path).expect("Failed to get HashMap types");
864
865 let handle_key = generate_code_for_handling_field(
866 read,
867 key_type,
868 field_name,
869 None,
870 None,
871 None,
872 None,
873 is_dynamic_int,
874 key_dyn_length,
875 false,
876 false,
877 false,
878 false,
879 level + 1,
880 );
881
882 let handle_value = generate_code_for_handling_field(
883 read,
884 value_type,
885 field_name,
886 None,
887 None,
888 None,
889 None,
890 is_dynamic_int,
891 val_dyn_length,
892 false,
893 false,
894 false,
895 false,
896 level + 1,
897 );
898
899 let (has_size, size_key) = generate_size_key(length_by, has_dynamic_length);
900
901 let write_code = quote! {
902 for (key, value) in _p_val {
903 let _p_val = key;
904 #handle_key
905 let _p_val = value;
906 #handle_value
907 }
908 };
909
910 if read {
911 if has_size {
912 quote! {
913 let _p_len = binary_codec::utils::get_read_size(_p_bytes, #size_key, _p_config)?;
914 let mut _p_map = std::collections::HashMap::<#key_type, #value_type>::with_capacity(_p_len);
915 for _ in 0.._p_len {
916 let _p_key;
917 #handle_key
918 _p_key = _p_val;
919 let _p_value;
920 #handle_value
921 _p_value = _p_val;
922 _p_map.insert(_p_key, _p_value);
923 }
924 let _p_val = _p_map;
925 }
926 } else {
927 quote! {
928 let mut _p_map = std::collections::HashMap::<#key_type, #value_type>::new();
929 while _p_config.next_reset_bits_pos() < _p_bytes.len() {
930 let _p_key;
931 #handle_key
932 _p_key = _p_val;
933 let _p_value;
934 #handle_value
935 _p_value = _p_val;
936 _p_map.insert(_p_key, _p_value);
937 }
938 let _p_val = _p_map;
939 }
940 }
941 } else {
942 if has_size {
943 quote! {
944 let _p_len = _p_val.len();
945 binary_codec::utils::write_size(_p_len, #size_key, _p_bytes, _p_config)?;
946 #write_code
947 }
948 } else {
949 quote! {
950 #write_code
951 }
952 }
953 }
954 }
955 _ => {
956 panic!("Type not implemented")
957 }
958 }
959 } else {
960 panic!("Multi-segment paths are not supported");
961 }
962 }
963 } else if let Type::Array(array) = field_type {
964 let len: usize = if let syn::Expr::Lit(ref arr_len_lit) = array.len {
965 if let Lit::Int(ref lit_int) = arr_len_lit.lit {
966 lit_int
967 .base10_parse()
968 .expect("Failed to parse literal to usize")
969 } else {
970 panic!("Expected an int to determine array length");
971 }
972 } else {
973 panic!("Expected literal to determine array length");
974 };
975
976 let array_type = &array.elem;
977 let handle = generate_code_for_handling_field(
978 read,
979 array_type,
980 field_name,
981 bits_count,
982 None,
983 None,
984 None,
985 is_dynamic_int,
986 val_dyn_length,
987 false,
988 false,
989 false,
990 true,
991 level + 1,
992 );
993
994 let array_name = format_ident!("__val_{}", level);
995
996 if read {
997 quote! {
998 let mut #array_name = Vec::<#array_type>::with_capacity(#len);
999 for _ in 0..#len {
1000 #handle;
1001 #array_name.push(_p_val);
1002 }
1003 let _p_val = TryInto::<[#array_type; #len]>::try_into(#array_name).expect("Failed to convert Vec to array");
1004 }
1005 } else {
1006 quote! {
1007 for _p_val in _p_val {
1008 #handle
1009 }
1010 }
1011 }
1012 } else {
1013 panic!("Field type of '{:?}' not supported", field_name);
1014 }
1015}
1016
1017fn generate_error_type(read: bool) -> proc_macro2::TokenStream {
1018 if read {
1019 quote! { binary_codec::DeserializationError }
1020 } else {
1021 quote! { binary_codec::SerializationError }
1022 }
1023}
1024
1025fn generate_size_key(
1026 length_by: Option<String>,
1027 has_dynamic_length: bool,
1028) -> (bool, proc_macro2::TokenStream) {
1029 if let Some(length_by) = length_by.as_ref() {
1030 (true, quote! { Some(#length_by) })
1031 } else if has_dynamic_length {
1032 (true, quote! { Some("__dynamic") })
1033 } else {
1034 (false, quote! { None })
1035 }
1036}
1037
1038fn get_string_value_from_attribute(attr: &Attribute) -> Option<String> {
1039 match &attr.meta {
1040 syn::Meta::Path(_) => None,
1041 syn::Meta::List(list_value) => {
1042 for token in list_value.tokens.clone().into_iter() {
1044 if let proc_macro2::TokenTree::Literal(lit) = token {
1045 return Some(lit.to_string().trim_matches('"').to_string());
1046 }
1047 }
1048
1049 None
1050 }
1051 syn::Meta::NameValue(name_value) => {
1052 if let syn::Expr::Lit(lit_expr) = &name_value.value {
1053 if let Lit::Str(lit_str) = &lit_expr.lit {
1054 return Some(lit_str.value());
1055 }
1056 }
1057
1058 None
1059 }
1060 }
1061}
1062
1063fn get_int_value_from_attribute(attr: &Attribute) -> Option<i32> {
1064 match &attr.meta {
1065 syn::Meta::Path(_) => None,
1066 syn::Meta::List(list_value) => {
1067 for token in list_value.tokens.clone().into_iter() {
1069 if let proc_macro2::TokenTree::Literal(lit) = token {
1070 if let Ok(val) = lit.to_string().parse::<i32>() {
1071 return Some(val);
1072 }
1073 }
1074 }
1075
1076 None
1077 }
1078 syn::Meta::NameValue(name_value) => {
1079 if let syn::Expr::Lit(lit_expr) = &name_value.value {
1080 if let Lit::Int(lit_int) = &lit_expr.lit {
1081 return Some(lit_int.base10_parse().expect("Not a valid int value"));
1082 }
1083 }
1084
1085 None
1086 }
1087 }
1088}
1089
1090fn get_inner_type(path: &syn::Path) -> Option<&syn::Type> {
1091 if let Some(PathArguments::AngleBracketed(args)) =
1092 path.segments.last().map(|seg| &seg.arguments)
1093 {
1094 if let Some(arg) = args.args.first() {
1095 if let syn::GenericArgument::Type(inner_type) = arg {
1096 return Some(inner_type);
1097 }
1098 }
1099 }
1100
1101 None
1102}
1103
1104fn get_two_types(path: &syn::Path) -> Option<(&syn::Type, &syn::Type)> {
1105 if let Some(PathArguments::AngleBracketed(args)) =
1106 path.segments.last().map(|seg| &seg.arguments)
1107 {
1108 let mut types = args.args.iter().filter_map(|arg| {
1109 if let syn::GenericArgument::Type(inner_type) = arg {
1110 Some(inner_type)
1111 } else {
1112 None
1113 }
1114 });
1115
1116 if let (Some(t1), Some(t2)) = (types.next(), types.next()) {
1117 return Some((t1, t2));
1118 }
1119 }
1120
1121 None
1122}
1123
1124fn generate_dynint(read: bool) -> proc_macro2::TokenStream {
1125 if read {
1126 quote! {
1127 let _p_dyn = binary_codec::dyn_int::read_dynint(_p_bytes, _p_config)?;
1128 }
1129 } else {
1130 quote! {
1131 binary_codec::dyn_int::write_dynint(_p_dyn, _p_bytes, _p_config)?;
1132 }
1133 }
1134}