binary_codec_derive/
lib.rs

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