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