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        match &variant.fields {
267            Fields::Unit => quote! {
268                Self::#var_ident => #disc_value
269            },
270            Fields::Unnamed(_) => quote! {
271                Self::#var_ident(..) => #disc_value
272            },
273            Fields::Named(_) => quote! {
274                Self::#var_ident { .. } => #disc_value
275            },
276        }
277    });
278
279    // Assign discriminant values starting from 0
280    let serialization_variants = data_enum.variants.iter().enumerate().map(|(i, variant)| {
281        let var_ident = &variant.ident;
282        let disc_value = i as u8; // Could be changed to u16/u32 if needed
283        let fields = &variant.fields;
284
285        let write_disc = if no_disc_prefix {
286            quote! {}
287        } else {
288            quote! {
289                let _p_disc: u8 = #disc_value;
290                binary_codec::fixed_int::FixedInt::write(_p_disc, _p_bytes, _p_config)?;
291            }
292        };
293
294        match fields {
295            Fields::Unit => {
296                if read {
297                    quote! {
298                        #disc_value => {
299                            Ok(Self::#var_ident)
300                        }
301                    }
302                } else {
303                    quote! {
304                        Self::#var_ident => {
305                            #write_disc
306                        }
307                    }
308                }
309            }
310            Fields::Unnamed(fields_unnamed) => {
311                let field_count = fields_unnamed.unnamed.len();
312                let idents: Vec<_> = (0..field_count).map(|i| format_ident!("f{}", i)).collect();
313                let ident_refs: Vec<&syn::Ident> = idents.iter().collect();
314                let field_serializations =
315                    generate_enum_field_serializations(read, &ident_refs, &fields_unnamed.unnamed);
316                if read {
317                    quote! {
318                        #disc_value => {
319                            #(#field_serializations)*
320                            Ok(Self::#var_ident(#(#idents),*))
321                        }
322                    }
323                } else {
324                    quote! {
325                        Self::#var_ident(#(#idents),*) => {
326                            #write_disc
327                            #(#field_serializations)*
328                        }
329                    }
330                }
331            }
332            Fields::Named(fields_named) => {
333                let field_idents: Vec<_> = fields_named
334                    .named
335                    .iter()
336                    .map(|f| f.ident.as_ref().unwrap())
337                    .collect();
338
339                let field_serializations =
340                    generate_enum_field_serializations(read, &field_idents, &fields_named.named);
341
342                if read {
343                    quote! {
344                        #disc_value => {
345                            #(#field_serializations)*
346                            Ok(Self::#var_ident { #(#field_idents),* })
347                        }
348                    }
349                } else {
350                    quote! {
351                        Self::#var_ident { #(#field_idents),* } => {
352                            #write_disc
353                            #(#field_serializations)*
354                        }
355                    }
356                }
357            }
358        }
359    });
360
361    if read {
362        quote! {
363            impl binary_codec::BinaryDeserializer for #enum_name {
364                fn from_bytes(bytes: &[u8], config: Option<&mut binary_codec::SerializerConfig>) -> Result<Self, #error_type> {
365                    let mut _new_config = binary_codec::SerializerConfig::new();
366                    let _p_config = config.unwrap_or(&mut _new_config);
367                    let _p_bytes = bytes;
368
369                    let _p_disc = if let Some(disc) = _p_config.discriminator.take() {
370                        disc
371                    } else {
372                        binary_codec::fixed_int::FixedInt::read(_p_bytes, _p_config)?
373                    };
374
375                    match _p_disc {
376                        #(#serialization_variants,)*
377                        _ => Err(#error_type::UnknownDiscriminant(_p_disc)),
378                    }
379                }
380            }
381        }
382        .into()
383    } else {
384        quote! {
385            impl binary_codec::BinarySerializer for #enum_name {
386                fn to_bytes(&self, config: Option<&mut binary_codec::SerializerConfig>) -> Result<Vec<u8>, #error_type> {
387                    let mut bytes = Vec::new();
388                    Self::write_bytes(self, &mut bytes, config)?;
389                    Ok(bytes)
390                }
391
392                fn write_bytes(&self, buffer: &mut Vec<u8>, config: Option<&mut binary_codec::SerializerConfig>) -> Result<(), #error_type> {
393                    let mut _new_config = binary_codec::SerializerConfig::new();
394                    let _p_config = config.unwrap_or(&mut _new_config);
395                    let _p_bytes = buffer;
396
397                    match self {
398                        #(#serialization_variants)*
399                    }
400
401                    Ok(())
402                }
403            }
404
405            impl #enum_name {
406                fn get_discriminator(&self) -> u8 {
407                    match self {
408                        #(#disc_variants,)*
409                    }
410                }
411            }
412        }
413        .into()
414    }
415}
416
417fn generate_enum_field_serializations(
418    read: bool,
419    idents: &Vec<&syn::Ident>,
420    fields: &Punctuated<syn::Field, Comma>,
421) -> Vec<proc_macro2::TokenStream> {
422    let field_serializations = fields.iter().enumerate().map(|(i, f)| {
423        let field_type = &f.ty;
424        let field_ident = &idents[i];
425
426        let handle_field = generate_code_for_handling_field(
427            read,
428            field_type,
429            field_ident,
430            None,
431            None,
432            None,
433            None,
434            false,
435            false,
436            false,
437            false,
438            0,
439        );
440
441        if read {
442            quote! {
443                #handle_field
444                let #field_ident = _p_val;
445            }
446        } else {
447            quote! {
448                let _p_val = #field_ident;
449                #handle_field
450            }
451        }
452    });
453    field_serializations.collect()
454}
455
456fn generate_code_for_handling_field(
457    read: bool,
458    field_type: &Type,
459    field_name: &syn::Ident,
460    bits_count: Option<u8>,
461    toggled_by: Option<String>,
462    variant_by: Option<String>,
463    length_by: Option<String>,
464    is_dynamic_int: bool,
465    has_dynamic_length: bool,
466    key_dyn_length: bool,
467    val_dyn_length: bool,
468    level: usize,
469) -> proc_macro2::TokenStream {
470    if let Type::Path(path) = field_type {
471        let path = &path.path;
472
473        if let Some(ident) = path.get_ident() {
474            let ident_name = ident.to_string();
475
476            // Single segment without arguments
477            match ident_name.as_str() {
478                "bool" => {
479                    if read {
480                        quote! { let _p_val = binary_codec::dynamics::read_bool(_p_bytes, _p_config)?; }
481                    } else {
482                        quote! { binary_codec::dynamics::write_bool(*_p_val, _p_bytes, _p_config)?; }
483                    }
484                }
485                "i8" => {
486                    if let Some(bits_count) = bits_count.as_ref() {
487                        if *bits_count < 1 || *bits_count > 7 {
488                            panic!("Bits count should be between 1 and 7");
489                        }
490
491                        if read {
492                            quote! { let _p_val = binary_codec::dynamics::read_small_dynamic_signed(_p_bytes, _p_config, #bits_count)?; }
493                        } else {
494                            quote! { binary_codec::dynamics::write_small_dynamic_signed(*_p_val, _p_bytes, _p_config, #bits_count)?; }
495                        }
496                    } else {
497                        if read {
498                            quote! {
499                                let _p_val = binary_codec::dynamics::read_zigzag(_p_bytes, _p_config)?;
500                            }
501                        } else {
502                            quote! {
503                                binary_codec::dynamics::write_zigzag(*_p_val, _p_bytes, _p_config)?;
504                            }
505                        }
506                    }
507                }
508                "u8" => {
509                    if let Some(bits_count) = bits_count.as_ref() {
510                        if *bits_count < 1 || *bits_count > 7 {
511                            panic!("Bits count should be between 1 and 7");
512                        }
513
514                        if read {
515                            quote! { let _p_val = binary_codec::dynamics::read_small_dynamic_unsigned(_p_bytes, _p_config, #bits_count)?; }
516                        } else {
517                            quote! { binary_codec::dynamics::write_small_dynamic_unsigned(*_p_val, _p_bytes, _p_config, #bits_count)?; }
518                        }
519                    } else {
520                        if read {
521                            quote! {
522                                let _p_val = binary_codec::fixed_int::FixedInt::read(_p_bytes, _p_config)?;
523                            }
524                        } else {
525                            quote! {
526                                binary_codec::fixed_int::FixedInt::write(*_p_val, _p_bytes, _p_config)?;
527                            }
528                        }
529                    }
530                }
531                "u16" | "u32" | "u64" | "u128" => {
532                    if is_dynamic_int {
533                        let dynint: proc_macro2::TokenStream = generate_dynint(read);
534                        if read {
535                            quote! {
536                                #dynint
537                                let _p_val = _p_dyn as #ident;
538                            }
539                        } else {
540                            quote! {
541                                let _p_dyn = *_p_val as u128;
542                                #dynint
543                            }
544                        }
545                    } else {
546                        if read {
547                            quote! {
548                                let _p_val = binary_codec::fixed_int::FixedInt::read(_p_bytes, _p_config)?;
549                            }
550                        } else {
551                            quote! {
552                                binary_codec::fixed_int::FixedInt::write(*_p_val, _p_bytes, _p_config)?;
553                            }
554                        }
555                    }
556                }
557                "i16" | "i32" | "i64" | "i128" => {
558                    if is_dynamic_int {
559                        let dynint: proc_macro2::TokenStream = generate_dynint(read);
560                        if read {
561                            quote! {
562                                #dynint
563                                let _p_val: #ident = binary_codec::fixed_int::ZigZag::to_signed(_p_dyn);
564                            }
565                        } else {
566                            quote! {
567                                let _p_dyn = binary_codec::fixed_int::ZigZag::to_unsigned(*_p_val) as u128;
568                                #dynint
569                            }
570                        }
571                    } else {
572                        if read {
573                            quote! {
574                                let _p_val = binary_codec::fixed_int::read_zigzag(_p_bytes, _p_config)?;
575                            }
576                        } else {
577                            quote! {
578                                binary_codec::fixed_int::write_zigzag(*_p_val, _p_bytes, _p_config)?;
579                            }
580                        }
581                    }
582                }
583                "String" => {
584                    let size_key = generate_size_key(length_by, has_dynamic_length).1;
585
586                    if read {
587                        quote! {
588                            let _p_val = binary_codec::variable::read_string(_p_bytes, #size_key, _p_config)?;
589                        }
590                    } else {
591                        quote! {
592                            binary_codec::variable::write_string(_p_val, #size_key, _p_bytes, _p_config)?;
593                        }
594                    }
595                }
596                _ => {
597                    let size_key = generate_size_key(length_by, has_dynamic_length).1;
598
599                    let variant_code = if variant_by.is_some() {
600                        quote! { 
601                            _p_config.discriminator = _p_config.get_variant(#variant_by);
602                        }
603                    } else { quote! {} };
604
605                    if read {
606                        quote! {
607                            #variant_code
608                            let _p_val = binary_codec::variable::read_object(_p_bytes, #size_key, _p_config)?;
609                        }
610                    } else {
611                        quote! {
612                            #variant_code
613                            binary_codec::variable::write_object(_p_val, #size_key, _p_bytes, _p_config)?;
614                        }
615                    }
616                }
617            }
618        } else {
619            // Multiple segments, or arguments
620            if path.segments.len() == 1 {
621                let ident = &path.segments[0].ident;
622                let ident_name = ident.to_string();
623
624                match ident_name.as_ref() {
625                    "Option" => {
626                        let inner_type = get_inner_type(path).expect("Option missing inner type");
627                        let handle = generate_code_for_handling_field(
628                            read,
629                            inner_type,
630                            field_name,
631                            bits_count,
632                            None,
633                            variant_by,
634                            length_by,
635                            is_dynamic_int,
636                            has_dynamic_length,
637                            key_dyn_length,
638                            val_dyn_length,
639                            level + 1,
640                        );
641                        let option_name: syn::Ident = format_ident!("__option_{}", level);
642
643                        if let Some(toggled_by) = toggled_by {
644                            // If toggled_by is set, read or write it
645                            let toggled_by = quote! {
646                                _p_config.get_toggle(#toggled_by).unwrap_or(false)
647                            };
648
649                            if read {
650                                quote! {
651                                    let mut #option_name: Option<#inner_type> = None;
652                                    if #toggled_by {
653                                        #handle
654                                        #option_name = Some(_p_val);
655                                    }
656                                    let _p_val = #option_name;
657                                }
658                            } else {
659                                quote! {
660                                    if #toggled_by {
661                                        let _p_val = _p_val.as_ref().expect("Expected Some value, because toggled_by field is true");
662                                        #handle
663                                    }
664                                }
665                            }
666                        } else {
667                            // If space available, read it, write it if not None
668                            if read {
669                                quote! {
670                                    let mut #option_name: Option<#inner_type> = None;
671                                    if _p_config.next_reset_bits_pos() < _p_bytes.len() {
672                                        #handle
673                                        #option_name = Some(_p_val);
674                                    }
675                                    let _p_val = #option_name;
676                                }
677                            } else {
678                                quote! {
679                                    if let Some(_p_val) = _p_val.as_ref() {
680                                        #handle
681                                    }
682                                }
683                            }
684                        }
685                    }
686                    "Vec" => {
687                        let vec_name = format_ident!("__val_{}", level);
688                        let inner_type = get_inner_type(path).expect("Vec missing inner type");
689                        let handle = generate_code_for_handling_field(
690                            read,
691                            inner_type,
692                            field_name,
693                            bits_count,
694                            None,
695                            None,
696                            None,
697                            is_dynamic_int,
698                            val_dyn_length,
699                            false,
700                            false,
701                            level + 1,
702                        );
703
704                        let (has_size, size_key) = generate_size_key(length_by, has_dynamic_length);
705
706                        let write_code = quote! {
707                            for _p_val in _p_val {
708                                #handle
709                            }
710                        };
711
712                        if has_size {
713                            if read {
714                                quote! {
715                                    let _p_len = binary_codec::utils::get_read_size(_p_bytes, #size_key, _p_config)?;
716                                    let mut #vec_name = Vec::<#inner_type>::with_capacity(_p_len);
717                                    for _ in 0.._p_len {
718                                        #handle
719                                        #vec_name.push(_p_val);
720                                    }
721                                    let _p_val = #vec_name;
722                                }
723                            } else {
724                                quote! {
725                                    let _p_len = _p_val.len();
726                                    binary_codec::utils::write_size(_p_len, #size_key, _p_bytes, _p_config)?;
727                                    #write_code
728                                }
729                            }
730                        } else {
731                            if read {
732                                quote! {
733                                    let mut #vec_name = Vec::<#inner_type>::new();
734                                    while _p_config.next_reset_bits_pos() < _p_bytes.len() {
735                                        #handle
736                                        #vec_name.push(_p_val);
737                                    }
738                                    let _p_val = #vec_name;
739                                }
740                            } else {
741                                quote! {
742                                    #write_code
743                                }
744                            }
745                        }
746                    }
747                    "HashMap" => {
748                        let (key_type, value_type) =
749                            get_two_types(path).expect("Failed to get HashMap types");
750
751                        let handle_key = generate_code_for_handling_field(
752                            read,
753                            key_type,
754                            field_name,
755                            None,
756                            None,
757                            None,
758                            None,
759                            is_dynamic_int,
760                            key_dyn_length,
761                            false,
762                            false,
763                            level + 1,
764                        );
765
766                        let handle_value = generate_code_for_handling_field(
767                            read,
768                            value_type,
769                            field_name,
770                            None,
771                            None,
772                            None,
773                            None,
774                            is_dynamic_int,
775                            val_dyn_length,
776                            false,
777                            false,
778                            level + 1,
779                        );
780
781                        let (has_size, size_key) = generate_size_key(length_by, has_dynamic_length);
782
783                        let write_code = quote! {
784                            for (key, value) in _p_val {
785                                let _p_val = key;
786                                #handle_key
787                                let _p_val = value;
788                                #handle_value
789                            }
790                        };
791
792                        if read {
793                            if has_size {
794                                quote! {
795                                    let _p_len = binary_codec::utils::get_read_size(_p_bytes, #size_key, _p_config)?;
796                                    let mut _p_map = std::collections::HashMap::<#key_type, #value_type>::with_capacity(_p_len);
797                                    for _ in 0.._p_len {
798                                        let _p_key;
799                                        #handle_key
800                                        _p_key = _p_val;
801                                        let _p_value;
802                                        #handle_value
803                                        _p_value = _p_val;
804                                        _p_map.insert(_p_key, _p_value);
805                                    }
806                                    let _p_val = _p_map;
807                                }
808                            } else {
809                                quote! {
810                                    let mut _p_map = std::collections::HashMap::<#key_type, #value_type>::new();
811                                    while _p_config.next_reset_bits_pos() < _p_bytes.len() {
812                                        let _p_key;
813                                        #handle_key
814                                        _p_key = _p_val;
815                                        let _p_value;
816                                        #handle_value
817                                        _p_value = _p_val;
818                                        _p_map.insert(_p_key, _p_value);
819                                    }
820                                    let _p_val = _p_map;
821                                }
822                            }
823                        } else {
824                            if has_size {
825                                quote! {
826                                    let _p_len = _p_val.len();
827                                    binary_codec::utils::write_size(_p_len, #size_key, _p_bytes, _p_config)?;
828                                    #write_code
829                                }
830                            } else {
831                                quote! {
832                                    #write_code
833                                }
834                            }
835                        }
836                    }
837                    _ => {
838                        panic!("Type not implemented")
839                    }
840                }
841            } else {
842                panic!("Multi-segment paths are not supported");
843            }
844        }
845    } else if let Type::Array(array) = field_type {
846        let len: usize = if let syn::Expr::Lit(ref arr_len_lit) = array.len {
847            if let Lit::Int(ref lit_int) = arr_len_lit.lit {
848                lit_int
849                    .base10_parse()
850                    .expect("Failed to parse literal to usize")
851            } else {
852                panic!("Expected an int to determine array length");
853            }
854        } else {
855            panic!("Expected literal to determine array length");
856        };
857
858        let array_type = &array.elem;
859        let handle = generate_code_for_handling_field(
860            read,
861            array_type,
862            field_name,
863            bits_count,
864            None,
865            None,
866            None,
867            is_dynamic_int,
868            val_dyn_length,
869            false,
870            false,
871            level + 1,
872        );
873
874        let array_name = format_ident!("__val_{}", level);
875
876        if read {
877            quote! {
878                let mut #array_name = Vec::<#array_type>::with_capacity(#len);
879                for _ in 0..#len {
880                    #handle;
881                    #array_name.push(_p_val);
882                }
883                let _p_val = TryInto::<[#array_type; #len]>::try_into(#array_name).expect("Failed to convert Vec to array");
884            }
885        } else {
886            quote! {
887                for _p_val in _p_val {
888                    #handle
889                }
890            }
891        }
892    } else {
893        panic!("Field type of '{:?}' not supported", field_name);
894    }
895}
896
897fn generate_error_type(read: bool) -> proc_macro2::TokenStream {
898    if read {
899        quote! { binary_codec::DeserializationError }
900    } else {
901        quote! { binary_codec::SerializationError }
902    }
903}
904
905fn generate_size_key(length_by: Option<String>, has_dynamic_length: bool) -> (bool, proc_macro2::TokenStream) {
906    if let Some(length_by) = length_by.as_ref() {
907        (true, quote! { Some(#length_by) })
908    } else if has_dynamic_length {
909        (true, quote! { Some("__dynamic") })
910    } else {
911        (false, quote! { None })
912    }
913}
914
915fn get_string_value_from_attribute(
916    attr: &Attribute
917) -> Option<String> {
918    match &attr.meta {
919        syn::Meta::Path(_) => {
920            None
921        }
922        syn::Meta::List(list_value) => {
923            // #[myattribute("value")]
924            for token in list_value.tokens.clone().into_iter() {
925                if let proc_macro2::TokenTree::Literal(lit) = token {
926                    return Some(lit.to_string().trim_matches('"').to_string());
927                }
928            }
929
930            None
931        }
932        syn::Meta::NameValue(name_value) => {
933            if let syn::Expr::Lit(lit_expr) = &name_value.value {
934                if let Lit::Str(lit_str) = &lit_expr.lit {
935                    return Some(lit_str.value());
936                }
937            }
938
939            None
940        }
941    }
942}
943
944fn get_int_value_from_attribute(attr: &Attribute) -> Option<i32> {
945    match &attr.meta {
946        syn::Meta::Path(_) => {
947            None
948        }
949        syn::Meta::List(list_value) => {
950            // #[myattribute(value)]
951            for token in list_value.tokens.clone().into_iter() {
952                if let proc_macro2::TokenTree::Literal(lit) = token {
953                    if let Ok(val) = lit.to_string().parse::<i32>() {
954                        return Some(val);
955                    }
956                }
957            }
958
959            None
960        }
961        syn::Meta::NameValue(name_value) => {
962            if let syn::Expr::Lit(lit_expr) = &name_value.value {
963                if let Lit::Int(lit_int) = &lit_expr.lit {
964                    return Some(lit_int.base10_parse().expect("Not a valid int value"));
965                }
966            }
967
968            None
969        }
970    }
971}
972
973fn get_inner_type(path: &syn::Path) -> Option<&syn::Type> {
974    if let Some(PathArguments::AngleBracketed(args)) =
975        path.segments.last().map(|seg| &seg.arguments)
976    {
977        if let Some(arg) = args.args.first() {
978            if let syn::GenericArgument::Type(inner_type) = arg {
979                return Some(inner_type);
980            }
981        }
982    }
983
984    None
985}
986
987fn get_two_types(path: &syn::Path) -> Option<(&syn::Type, &syn::Type)> {
988    if let Some(PathArguments::AngleBracketed(args)) =
989        path.segments.last().map(|seg| &seg.arguments)
990    {
991        let mut types = args.args.iter().filter_map(|arg| {
992            if let syn::GenericArgument::Type(inner_type) = arg {
993                Some(inner_type)
994            } else {
995                None
996            }
997        });
998
999        if let (Some(t1), Some(t2)) = (types.next(), types.next()) {
1000            return Some((t1, t2));
1001        }
1002    }
1003
1004    None
1005}
1006
1007fn generate_dynint(read: bool) -> proc_macro2::TokenStream {
1008    if read {
1009        quote! {
1010            let _p_dyn = binary_codec::dyn_int::read_dynint(_p_bytes, _p_config)?;
1011        }
1012    } else {
1013        quote! {
1014            binary_codec::dyn_int::write_dynint(_p_dyn, _p_bytes, _p_config)?;
1015        }
1016    }
1017}