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