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