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 read_bytes(
250                        stream: &mut binary_codec::BitStreamReader,
251                        config: Option<&mut binary_codec::SerializerConfig<T>>,
252                    ) -> Result<Self, #error_type> {
253                        let mut _new_config = binary_codec::SerializerConfig::new(None);
254                        let _p_config = config.unwrap_or(&mut _new_config);
255                        let _p_stream = stream;
256
257                        #(#field_serializations)*
258
259                        Ok(Self {
260                            #(#vars),*
261                        })
262                    }
263                }
264            }
265    } else {
266        // write bytes code
267        quote! {
268            impl<T : Clone> binary_codec::BinarySerializer<T> for #struct_name {
269                fn write_bytes(
270                    &self,
271                    stream: &mut binary_codec::BitStreamWriter,
272                    config: Option<&mut binary_codec::SerializerConfig<T>>,
273                ) -> Result<(), #error_type> {
274                    let mut _new_config = binary_codec::SerializerConfig::new(None);
275                    let _p_config = config.unwrap_or(&mut _new_config);
276                    let _p_stream = stream;
277
278                    #(#field_serializations)*
279                    Ok(())
280                }
281            }
282        }
283    };
284
285    serializer_code.into()
286}
287
288fn generate_enum_serializer(
289    read: bool,
290    ast: &DeriveInput,
291    data_enum: &syn::DataEnum,
292) -> proc_macro::TokenStream {
293    let enum_name = &ast.ident;
294    let error_type = generate_error_type(read);
295
296    let mut no_disc_prefix = false;
297
298    // Search attributes for variant_by declarations
299    for attr in ast.attrs.iter() {
300        // #[no_disc_prefix] attribute
301        if attr.path().is_ident("no_discriminator") {
302            no_disc_prefix = true;
303        }
304    }
305
306    let mut configure_functions = Vec::new();
307
308    // Create discriminant getter
309    let disc_variants = data_enum
310        .variants
311        .iter()
312        .enumerate()
313        .map(|(i, variant)| {
314            let var_ident = &variant.ident;
315            let disc_value = i as u8;
316
317            for attr in variant.attrs.iter() {
318                if attr.path().is_ident("toggled_by") {
319                    let field = get_string_value_from_attribute(attr)
320                        .expect("toggled_by for multi_enum should have a value");
321                    configure_functions.push(quote! {
322                        _p_config.configure_multi_disc(stringify!(#enum_name), #disc_value, #field);
323                    });
324                }
325            }
326
327            match &variant.fields {
328                Fields::Unit => quote! {
329                    Self::#var_ident => #disc_value
330                },
331                Fields::Unnamed(_) => quote! {
332                    Self::#var_ident(..) => #disc_value
333                },
334                Fields::Named(_) => quote! {
335                    Self::#var_ident { .. } => #disc_value
336                },
337            }
338        })
339        .collect::<Vec<_>>();
340
341    // Assign discriminant values starting from 0
342    let serialization_variants = data_enum.variants.iter().enumerate().map(|(i, variant)| {
343        let var_ident = &variant.ident;
344        let disc_value = i as u8; // Could be changed to u16/u32 if needed
345        let fields = &variant.fields;
346
347        // TODO: problem might be that attrs are not used from the fields??.
348
349        let write_disc = if no_disc_prefix {
350            quote! {}
351        } else {
352            quote! {
353                let _p_disc: u8 = #disc_value;
354                _p_stream.write_fixed_int(_p_disc);
355            }
356        };
357
358        match fields {
359            Fields::Unit => {
360                if read {
361                    quote! {
362                        #disc_value => {
363                            Ok(Self::#var_ident)
364                        }
365                    }
366                } else {
367                    quote! {
368                        Self::#var_ident => {
369                            #write_disc
370                        }
371                    }
372                }
373            }
374            Fields::Unnamed(fields_unnamed) => {
375                let field_count = fields_unnamed.unnamed.len();
376                let idents: Vec<_> = (0..field_count).map(|i| format_ident!("f{}", i)).collect();
377                let ident_refs: Vec<&syn::Ident> = idents.iter().collect();
378                let field_serializations =
379                    generate_enum_field_serializations(read, &ident_refs, &fields_unnamed.unnamed);
380                if read {
381                    quote! {
382                        #disc_value => {
383                            #(#field_serializations)*
384                            Ok(Self::#var_ident(#(#idents),*))
385                        }
386                    }
387                } else {
388                    quote! {
389                        Self::#var_ident(#(#idents),*) => {
390                            #write_disc
391                            #(#field_serializations)*
392                        }
393                    }
394                }
395            }
396            Fields::Named(fields_named) => {
397                let field_idents: Vec<_> = fields_named
398                    .named
399                    .iter()
400                    .map(|f| f.ident.as_ref().unwrap())
401                    .collect();
402
403                let field_serializations =
404                    generate_enum_field_serializations(read, &field_idents, &fields_named.named);
405
406                if read {
407                    quote! {
408                        #disc_value => {
409                            #(#field_serializations)*
410                            Ok(Self::#var_ident { #(#field_idents),* })
411                        }
412                    }
413                } else {
414                    quote! {
415                        Self::#var_ident { #(#field_idents),* } => {
416                            #write_disc
417                            #(#field_serializations)*
418                        }
419                    }
420                }
421            }
422        }
423    });
424
425    if read {
426        quote! {
427            impl #enum_name {
428                pub fn configure_multi_disc<T : Clone>(config: &mut binary_codec::SerializerConfig<T>) {
429                    let _p_config = config;
430                    #(#configure_functions)*
431                }
432            }
433
434            impl<T : Clone> binary_codec::BinaryDeserializer<T> for #enum_name {
435                fn read_bytes(
436                    stream: &mut binary_codec::BitStreamReader,
437                    config: Option<&mut binary_codec::SerializerConfig<T>>,
438                ) -> Result<Self, #error_type> {
439                    let mut _new_config = binary_codec::SerializerConfig::new(None);
440                    let _p_config = config.unwrap_or(&mut _new_config);
441                    let _p_stream = stream;
442
443                    let _p_disc = if let Some(disc) = _p_config.discriminator.take() {
444                        disc
445                    } else {
446                        _p_stream.read_fixed_int()?
447                    };
448
449                    match _p_disc {
450                        #(#serialization_variants,)*
451                        _ => Err(#error_type::UnknownDiscriminant(_p_disc)),
452                    }
453                }
454            }
455        }
456        .into()
457    } else {
458        quote! {
459            impl<T : Clone> binary_codec::BinarySerializer<T> for #enum_name {
460                fn write_bytes(
461                    &self,
462                    stream: &mut binary_codec::BitStreamWriter,
463                    config: Option<&mut binary_codec::SerializerConfig<T>>,
464                ) -> Result<(), #error_type> {
465                    let mut _new_config = binary_codec::SerializerConfig::new(None);
466                    let _p_config = config.unwrap_or(&mut _new_config);
467                    #(#configure_functions)*
468                    let _p_stream = stream;
469
470                    match self {
471                        #(#serialization_variants)*
472                    }
473
474                    Ok(())
475                }
476            }
477
478            impl #enum_name {
479                pub fn get_discriminator(&self) -> u8 {
480                    match self {
481                        #(#disc_variants,)*
482                    }
483                }
484            }
485        }
486        .into()
487    }
488}
489
490fn generate_enum_field_serializations(
491    read: bool,
492    idents: &Vec<&syn::Ident>,
493    fields: &Punctuated<syn::Field, Comma>,
494) -> Vec<proc_macro2::TokenStream> {
495    let field_serializations = fields.iter().enumerate().map(|(i, f)| {
496        let field_type = &f.ty;
497        let field_ident = &idents[i];
498
499        generate_field_serializer(read, &field_ident, field_type, f, true)
500    });
501    field_serializations.collect()
502}
503
504fn generate_code_for_handling_field(
505    read: bool,
506    field_type: &Type,
507    field_name: &syn::Ident,
508    bits_count: Option<u8>,
509    toggled_by: Option<String>,
510    variant_by: Option<String>,
511    length_by: Option<String>,
512    is_dynamic_int: bool,
513    has_dynamic_length: bool,
514    key_dyn_length: bool,
515    val_dyn_length: bool,
516    multi_enum: bool,
517    direct_collection_child: bool,
518    level: usize,
519) -> proc_macro2::TokenStream {
520    if let Type::Path(path) = field_type {
521        let path = &path.path;
522
523        if let Some(ident) = path.get_ident() {
524            let ident_name = ident.to_string();
525
526            // Single segment without arguments
527            match ident_name.as_str() {
528                "bool" => {
529                    if read {
530                        quote! { let _p_val = _p_stream.read_bit()?;}
531                    } else {
532                        quote! { _p_stream.write_bit(*_p_val); }
533                    }
534                }
535                "i8" => {
536                    if let Some(bits_count) = bits_count.as_ref() {
537                        if *bits_count < 1 || *bits_count > 7 {
538                            panic!("Bits count should be between 1 and 7");
539                        }
540
541                        if read {
542                            quote! { let _p_val = binary_codec::ZigZag::to_signed(_p_stream.read_small(#bits_count)?); }
543                        } else {
544                            quote! { _p_stream.write_small(binary_codec::ZigZag::to_unsigned(*_p_val), #bits_count); }
545                        }
546                    } else {
547                        if read {
548                            quote! { let _p_val = _p_stream.read_fixed_int()?; }
549                        } else {
550                            quote! { _p_stream.write_fixed_int(*_p_val); }
551                        }
552                    }
553                }
554                "u8" => {
555                    if let Some(bits_count) = bits_count.as_ref() {
556                        if *bits_count < 1 || *bits_count > 7 {
557                            panic!("Bits count should be between 1 and 7");
558                        }
559
560                        if read {
561                            quote! { let _p_val = _p_stream.read_small(#bits_count)?; }
562                        } else {
563                            quote! { _p_stream.write_small(*_p_val, #bits_count); }
564                        }
565                    } else {
566                        if read {
567                            quote! { let _p_val = _p_stream.read_byte()?; }
568                        } else {
569                            quote! { _p_stream.write_byte(*_p_val); }
570                        }
571                    }
572                }
573                "u16" | "u32" | "u64" | "u128" => {
574                    if is_dynamic_int {
575                        let dynint: proc_macro2::TokenStream = generate_dynint(read);
576                        if read {
577                            quote! {
578                                #dynint
579                                let _p_val = _p_dyn as #ident;
580                            }
581                        } else {
582                            quote! {
583                                let _p_dyn = *_p_val as u128;
584                                #dynint
585                            }
586                        }
587                    } else {
588                        if read {
589                            quote! { let _p_val = _p_stream.read_fixed_int()?; }
590                        } else {
591                            quote! { _p_stream.write_fixed_int(*_p_val); }
592                        }
593                    }
594                }
595                "i16" | "i32" | "i64" | "i128" => {
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: #ident = binary_codec::ZigZag::to_signed(_p_dyn);
602                            }
603                        } else {
604                            quote! {
605                                let _p_dyn = binary_codec::ZigZag::to_unsigned(*_p_val) as u128;
606                                #dynint
607                            }
608                        }
609                    } else {
610                        if read {
611                            quote! { let _p_val = _p_stream.read_fixed_int()?; }
612                        } else {
613                            quote! { _p_stream.write_fixed_int(*_p_val); }
614                        }
615                    }
616                }
617                "String" => {
618                    let size_key = generate_size_key(length_by, has_dynamic_length).1;
619
620                    if read {
621                        quote! {
622                            let _p_val = binary_codec::utils::read_string(_p_stream, #size_key, _p_config)?;
623                        }
624                    } else {
625                        quote! {
626                            binary_codec::utils::write_string(_p_val, #size_key, _p_stream, _p_config)?;
627                        }
628                    }
629                }
630                _ => {
631                    let size_key = generate_size_key(length_by, has_dynamic_length).1;
632
633                    let variant_code = if variant_by.is_some() {
634                        quote! {
635                            _p_config.discriminator = _p_config.get_variant(#variant_by);
636                        }
637                    } else if multi_enum {
638                        let config_multi = if !direct_collection_child {
639                            quote! { #ident::configure_multi_disc(_p_config); }
640                        } else {
641                            quote! {}
642                        };
643
644                        quote! {
645                            #config_multi
646                            _p_config.discriminator = _p_config.get_next_multi_disc(stringify!(#field_name), #ident_name);
647                        }
648                    } else {
649                        quote! {
650                            _p_config.discriminator = None;
651                        }
652                    };
653
654                    if read {
655                        quote! {
656                            #variant_code
657                            let _p_val = binary_codec::utils::read_object(_p_stream, #size_key, _p_config)?;
658                        }
659                    } else {
660                        quote! {
661                            #variant_code
662                            binary_codec::utils::write_object(_p_val, #size_key, _p_stream, _p_config)?;
663                        }
664                    }
665                }
666            }
667        } else {
668            // Multiple segments, or arguments
669            if path.segments.len() == 1 {
670                let ident = &path.segments[0].ident;
671                let ident_name = ident.to_string();
672
673                match ident_name.as_ref() {
674                    "RefCell" => {
675                        let inner_type = get_inner_type(path).expect("Option missing inner type");
676                        let handle = generate_code_for_handling_field(
677                            read,
678                            inner_type,
679                            field_name,
680                            bits_count,
681                            None,
682                            variant_by,
683                            length_by,
684                            is_dynamic_int,
685                            has_dynamic_length,
686                            key_dyn_length,
687                            val_dyn_length,
688                            multi_enum,
689                            false,
690                            level + 1,
691                        );
692
693                        if read {
694                            quote! {
695                                #handle
696                                let _p_val = RefCell::new(_p_val);
697                            }
698                        } else {
699                            quote! {
700                                let _p_val = &*_p_val.borrow();
701                                #handle
702                            }
703                        }
704                    }
705                    "Option" => {
706                        let inner_type = get_inner_type(path).expect("Option missing inner type");
707                        let handle = generate_code_for_handling_field(
708                            read,
709                            inner_type,
710                            field_name,
711                            bits_count,
712                            None,
713                            variant_by,
714                            length_by,
715                            is_dynamic_int,
716                            has_dynamic_length,
717                            key_dyn_length,
718                            val_dyn_length,
719                            multi_enum,
720                            false,
721                            level + 1,
722                        );
723                        let option_name: syn::Ident = format_ident!("__option_{}", level);
724
725                        if let Some(toggled_by) = toggled_by {
726                            // If toggled_by is set, read or write it
727                            let toggled_by = quote! {
728                                _p_config.get_toggle(#toggled_by).unwrap_or(false)
729                            };
730
731                            if read {
732                                quote! {
733                                    let mut #option_name: Option<#inner_type> = None;
734                                    if #toggled_by {
735                                        #handle
736                                        #option_name = Some(_p_val);
737                                    }
738                                    let _p_val = #option_name;
739                                }
740                            } else {
741                                quote! {
742                                    if #toggled_by {
743                                        let _p_val = _p_val.as_ref().expect("Expected Some value, because toggled_by field is true");
744                                        #handle
745                                    }
746                                }
747                            }
748                        } else {
749                            // If space available, read it, write it if not None
750                            if read {
751                                quote! {
752                                    let mut #option_name: Option<#inner_type> = None;
753                                    if _p_stream.bytes_left() > 0 {
754                                        #handle
755                                        #option_name = Some(_p_val);
756                                    }
757                                    let _p_val = #option_name;
758                                }
759                            } else {
760                                quote! {
761                                    if let Some(_p_val) = _p_val.as_ref() {
762                                        #handle
763                                    }
764                                }
765                            }
766                        }
767                    }
768                    "Vec" => {
769                        let vec_name = format_ident!("__val_{}", level);
770                        let inner_type = get_inner_type(path).expect("Vec missing inner type");
771
772                        // If inner type is u8, optimize to bulk read/write bytes
773                        if let Type::Path(inner_path) = inner_type {
774                            if let Some(inner_ident) = inner_path.path.get_ident() {
775                                if inner_ident == "u8" {
776                                    let (has_size, size_key) = generate_size_key(length_by, has_dynamic_length);
777
778                                    if read {
779                                        if has_size || multi_enum {
780                                            // sized read
781                                            let len_code = if multi_enum {
782                                                quote! {
783                                                    // multi_enum sized Vec<u8>
784                                                    let _p_len = _p_config.get_multi_disc_size("u8");
785                                                }
786                                            } else {
787                                                quote! {
788                                                    let _p_len = binary_codec::utils::get_read_size(_p_stream, #size_key, _p_config)?;
789                                                }
790                                            };
791
792                                            quote! {
793                                                #len_code
794                                                let _p_val = _p_stream.read_bytes(_p_len)?.to_vec();
795                                            }
796                                        } else {
797                                            // read all remaining bytes
798                                            quote! {
799                                                let _p_len = _p_stream.bytes_left();
800                                                let _p_val = _p_stream.read_bytes(_p_len)?.to_vec();
801                                            }
802                                        }
803                                    } else {
804                                        // write path: if sized, write size first
805                                        let write_size = if has_size {
806                                            quote! {
807                                                let _p_len = _p_val.len();
808                                                binary_codec::utils::write_size(_p_len, #size_key, _p_stream, _p_config)?;
809                                            }
810                                        } else {
811                                            quote! {}
812                                        };
813
814                                        quote! {
815                                            #write_size
816                                            _p_stream.write_bytes(&_p_val);
817                                        }
818                                    }
819                                } else {
820                                    // Fallback to element-wise handling for non-u8 inner types
821                                    let handle = generate_code_for_handling_field(
822                                        read,
823                                        inner_type,
824                                        field_name,
825                                        bits_count,
826                                        None,
827                                        None,
828                                        None,
829                                        is_dynamic_int,
830                                        val_dyn_length,
831                                        false,
832                                        false,
833                                        multi_enum,
834                                        true,
835                                        level + 1,
836                                    );
837
838                                    let (has_size, size_key) = generate_size_key(length_by, has_dynamic_length);
839
840                                    let write_code = quote! {
841                                        for _p_val in _p_val {
842                                            #handle
843                                        }
844                                    };
845
846                                    if has_size || (read && multi_enum) {
847                                        if read {
848                                            let len_code = if multi_enum && let Type::Path(path) = inner_type {
849                                                let enum_ident = path
850                                                    .path
851                                                    .get_ident()
852                                                    .expect("Expected ident for multi_enum inner type");
853                                                quote! {
854                                                    #enum_ident::configure_multi_disc(_p_config);
855                                                    let _p_len = _p_config.get_multi_disc_size(stringify!(#enum_ident));
856                                                }
857                                            } else {
858                                                quote! {
859                                                    let _p_len = binary_codec::utils::get_read_size(_p_stream, #size_key, _p_config)?;
860                                                }
861                                            };
862
863                                            quote! {
864                                                #len_code
865                                                let mut #vec_name = Vec::<#inner_type>::with_capacity(_p_len);
866                                                for _ in 0.._p_len {
867                                                    #handle
868                                                    #vec_name.push(_p_val);
869                                                }
870                                                let _p_val = #vec_name;
871                                            }
872                                        } else {
873                                            quote! {
874                                                let _p_len = _p_val.len();
875                                                binary_codec::utils::write_size(_p_len, #size_key, _p_stream, _p_config)?;
876                                                #write_code
877                                            }
878                                        }
879                                    } else {
880                                        if read {
881                                            quote! {
882                                                let mut #vec_name = Vec::<#inner_type>::new();
883                                                while _p_stream.bytes_left() > 0 {
884                                                    #handle
885                                                    #vec_name.push(_p_val);
886                                                }
887                                                let _p_val = #vec_name;
888                                            }
889                                        } else {
890                                            quote! {
891                                                #write_code
892                                            }
893                                        }
894                                    }
895                                }
896                            } else {
897                                panic!("Unsupported inner type for Vec");
898                            }
899                        } else {
900                            panic!("Unsupported inner type for Vec");
901                        }
902                    }
903                    "HashMap" => {
904                        let (key_type, value_type) =
905                            get_two_types(path).expect("Failed to get HashMap types");
906
907                        let handle_key = generate_code_for_handling_field(
908                            read,
909                            key_type,
910                            field_name,
911                            None,
912                            None,
913                            None,
914                            None,
915                            is_dynamic_int,
916                            key_dyn_length,
917                            false,
918                            false,
919                            false,
920                            false,
921                            level + 1,
922                        );
923
924                        let handle_value = generate_code_for_handling_field(
925                            read,
926                            value_type,
927                            field_name,
928                            None,
929                            None,
930                            None,
931                            None,
932                            is_dynamic_int,
933                            val_dyn_length,
934                            false,
935                            false,
936                            false,
937                            false,
938                            level + 1,
939                        );
940
941                        let (has_size, size_key) = generate_size_key(length_by, has_dynamic_length);
942
943                        let write_code = quote! {
944                            for (key, value) in _p_val {
945                                let _p_val = key;
946                                #handle_key
947                                let _p_val = value;
948                                #handle_value
949                            }
950                        };
951
952                        if read {
953                            if has_size {
954                                quote! {
955                                    let _p_len = binary_codec::utils::get_read_size(_p_stream, #size_key, _p_config)?;
956                                    let mut _p_map = std::collections::HashMap::<#key_type, #value_type>::with_capacity(_p_len);
957                                    for _ in 0.._p_len {
958                                        let _p_key;
959                                        #handle_key
960                                        _p_key = _p_val;
961                                        let _p_value;
962                                        #handle_value
963                                        _p_value = _p_val;
964                                        _p_map.insert(_p_key, _p_value);
965                                    }
966                                    let _p_val = _p_map;
967                                }
968                            } else {
969                                quote! {
970                                    let mut _p_map = std::collections::HashMap::<#key_type, #value_type>::new();
971                                    while _p_stream.bytes_left() > 0 {
972                                        let _p_key;
973                                        #handle_key
974                                        _p_key = _p_val;
975                                        let _p_value;
976                                        #handle_value
977                                        _p_value = _p_val;
978                                        _p_map.insert(_p_key, _p_value);
979                                    }
980                                    let _p_val = _p_map;
981                                }
982                            }
983                        } else {
984                            if has_size {
985                                quote! {
986                                    let _p_len = _p_val.len();
987                                    binary_codec::utils::write_size(_p_len, #size_key, _p_stream, _p_config)?;
988                                    #write_code
989                                }
990                            } else {
991                                quote! {
992                                    #write_code
993                                }
994                            }
995                        }
996                    }
997                    _ => {
998                        panic!("Type not implemented")
999                    }
1000                }
1001            } else {
1002                panic!("Multi-segment paths are not supported");
1003            }
1004        }
1005    } else if let Type::Array(array) = field_type {
1006        let len: usize = if let syn::Expr::Lit(ref arr_len_lit) = array.len {
1007            if let Lit::Int(ref lit_int) = arr_len_lit.lit {
1008                lit_int
1009                    .base10_parse()
1010                    .expect("Failed to parse literal to usize")
1011            } else {
1012                panic!("Expected an int to determine array length");
1013            }
1014        } else {
1015            panic!("Expected literal to determine array length");
1016        };
1017
1018        let array_type = &*array.elem;
1019        // Optimize [u8; N] to bulk read_bytes / write_bytes
1020        if let Type::Path(at_path) = array_type {
1021            if let Some(at_ident) = at_path.path.get_ident() {
1022                if at_ident == "u8" {
1023                    if read {
1024                        quote! {
1025                            let _p_slice = _p_stream.read_bytes(#len)?;
1026                            let _p_val = <[u8; #len]>::try_from(_p_slice).expect("Failed to convert slice to array");
1027                        }
1028                    } else {
1029                        quote! {
1030                            _p_stream.write_bytes(&_p_val);
1031                        }
1032                    }
1033                } else {
1034                    let handle = generate_code_for_handling_field(
1035                        read,
1036                        array_type,
1037                        field_name,
1038                        bits_count,
1039                        None,
1040                        None,
1041                        None,
1042                        is_dynamic_int,
1043                        val_dyn_length,
1044                        false,
1045                        false,
1046                        false,
1047                        true,
1048                        level + 1,
1049                    );
1050
1051                    let array_name = format_ident!("__val_{}", level);
1052
1053                    if read {
1054                        quote! {
1055                            let mut #array_name = Vec::<#array_type>::with_capacity(#len);
1056                            for _ in 0..#len {
1057                                #handle;
1058                                #array_name.push(_p_val);
1059                            }
1060                            let _p_val = TryInto::<[#array_type; #len]>::try_into(#array_name).expect("Failed to convert Vec to array");
1061                        }
1062                    } else {
1063                        quote! {
1064                            for _p_val in _p_val {
1065                                #handle
1066                            }
1067                        }
1068                    }
1069                }
1070            } else {
1071                // fallback to element handling
1072                let handle = generate_code_for_handling_field(
1073                    read,
1074                    array_type,
1075                    field_name,
1076                    bits_count,
1077                    None,
1078                    None,
1079                    None,
1080                    is_dynamic_int,
1081                    val_dyn_length,
1082                    false,
1083                    false,
1084                    false,
1085                    true,
1086                    level + 1,
1087                );
1088
1089                let array_name = format_ident!("__val_{}", level);
1090
1091                if read {
1092                    quote! {
1093                        let mut #array_name = Vec::<#array_type>::with_capacity(#len);
1094                        for _ in 0..#len {
1095                            #handle;
1096                            #array_name.push(_p_val);
1097                        }
1098                        let _p_val = TryInto::<[#array_type; #len]>::try_into(#array_name).expect("Failed to convert Vec to array");
1099                    }
1100                } else {
1101                    quote! {
1102                        for _p_val in _p_val {
1103                            #handle
1104                        }
1105                    }
1106                }
1107            }
1108        } else {
1109            panic!("Unsupported array element type");
1110        }
1111    } else {
1112        panic!("Field type of '{:?}' not supported", field_name);
1113    }
1114}
1115
1116fn generate_error_type(read: bool) -> proc_macro2::TokenStream {
1117    if read {
1118        quote! { binary_codec::DeserializationError }
1119    } else {
1120        quote! { binary_codec::SerializationError }
1121    }
1122}
1123
1124fn generate_size_key(
1125    length_by: Option<String>,
1126    has_dynamic_length: bool,
1127) -> (bool, proc_macro2::TokenStream) {
1128    if let Some(length_by) = length_by.as_ref() {
1129        (true, quote! { Some(#length_by) })
1130    } else if has_dynamic_length {
1131        (true, quote! { Some("__dynamic") })
1132    } else {
1133        (false, quote! { None })
1134    }
1135}
1136
1137fn get_string_value_from_attribute(attr: &Attribute) -> Option<String> {
1138    match &attr.meta {
1139        syn::Meta::Path(_) => None,
1140        syn::Meta::List(list_value) => {
1141            // #[myattribute("value")]
1142            for token in list_value.tokens.clone().into_iter() {
1143                if let proc_macro2::TokenTree::Literal(lit) = token {
1144                    return Some(lit.to_string().trim_matches('"').to_string());
1145                }
1146            }
1147
1148            None
1149        }
1150        syn::Meta::NameValue(name_value) => {
1151            if let syn::Expr::Lit(lit_expr) = &name_value.value {
1152                if let Lit::Str(lit_str) = &lit_expr.lit {
1153                    return Some(lit_str.value());
1154                }
1155            }
1156
1157            None
1158        }
1159    }
1160}
1161
1162fn get_int_value_from_attribute(attr: &Attribute) -> Option<i32> {
1163    match &attr.meta {
1164        syn::Meta::Path(_) => None,
1165        syn::Meta::List(list_value) => {
1166            // #[myattribute(value)]
1167            for token in list_value.tokens.clone().into_iter() {
1168                if let proc_macro2::TokenTree::Literal(lit) = token {
1169                    if let Ok(val) = lit.to_string().parse::<i32>() {
1170                        return Some(val);
1171                    }
1172                }
1173            }
1174
1175            None
1176        }
1177        syn::Meta::NameValue(name_value) => {
1178            if let syn::Expr::Lit(lit_expr) = &name_value.value {
1179                if let Lit::Int(lit_int) = &lit_expr.lit {
1180                    return Some(lit_int.base10_parse().expect("Not a valid int value"));
1181                }
1182            }
1183
1184            None
1185        }
1186    }
1187}
1188
1189fn get_inner_type(path: &syn::Path) -> Option<&syn::Type> {
1190    if let Some(PathArguments::AngleBracketed(args)) =
1191        path.segments.last().map(|seg| &seg.arguments)
1192    {
1193        if let Some(arg) = args.args.first() {
1194            if let syn::GenericArgument::Type(inner_type) = arg {
1195                return Some(inner_type);
1196            }
1197        }
1198    }
1199
1200    None
1201}
1202
1203fn get_two_types(path: &syn::Path) -> Option<(&syn::Type, &syn::Type)> {
1204    if let Some(PathArguments::AngleBracketed(args)) =
1205        path.segments.last().map(|seg| &seg.arguments)
1206    {
1207        let mut types = args.args.iter().filter_map(|arg| {
1208            if let syn::GenericArgument::Type(inner_type) = arg {
1209                Some(inner_type)
1210            } else {
1211                None
1212            }
1213        });
1214
1215        if let (Some(t1), Some(t2)) = (types.next(), types.next()) {
1216            return Some((t1, t2));
1217        }
1218    }
1219
1220    None
1221}
1222
1223fn generate_dynint(read: bool) -> proc_macro2::TokenStream {
1224    if read {
1225        quote! {
1226            let _p_dyn = _p_stream.read_dyn_int()?;
1227        }
1228    } else {
1229        quote! {
1230            _p_stream.write_dyn_int(_p_dyn);
1231        }
1232    }
1233}