binary_codec_derive/
lib.rs

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    // Parse code input (TokenStream) to AST
58    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    // Search attributes for length/toggle declarations
98    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            _ => {} // None => continue
114        }
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    // Runtime toggle_key
141    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    // Runtime length_key
150    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    // Runtime variant_key
159    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    // Compose code to handle field
168    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    // Iterate all fields in the struct
229    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        // read bytes code
247        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        // write bytes code
264        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    // Search attributes for variant_by declarations
298    for attr in ast.attrs.iter() {
299        // #[no_disc_prefix] attribute
300        if attr.path().is_ident("no_discriminator") {
301            no_disc_prefix = true;
302        }
303    }
304
305    let mut configure_functions = Vec::new();
306
307    // Create discriminant getter
308    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    // Assign discriminant values starting from 0
341    let serialization_variants = data_enum.variants.iter().enumerate().map(|(i, variant)| {
342        let var_ident = &variant.ident;
343        let disc_value = i as u8; // Could be changed to u16/u32 if needed
344        let fields = &variant.fields;
345
346        // TODO: problem might be that attrs are not used from the fields??.
347
348        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            // Single segment without arguments
525            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            // Multiple segments, or arguments
683            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                            // If toggled_by is set, read or write it
741                            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 space available, read it, write it if not None
764                            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            // #[myattribute("value")]
1043            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            // #[myattribute(value)]
1068            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}