Skip to main content

binary_codec_derive/
lib.rs

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