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