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