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