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 {
331                    lit: Lit::Int(lit_int),
332                    ..
333                }) => lit_int
334                    .base10_parse::<u8>()
335                    .expect("Invalid discriminant integer"),
336                _ => panic!("Discriminant must be an integer literal"),
337            }
338        } else {
339            match last_val {
340                Some(v) => v + 1,
341                None => 0,
342            }
343        };
344
345        if val > u8::from(u8::MAX) {
346            panic!("Discriminant value too large (must fit in u8)");
347        }
348
349        disc_values.push(val);
350        last_val = Some(val);
351    }
352
353    // Create discriminant getter
354    let disc_variants = data_enum
355        .variants
356        .iter()
357        .enumerate()
358        .map(|(i, variant)| {
359            let var_ident = &variant.ident;
360            let disc_value = disc_values[i];
361
362            for attr in variant.attrs.iter() {
363                if attr.path().is_ident("toggled_by") {
364                    let field = get_string_value_from_attribute(attr)
365                        .expect("toggled_by for multi_enum should have a value");
366                    configure_functions.push(quote! {
367                        _p_config.configure_multi_disc(stringify!(#enum_name), #disc_value, #field);
368                    });
369                }
370            }
371
372            match &variant.fields {
373                Fields::Unit => quote! {
374                    Self::#var_ident => #disc_value
375                },
376                Fields::Unnamed(_) => quote! {
377                    Self::#var_ident(..) => #disc_value
378                },
379                Fields::Named(_) => quote! {
380                    Self::#var_ident { .. } => #disc_value
381                },
382            }
383        })
384        .collect::<Vec<_>>();
385
386    // Assign discriminant values starting from 0
387    let serialization_variants = data_enum.variants.iter().enumerate().map(|(i, variant)| {
388        let var_ident = &variant.ident;
389        let disc_value = disc_values[i];
390        let fields = &variant.fields;
391
392        // TODO: problem might be that attrs are not used from the fields??.
393
394        let write_disc = if no_disc_prefix {
395            quote! {}
396        } else {
397            quote! {
398                let _p_disc: u8 = #disc_value;
399                _p_stream.write_fixed_int(_p_disc);
400            }
401        };
402
403        match fields {
404            Fields::Unit => {
405                if read {
406                    quote! {
407                        #disc_value => {
408                            Ok(Self::#var_ident)
409                        }
410                    }
411                } else {
412                    quote! {
413                        Self::#var_ident => {
414                            #write_disc
415                        }
416                    }
417                }
418            }
419            Fields::Unnamed(fields_unnamed) => {
420                let field_count = fields_unnamed.unnamed.len();
421                let idents: Vec<_> = (0..field_count).map(|i| format_ident!("f{}", i)).collect();
422                let ident_refs: Vec<&syn::Ident> = idents.iter().collect();
423                let field_serializations =
424                    generate_enum_field_serializations(read, &ident_refs, &fields_unnamed.unnamed);
425                if read {
426                    quote! {
427                        #disc_value => {
428                            #(#field_serializations)*
429                            Ok(Self::#var_ident(#(#idents),*))
430                        }
431                    }
432                } else {
433                    quote! {
434                        Self::#var_ident(#(#idents),*) => {
435                            #write_disc
436                            #(#field_serializations)*
437                        }
438                    }
439                }
440            }
441            Fields::Named(fields_named) => {
442                let field_idents: Vec<_> = fields_named
443                    .named
444                    .iter()
445                    .map(|f| f.ident.as_ref().unwrap())
446                    .collect();
447
448                let field_serializations =
449                    generate_enum_field_serializations(read, &field_idents, &fields_named.named);
450
451                if read {
452                    quote! {
453                        #disc_value => {
454                            #(#field_serializations)*
455                            Ok(Self::#var_ident { #(#field_idents),* })
456                        }
457                    }
458                } else {
459                    quote! {
460                        Self::#var_ident { #(#field_idents),* } => {
461                            #write_disc
462                            #(#field_serializations)*
463                        }
464                    }
465                }
466            }
467        }
468    });
469
470    if read {
471        quote! {
472            impl #enum_name {
473                pub fn configure_multi_disc<T : Clone>(config: &mut binary_codec::SerializerConfig<T>) {
474                    let _p_config = config;
475                    #(#configure_functions)*
476                }
477            }
478
479            impl<T : Clone> binary_codec::BinaryDeserializer<T> for #enum_name {
480                fn read_bytes(
481                    stream: &mut binary_codec::BitStreamReader,
482                    config: Option<&mut binary_codec::SerializerConfig<T>>,
483                ) -> Result<Self, #error_type> {
484                    let mut _new_config = binary_codec::SerializerConfig::new(None);
485                    let _p_config = config.unwrap_or(&mut _new_config);
486                    let _p_stream = stream;
487
488                    let _p_disc = if let Some(disc) = _p_config.discriminator.take() {
489                        disc
490                    } else {
491                        _p_stream.read_fixed_int()?
492                    };
493
494                    match _p_disc {
495                        #(#serialization_variants,)*
496                        _ => Err(#error_type::UnknownDiscriminant(_p_disc)),
497                    }
498                }
499            }
500        }
501        .into()
502    } else {
503        quote! {
504            impl<T : Clone> binary_codec::BinarySerializer<T> for #enum_name {
505                fn write_bytes(
506                    &self,
507                    stream: &mut binary_codec::BitStreamWriter,
508                    config: Option<&mut binary_codec::SerializerConfig<T>>,
509                ) -> Result<(), #error_type> {
510                    let mut _new_config = binary_codec::SerializerConfig::new(None);
511                    let _p_config = config.unwrap_or(&mut _new_config);
512                    #(#configure_functions)*
513                    let _p_stream = stream;
514
515                    match self {
516                        #(#serialization_variants)*
517                    }
518
519                    Ok(())
520                }
521            }
522
523            impl #enum_name {
524                pub fn get_discriminator(&self) -> u8 {
525                    match self {
526                        #(#disc_variants,)*
527                    }
528                }
529            }
530        }
531        .into()
532    }
533}
534
535fn generate_enum_field_serializations(
536    read: bool,
537    idents: &Vec<&syn::Ident>,
538    fields: &Punctuated<syn::Field, Comma>,
539) -> Vec<proc_macro2::TokenStream> {
540    let field_serializations = fields.iter().enumerate().map(|(i, f)| {
541        let field_type = &f.ty;
542        let field_ident = &idents[i];
543
544        generate_field_serializer(read, &field_ident, field_type, f, true)
545    });
546    field_serializations.collect()
547}
548
549fn generate_code_for_handling_field(
550    read: bool,
551    field_type: &Type,
552    field_name: &syn::Ident,
553    bits_count: Option<u8>,
554    toggled_by: Option<String>,
555    variant_by: Option<String>,
556    length_by: Option<String>,
557    is_dynamic_int: bool,
558    has_dynamic_length: bool,
559    key_dyn_length: bool,
560    val_dyn_length: bool,
561    multi_enum: bool,
562    direct_collection_child: bool,
563    level: usize,
564) -> proc_macro2::TokenStream {
565    if let Type::Path(path) = field_type {
566        let path = &path.path;
567
568        if let Some(ident) = path.get_ident() {
569            let ident_name = ident.to_string();
570
571            // Single segment without arguments
572            match ident_name.as_str() {
573                "bool" => {
574                    if read {
575                        quote! { let _p_val = _p_stream.read_bit()?;}
576                    } else {
577                        quote! { _p_stream.write_bit(*_p_val); }
578                    }
579                }
580                "i8" => {
581                    if let Some(bits_count) = bits_count.as_ref() {
582                        if *bits_count < 1 || *bits_count > 7 {
583                            panic!("Bits count should be between 1 and 7");
584                        }
585
586                        if read {
587                            quote! { let _p_val = binary_codec::ZigZag::to_signed(_p_stream.read_small(#bits_count)?); }
588                        } else {
589                            quote! { _p_stream.write_small(binary_codec::ZigZag::to_unsigned(*_p_val), #bits_count); }
590                        }
591                    } else {
592                        if read {
593                            quote! { let _p_val = _p_stream.read_fixed_int()?; }
594                        } else {
595                            quote! { _p_stream.write_fixed_int(*_p_val); }
596                        }
597                    }
598                }
599                "u8" => {
600                    if let Some(bits_count) = bits_count.as_ref() {
601                        if *bits_count < 1 || *bits_count > 7 {
602                            panic!("Bits count should be between 1 and 7");
603                        }
604
605                        if read {
606                            quote! { let _p_val = _p_stream.read_small(#bits_count)?; }
607                        } else {
608                            quote! { _p_stream.write_small(*_p_val, #bits_count); }
609                        }
610                    } else {
611                        if read {
612                            quote! { let _p_val = _p_stream.read_byte()?; }
613                        } else {
614                            quote! { _p_stream.write_byte(*_p_val); }
615                        }
616                    }
617                }
618                "u16" | "u32" | "u64" | "u128" => {
619                    if is_dynamic_int {
620                        let dynint: proc_macro2::TokenStream = generate_dynint(read);
621                        if read {
622                            quote! {
623                                #dynint
624                                let _p_val = _p_dyn as #ident;
625                            }
626                        } else {
627                            quote! {
628                                let _p_dyn = *_p_val as u128;
629                                #dynint
630                            }
631                        }
632                    } else {
633                        if read {
634                            quote! { let _p_val = _p_stream.read_fixed_int()?; }
635                        } else {
636                            quote! { _p_stream.write_fixed_int(*_p_val); }
637                        }
638                    }
639                }
640                "i16" | "i32" | "i64" | "i128" => {
641                    if is_dynamic_int {
642                        let dynint: proc_macro2::TokenStream = generate_dynint(read);
643                        if read {
644                            quote! {
645                                #dynint
646                                let _p_val: #ident = binary_codec::ZigZag::to_signed(_p_dyn);
647                            }
648                        } else {
649                            quote! {
650                                let _p_dyn = binary_codec::ZigZag::to_unsigned(*_p_val) as u128;
651                                #dynint
652                            }
653                        }
654                    } else {
655                        if read {
656                            quote! { let _p_val = _p_stream.read_fixed_int()?; }
657                        } else {
658                            quote! { _p_stream.write_fixed_int(*_p_val); }
659                        }
660                    }
661                }
662                "String" => {
663                    let size_key = generate_size_key(length_by, has_dynamic_length).1;
664
665                    if read {
666                        quote! {
667                            let _p_val = binary_codec::utils::read_string(_p_stream, #size_key, _p_config)?;
668                        }
669                    } else {
670                        quote! {
671                            binary_codec::utils::write_string(_p_val, #size_key, _p_stream, _p_config)?;
672                        }
673                    }
674                }
675                _ => {
676                    let size_key = generate_size_key(length_by, has_dynamic_length).1;
677
678                    let variant_code = if variant_by.is_some() {
679                        quote! {
680                            _p_config.discriminator = _p_config.get_variant(#variant_by);
681                        }
682                    } else if multi_enum {
683                        let config_multi = if !direct_collection_child {
684                            quote! { #ident::configure_multi_disc(_p_config); }
685                        } else {
686                            quote! {}
687                        };
688
689                        quote! {
690                            #config_multi
691                            _p_config.discriminator = _p_config.get_next_multi_disc(stringify!(#field_name), #ident_name);
692                        }
693                    } else {
694                        quote! {
695                            _p_config.discriminator = None;
696                        }
697                    };
698
699                    if read {
700                        quote! {
701                            #variant_code
702                            let _p_val = binary_codec::utils::read_object(_p_stream, #size_key, _p_config)?;
703                        }
704                    } else {
705                        quote! {
706                            #variant_code
707                            binary_codec::utils::write_object(_p_val, #size_key, _p_stream, _p_config)?;
708                        }
709                    }
710                }
711            }
712        } else {
713            // Multiple segments, or arguments
714            if path.segments.len() == 1 {
715                let ident = &path.segments[0].ident;
716                let ident_name = ident.to_string();
717
718                match ident_name.as_ref() {
719                    "RefCell" => {
720                        let inner_type = get_inner_type(path).expect("Option missing inner type");
721                        let handle = generate_code_for_handling_field(
722                            read,
723                            inner_type,
724                            field_name,
725                            bits_count,
726                            None,
727                            variant_by,
728                            length_by,
729                            is_dynamic_int,
730                            has_dynamic_length,
731                            key_dyn_length,
732                            val_dyn_length,
733                            multi_enum,
734                            false,
735                            level + 1,
736                        );
737
738                        if read {
739                            quote! {
740                                #handle
741                                let _p_val = RefCell::new(_p_val);
742                            }
743                        } else {
744                            quote! {
745                                let _p_val = &*_p_val.borrow();
746                                #handle
747                            }
748                        }
749                    }
750                    "Option" => {
751                        let inner_type = get_inner_type(path).expect("Option missing inner type");
752                        let handle = generate_code_for_handling_field(
753                            read,
754                            inner_type,
755                            field_name,
756                            bits_count,
757                            None,
758                            variant_by,
759                            length_by,
760                            is_dynamic_int,
761                            has_dynamic_length,
762                            key_dyn_length,
763                            val_dyn_length,
764                            multi_enum,
765                            false,
766                            level + 1,
767                        );
768                        let option_name: syn::Ident = format_ident!("__option_{}", level);
769
770                        if let Some(toggled_by) = toggled_by {
771                            // If toggled_by is set, read or write it
772                            let toggled_by = quote! {
773                                _p_config.get_toggle(#toggled_by).unwrap_or(false)
774                            };
775
776                            if read {
777                                quote! {
778                                    let mut #option_name: Option<#inner_type> = None;
779                                    if #toggled_by {
780                                        #handle
781                                        #option_name = Some(_p_val);
782                                    }
783                                    let _p_val = #option_name;
784                                }
785                            } else {
786                                quote! {
787                                    if #toggled_by {
788                                        let _p_val = _p_val.as_ref().expect("Expected Some value, because toggled_by field is true");
789                                        #handle
790                                    }
791                                }
792                            }
793                        } else {
794                            // If space available, read it, write it if not None
795                            if read {
796                                quote! {
797                                    let mut #option_name: Option<#inner_type> = None;
798                                    if _p_stream.bytes_left() > 0 {
799                                        #handle
800                                        #option_name = Some(_p_val);
801                                    }
802                                    let _p_val = #option_name;
803                                }
804                            } else {
805                                quote! {
806                                    if let Some(_p_val) = _p_val.as_ref() {
807                                        #handle
808                                    }
809                                }
810                            }
811                        }
812                    }
813                    "Vec" => {
814                        let vec_name = format_ident!("__val_{}", level);
815                        let inner_type = get_inner_type(path).expect("Vec missing inner type");
816
817                        // If inner type is u8, optimize to bulk read/write bytes
818                        if let Type::Path(inner_path) = inner_type {
819                            if let Some(inner_ident) = inner_path.path.get_ident() {
820                                if inner_ident == "u8" {
821                                    let (has_size, size_key) =
822                                        generate_size_key(length_by, has_dynamic_length);
823
824                                    if read {
825                                        if has_size || multi_enum {
826                                            // sized read
827                                            let len_code = if multi_enum {
828                                                quote! {
829                                                    // multi_enum sized Vec<u8>
830                                                    let _p_len = _p_config.get_multi_disc_size("u8");
831                                                }
832                                            } else {
833                                                quote! {
834                                                    let _p_len = binary_codec::utils::get_read_size(_p_stream, #size_key, _p_config)?;
835                                                }
836                                            };
837
838                                            return quote! {
839                                                #len_code
840                                                let _p_val = _p_stream.read_bytes(_p_len)?.to_vec();
841                                            };
842                                        } else {
843                                            // read all remaining bytes
844                                            return quote! {
845                                                let _p_len = _p_stream.bytes_left();
846                                                let _p_val = _p_stream.read_bytes(_p_len)?.to_vec();
847                                            };
848                                        }
849                                    } else {
850                                        // write path: if sized, write size first
851                                        let write_size = if has_size {
852                                            quote! {
853                                                let _p_len = _p_val.len();
854                                                binary_codec::utils::write_size(_p_len, #size_key, _p_stream, _p_config)?;
855                                            }
856                                        } else {
857                                            quote! {}
858                                        };
859
860                                        return quote! {
861                                            #write_size
862                                            _p_stream.write_bytes(_p_val);
863                                        };
864                                    }
865                                }
866                            }
867                        }
868
869                        // Fallback to element-wise handling for non-u8 inner types
870                        let handle = generate_code_for_handling_field(
871                            read,
872                            inner_type,
873                            field_name,
874                            bits_count,
875                            None,
876                            None,
877                            None,
878                            is_dynamic_int,
879                            val_dyn_length,
880                            false,
881                            false,
882                            multi_enum,
883                            true,
884                            level + 1,
885                        );
886
887                        let (has_size, size_key) = generate_size_key(length_by, has_dynamic_length);
888
889                        let write_code = quote! {
890                            for _p_val in _p_val {
891                                #handle
892                            }
893                        };
894
895                        if has_size || (read && multi_enum) {
896                            if read {
897                                let len_code = if multi_enum && let Type::Path(path) = inner_type {
898                                    let enum_ident = path
899                                        .path
900                                        .get_ident()
901                                        .expect("Expected ident for multi_enum inner type");
902                                    quote! {
903                                        #enum_ident::configure_multi_disc(_p_config);
904                                        let _p_len = _p_config.get_multi_disc_size(stringify!(#enum_ident));
905                                    }
906                                } else {
907                                    quote! {
908                                        let _p_len = binary_codec::utils::get_read_size(_p_stream, #size_key, _p_config)?;
909                                    }
910                                };
911
912                                quote! {
913                                    #len_code
914                                    let mut #vec_name = Vec::<#inner_type>::with_capacity(_p_len);
915                                    for _ in 0.._p_len {
916                                        #handle
917                                        #vec_name.push(_p_val);
918                                    }
919                                    let _p_val = #vec_name;
920                                }
921                            } else {
922                                quote! {
923                                    let _p_len = _p_val.len();
924                                    binary_codec::utils::write_size(_p_len, #size_key, _p_stream, _p_config)?;
925                                    #write_code
926                                }
927                            }
928                        } else {
929                            if read {
930                                quote! {
931                                    let mut #vec_name = Vec::<#inner_type>::new();
932                                    while _p_stream.bytes_left() > 0 {
933                                        #handle
934                                        #vec_name.push(_p_val);
935                                    }
936                                    let _p_val = #vec_name;
937                                }
938                            } else {
939                                quote! {
940                                    #write_code
941                                }
942                            }
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}