binary_codec_derive/
lib.rs

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