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