binary_codec_derive/
lib.rs

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