senax_encoder_derive/
lib.rs

1extern crate proc_macro;
2
3use crc::{Crc, CRC_64_ECMA_182};
4use itertools::izip;
5use proc_macro::TokenStream;
6use proc_macro2::Span;
7use quote::quote;
8use std::collections::{HashMap, HashSet};
9use syn::{
10    parse_macro_input, Attribute, Data, DeriveInput, Fields, GenericArgument, Ident, PathArguments,
11    Type,
12};
13
14/// CRC-64 hasher for field name to ID conversion
15const CRC64: Crc<u64> = Crc::<u64>::new(&CRC_64_ECMA_182);
16
17/// Calculate a unique field ID from a field name using CRC-64
18///
19/// This function generates a deterministic 64-bit ID from a field name by computing
20/// the CRC-64 hash. This ensures consistent field IDs across compilation runs
21/// while providing excellent distribution and minimizing collision probability.
22///
23/// # Arguments
24///
25/// * `name` - The field name to hash
26///
27/// # Returns
28///
29/// A 64-bit field ID (never 0, as 0 is reserved as a terminator)
30fn calculate_id_from_name(name: &str) -> u64 {
31    let crc64_hash = CRC64.checksum(name.as_bytes());
32    // Ensure it's not 0 (0 is reserved as terminator)
33    if crc64_hash == 0 {
34        u64::MAX
35    } else {
36        crc64_hash
37    }
38}
39
40/// Field attributes parsed from `#[senax(...)]` annotations
41///
42/// This struct represents the various attributes that can be applied to fields
43/// in structs and enum variants using the `#[senax(...)]` attribute macro.
44///
45/// # Fields
46///
47/// * `id` - The unique identifier for this field (computed from name or explicitly set)
48/// * `default` - Whether to use default values when the field is missing during decode
49/// * `skip_encode` - Whether to exclude this field from encoding
50/// * `skip_decode` - Whether to ignore this field during decoding
51/// * `skip_default` - Whether to use default value if field is missing
52/// * `rename` - Optional alternative name for ID calculation (maintains compatibility when renaming)
53#[derive(Debug, Clone)]
54#[allow(dead_code)] // The rename field is used indirectly in ID calculation
55struct FieldAttributes {
56    id: u64,
57    default: bool,
58    skip_encode: bool,
59    skip_decode: bool,
60    skip_default: bool,
61    rename: Option<String>,
62}
63
64/// Extract and parse `#[senax(...)]` attribute values from field attributes
65///
66/// This function parses the senax attributes applied to a field and returns
67/// a `FieldAttributes` struct containing all the parsed values.
68///
69/// # Arguments
70///
71/// * `attrs` - The attributes array from the field
72/// * `field_name` - The name of the field (used for ID calculation if no explicit ID is provided)
73///
74/// # Returns
75///
76/// A `FieldAttributes` struct with parsed values. If no explicit ID is provided,
77/// the ID is calculated using CRC64 hash of either the rename value or the field name.
78///
79/// # Supported Attributes
80///
81/// * `#[senax(id=1234)]` - Explicit field ID
82/// * `#[senax(default)]` - Use default value if field is missing during decode
83/// * `#[senax(skip_encode)]` - Skip this field during encoding
84/// * `#[senax(skip_decode)]` - Skip this field during decoding
85/// * `#[senax(skip_default)]` - Skip encoding if field value is default, use default if missing during decode
86/// * `#[senax(rename="name")]` - Alternative name for ID calculation
87///
88/// Multiple attributes can be combined: `#[senax(id=123, default, skip_encode)]`
89fn get_field_attributes(attrs: &[Attribute], field_name: &str) -> FieldAttributes {
90    let mut id = None;
91    let mut default = false;
92    let mut skip_encode = false;
93    let mut skip_decode = false;
94    let mut skip_default = false;
95    let mut rename = None;
96
97    for attr in attrs {
98        if attr.path().is_ident("senax") {
99            // Try to parse #[senax(id=1234, default, skip_encode, skip_decode, skip_default, rename="name")]
100            let parsed = attr.parse_args_with(|input: syn::parse::ParseStream| {
101                let mut parsed_id = None;
102                let mut parsed_default = false;
103                let mut parsed_skip_encode = false;
104                let mut parsed_skip_decode = false;
105                let mut parsed_skip_default = false;
106                let mut parsed_rename = None;
107
108                while !input.is_empty() {
109                    let ident = input.parse::<syn::Ident>()?;
110
111                    if ident == "id" {
112                        input.parse::<syn::Token![=]>()?;
113                        let lit = input.parse::<syn::LitInt>()?;
114                        if let Ok(id_val) = lit.base10_parse::<u64>() {
115                            if id_val == 0 {
116                                return Err(syn::Error::new(
117                                    lit.span(),
118                                    "Field ID 0 is reserved as a terminator",
119                                ));
120                            }
121                            parsed_id = Some(id_val);
122                        } else {
123                            return Err(syn::Error::new(lit.span(), "Failed to parse ID value"));
124                        }
125                    } else if ident == "default" {
126                        parsed_default = true;
127                    } else if ident == "skip_encode" {
128                        parsed_skip_encode = true;
129                    } else if ident == "skip_decode" {
130                        parsed_skip_decode = true;
131                    } else if ident == "skip_default" {
132                        parsed_skip_default = true;
133                    } else if ident == "rename" {
134                        input.parse::<syn::Token![=]>()?;
135                        let lit_str = input.parse::<syn::LitStr>()?;
136                        parsed_rename = Some(lit_str.value());
137                    } else {
138                        return Err(syn::Error::new(
139                            ident.span(),
140                            format!("Unknown attribute: {}", ident),
141                        ));
142                    }
143
144                    // Consume comma if present, otherwise end
145                    if input.peek(syn::Token![,]) {
146                        input.parse::<syn::Token![,]>()?;
147                    }
148                }
149
150                Ok((
151                    parsed_id,
152                    parsed_default,
153                    parsed_skip_encode,
154                    parsed_skip_decode,
155                    parsed_skip_default,
156                    parsed_rename,
157                ))
158            });
159
160            if let Ok((
161                parsed_id,
162                parsed_default,
163                parsed_skip_encode,
164                parsed_skip_decode,
165                parsed_skip_default,
166                parsed_rename,
167            )) = parsed
168            {
169                if let Some(id_val) = parsed_id {
170                    id = Some(id_val);
171                }
172                default = default || parsed_default;
173                skip_encode = skip_encode || parsed_skip_encode;
174                skip_decode = skip_decode || parsed_skip_decode;
175                skip_default = skip_default || parsed_skip_default;
176                if let Some(rename_val) = parsed_rename {
177                    rename = Some(rename_val);
178                }
179            } else {
180                eprintln!(
181                    "Warning: #[senax(...)] attribute for field '{}' is not in the correct format.",
182                    field_name
183                );
184            }
185        }
186    }
187
188    // ID calculation: Use explicit ID if provided, otherwise calculate CRC64 from rename or field name
189    let calculated_id = id.unwrap_or_else(|| {
190        let name_for_id = if let Some(ref rename_val) = rename {
191            rename_val.as_str()
192        } else {
193            field_name
194        };
195        calculate_id_from_name(name_for_id)
196    });
197
198    FieldAttributes {
199        id: calculated_id,
200        default,
201        skip_encode,
202        skip_decode,
203        skip_default,
204        rename,
205    }
206}
207
208/// Check if a type is `Option<T>`
209///
210/// This helper function determines whether a given type is wrapped in an `Option`.
211fn is_option_type(ty: &Type) -> bool {
212    if let Type::Path(type_path) = ty {
213        type_path
214            .path
215            .segments
216            .last()
217            .map_or(false, |seg| seg.ident == "Option")
218    } else {
219        false
220    }
221}
222
223/// Extract the inner type `T` from `Option<T>`
224///
225/// This helper function extracts the wrapped type from an `Option` type.
226/// Returns `None` if the type is not an `Option`.
227fn extract_inner_type_from_option(ty: &Type) -> Option<&Type> {
228    if let Type::Path(type_path) = ty {
229        if type_path
230            .path
231            .segments
232            .last()
233            .map_or(false, |seg| seg.ident == "Option")
234        {
235            if let PathArguments::AngleBracketed(args) =
236                &type_path.path.segments.last().unwrap().arguments
237            {
238                if let Some(GenericArgument::Type(inner_ty)) = args.args.first() {
239                    return Some(inner_ty);
240                }
241            }
242        }
243    }
244    None
245}
246
247/// Derive macro for implementing the `Encode` trait
248///
249/// This procedural macro automatically generates an implementation of the `Encode` trait
250/// for structs and enums. It supports various field attributes for customizing the
251/// encoding behavior.
252///
253/// # Supported Attributes
254///
255/// * `#[senax(id=N)]` - Set explicit field/variant ID
256/// * `#[senax(skip_encode)]` - Skip field during encoding
257/// * `#[senax(rename="name")]` - Use alternative name for ID calculation
258///
259/// # Examples
260///
261/// ```rust
262/// #[derive(Encode)]
263/// struct MyStruct {
264///     #[senax(id=1)]
265///     field1: i32,
266///     #[senax(skip_encode)]
267///     field2: String,
268/// }
269/// ```
270#[proc_macro_derive(Encode, attributes(senax))]
271pub fn derive_encode(input: TokenStream) -> TokenStream {
272    let input = parse_macro_input!(input as DeriveInput);
273    let name = &input.ident;
274    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
275
276    let encode_fields = match &input.data {
277        Data::Struct(s) => match &s.fields {
278            Fields::Named(fields) => {
279                let mut field_encode = Vec::new();
280                let mut used_ids_struct = HashSet::new();
281                for f in &fields.named {
282                    let field_name_str = f.ident.as_ref().unwrap().to_string();
283                    let field_attrs = get_field_attributes(&f.attrs, &field_name_str);
284
285                    // Skip fields marked with skip_encode
286                    if field_attrs.skip_encode {
287                        continue;
288                    }
289
290                    if !used_ids_struct.insert(field_attrs.id) {
291                        panic!("Field ID (0x{:016X}) is duplicated for struct '{}'. Please specify a different ID for field '{}' using #[senax(id=...)].", field_attrs.id, name, field_name_str);
292                    }
293
294                    let field_ident = &f.ident;
295                    let ty = &f.ty;
296                    let is_option = is_option_type(ty);
297                    let field_id = field_attrs.id;
298
299                    if is_option {
300                        field_encode.push(quote! {
301                            if let Some(val) = &self.#field_ident {
302                                senax_encoder::write_field_id_optimized(writer, #field_id)?;
303                                val.encode(writer)?;
304                            }
305                        });
306                    } else if field_attrs.skip_default {
307                        // For skip_default fields, check if the value is default before encoding
308                        field_encode.push(quote! {
309                            if !self.#field_ident.is_default() {
310                                senax_encoder::write_field_id_optimized(writer, #field_id)?;
311                                self.#field_ident.encode(writer)?;
312                            }
313                        });
314                    } else {
315                        field_encode.push(quote! {
316                            senax_encoder::write_field_id_optimized(writer, #field_id)?;
317                            self.#field_ident.encode(writer)?;
318                        });
319                    }
320                }
321                quote! {
322                    writer.put_u8(senax_encoder::TAG_STRUCT_NAMED);
323                    #(#field_encode)*
324                    senax_encoder::write_field_id_optimized(writer, 0)?;
325                }
326            }
327            Fields::Unnamed(fields) => {
328                let field_count = fields.unnamed.len();
329                let field_encode = fields.unnamed.iter().enumerate().map(|(i, _)| {
330                    let index = syn::Index::from(i);
331                    quote! {
332                        self.#index.encode(writer)?;
333                    }
334                });
335                quote! {
336                    writer.put_u8(senax_encoder::TAG_STRUCT_UNNAMED);
337                    let count: usize = #field_count;
338                    count.encode(writer)?;
339                    #(#field_encode)*
340                }
341            }
342            Fields::Unit => quote! {
343                writer.put_u8(senax_encoder::TAG_STRUCT_UNIT);
344            },
345        },
346        Data::Enum(e) => {
347            let mut variant_encode = Vec::new();
348            let mut used_ids_enum = HashSet::new();
349
350            for v in &e.variants {
351                let variant_name_str = v.ident.to_string();
352                let variant_attrs = get_field_attributes(&v.attrs, &variant_name_str);
353                let variant_id = variant_attrs.id;
354
355                if !used_ids_enum.insert(variant_id) {
356                    panic!("Variant ID (0x{:016X}) is duplicated for enum '{}'. Please specify a different ID for variant '{}' using #[senax(id=...)].", variant_id, name, variant_name_str);
357                }
358
359                let variant_ident = &v.ident;
360                match &v.fields {
361                    Fields::Named(fields) => {
362                        let field_idents: Vec<_> = fields
363                            .named
364                            .iter()
365                            .map(|f| f.ident.as_ref().unwrap())
366                            .collect();
367                        let mut field_encode = Vec::new();
368                        let mut used_ids_struct = HashSet::new();
369                        for f in &fields.named {
370                            let field_name_str = f.ident.as_ref().unwrap().to_string();
371                            let field_attrs = get_field_attributes(&f.attrs, &field_name_str);
372
373                            // Skip fields marked with skip_encode
374                            if field_attrs.skip_encode {
375                                continue;
376                            }
377
378                            if !used_ids_struct.insert(field_attrs.id) {
379                                panic!("Field ID (0x{:016X}) is duplicated for enum variant '{}'. Please specify a different ID for field '{}' using #[senax(id=...)].", field_attrs.id, variant_ident, field_name_str);
380                            }
381                            let field_ident = &f.ident;
382                            let ty = &f.ty;
383                            let is_option = is_option_type(ty);
384                            let field_id = field_attrs.id;
385                            if is_option {
386                                field_encode.push(quote! {
387                                    if let Some(val) = #field_ident {
388                                        senax_encoder::write_field_id_optimized(writer, #field_id)?;
389                                        val.encode(writer)?;
390                                    }
391                                });
392                            } else if field_attrs.skip_default {
393                                // For skip_default fields, check if the value is default before encoding
394                                field_encode.push(quote! {
395                                    if !#field_ident.is_default() {
396                                        senax_encoder::write_field_id_optimized(writer, #field_id)?;
397                                        #field_ident.encode(writer)?;
398                                    }
399                                });
400                            } else {
401                                field_encode.push(quote! {
402                                    senax_encoder::write_field_id_optimized(writer, #field_id)?;
403                                    #field_ident.encode(writer)?;
404                                });
405                            }
406                        }
407                        variant_encode.push(quote! {
408                            #name::#variant_ident { #(#field_idents),* } => {
409                                writer.put_u8(senax_encoder::TAG_ENUM_NAMED);
410                                senax_encoder::write_field_id_optimized(writer, #variant_id)?;
411                                #(#field_encode)*
412                                senax_encoder::write_field_id_optimized(writer, 0)?;
413                            }
414                        });
415                    }
416                    Fields::Unnamed(fields) => {
417                        let field_count = fields.unnamed.len();
418                        let field_bindings: Vec<_> = (0..field_count)
419                            .map(|i| Ident::new(&format!("field{}", i), Span::call_site()))
420                            .collect();
421                        let field_bindings_ref = &field_bindings;
422                        variant_encode.push(quote! {
423                            #name::#variant_ident( #(#field_bindings_ref),* ) => {
424                                writer.put_u8(senax_encoder::TAG_ENUM_UNNAMED);
425                                senax_encoder::write_field_id_optimized(writer, #variant_id)?;
426                                let count: usize = #field_count;
427                                count.encode(writer)?;
428                                #(
429                                    #field_bindings_ref.encode(writer)?;
430                                )*
431                            }
432                        });
433                    }
434                    Fields::Unit => {
435                        variant_encode.push(quote! {
436                            #name::#variant_ident => {
437                                writer.put_u8(senax_encoder::TAG_ENUM);
438                                senax_encoder::write_field_id_optimized(writer, #variant_id)?;
439                            }
440                        });
441                    }
442                }
443            }
444            quote! {
445                match self {
446                    #(#variant_encode)*
447                }
448            }
449        }
450        Data::Union(_) => unimplemented!("Unions are not supported"),
451    };
452
453    TokenStream::from(quote! {
454        impl #impl_generics senax_encoder::Encoder for #name #ty_generics #where_clause {
455            fn encode(&self, writer: &mut bytes::BytesMut) -> senax_encoder::Result<()> {
456                use bytes::{Buf, BufMut};
457                #encode_fields
458                Ok(())
459            }
460
461            fn is_default(&self) -> bool {
462                false // Structs and enums always return false
463            }
464        }
465    })
466}
467
468/// Derive macro for implementing the `Decode` trait
469///
470/// This procedural macro automatically generates an implementation of the `Decode` trait
471/// for structs and enums. It supports various field attributes for customizing the
472/// decoding behavior and provides forward/backward compatibility.
473///
474/// # Supported Attributes
475///
476/// * `#[senax(id=N)]` - Set explicit field/variant ID
477/// * `#[senax(default)]` - Use default value if field is missing
478/// * `#[senax(skip_decode)]` - Skip field during decoding (use default value)
479/// * `#[senax(skip_default)]` - Use default value if field is missing (same as default for decode)
480/// * `#[senax(rename="name")]` - Use alternative name for ID calculation
481///
482/// # Examples
483///
484/// ```rust
485/// #[derive(Decode)]
486/// struct MyStruct {
487///     #[senax(id=1)]
488///     field1: i32,
489///     #[senax(default)]
490///     field2: String,
491///     #[senax(skip_decode)]
492///     field3: bool,
493/// }
494/// ```
495#[proc_macro_derive(Decode, attributes(senax))]
496pub fn derive_decode(input: TokenStream) -> TokenStream {
497    let input = parse_macro_input!(input as DeriveInput);
498    let name = &input.ident;
499    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
500
501    let decode_fields = match &input.data {
502        Data::Struct(s) => match &s.fields {
503            Fields::Named(fields) => {
504                let mut field_idents = Vec::new();
505                let mut field_original_types = Vec::new();
506                let mut field_ids_for_match = Vec::new();
507                let mut field_is_option_flags = Vec::new();
508                let mut field_attrs_list = Vec::new();
509                let mut used_ids_struct_decode = HashMap::new();
510
511                for f in &fields.named {
512                    let field_name_str = f.ident.as_ref().unwrap().to_string();
513                    let field_attrs = get_field_attributes(&f.attrs, &field_name_str);
514
515                    if let Some(dup_field_name) =
516                        used_ids_struct_decode.insert(field_attrs.id, field_name_str.clone())
517                    {
518                        panic!("Field ID (0x{:016X}) is duplicated for struct '{}'. Please specify a different ID for field '{}' and '{}' using #[senax(id=...)].", 
519                              field_attrs.id, name, dup_field_name, field_name_str);
520                    }
521
522                    field_idents.push(f.ident.as_ref().unwrap().clone());
523                    field_original_types.push(f.ty.clone());
524                    field_ids_for_match.push(field_attrs.id);
525                    field_is_option_flags.push(is_option_type(&f.ty));
526                    field_attrs_list.push(field_attrs);
527                }
528
529                let field_value_definitions = field_idents
530                    .iter()
531                    .zip(field_original_types.iter())
532                    .zip(field_attrs_list.iter())
533                    .filter_map(|((ident, original_ty), attrs)| {
534                        if attrs.skip_decode {
535                            // Fields marked with skip_decode don't store values
536                            None
537                        } else if is_option_type(original_ty) {
538                            Some(quote! { #ident: #original_ty, })
539                        } else {
540                            Some(quote! { #ident: Option<#original_ty>, })
541                        }
542                    });
543
544                let match_arms = field_idents
545                    .iter()
546                    .zip(field_original_types.iter())
547                    .zip(field_ids_for_match.iter())
548                    .zip(field_attrs_list.iter())
549                    .filter_map(|(((ident, original_ty), id_val), attrs)| {
550                        if attrs.skip_decode {
551                            // Fields marked with skip_decode don't generate match arms (values are skipped)
552                            None
553                        } else if is_option_type(original_ty) {
554                            let inner_ty = extract_inner_type_from_option(original_ty)
555                                .unwrap_or_else(|| {
556                                    panic!(
557                                        "Failed to extract inner type from Option for field {}",
558                                        ident
559                                    )
560                                });
561                            Some(quote! {
562                                x if x == #id_val => {
563                                    field_values.#ident = Some(<#inner_ty>::decode(reader)?);
564                                }
565                            })
566                        } else {
567                            Some(quote! {
568                                x if x == #id_val => {
569                                    field_values.#ident = Some(<#original_ty>::decode(reader)?);
570                                }
571                            })
572                        }
573                    });
574
575                let struct_assignments = field_idents.iter()
576                    .zip(field_is_option_flags.iter())
577                    .zip(field_attrs_list.iter())
578                    .map(|((ident, is_opt_flag), attrs)| {
579                        if attrs.skip_decode {
580                            // Fields marked with skip_decode use default values
581                            quote! {
582                                #ident: Default::default(),
583                            }
584                        } else if *is_opt_flag {
585                            quote! {
586                                #ident: field_values.#ident,
587                            }
588                        } else if attrs.default || attrs.skip_default {
589                            // Fields marked with default or skip_default use default value if missing
590                            quote! {
591                                #ident: field_values.#ident.unwrap_or_default(),
592                            }
593                        } else {
594                            quote! {
595                                #ident: field_values.#ident.ok_or_else(||
596                                    senax_encoder::EncoderError::Decode(format!("Required field '{}' not found for struct {}", stringify!(#ident), stringify!(#name)))
597                                )?,
598                            }
599                        }
600                    });
601
602                quote! {
603                    if reader.remaining() == 0 {
604                        return Err(senax_encoder::EncoderError::InsufficientData);
605                    }
606                    let tag = reader.get_u8();
607                    if tag != senax_encoder::TAG_STRUCT_NAMED {
608                        return Err(senax_encoder::EncoderError::Decode(format!("Expected struct named tag ({}), got {}", senax_encoder::TAG_STRUCT_NAMED, tag)));
609                    }
610
611                    #[derive(Default)]
612                    struct FieldValues {
613                        #( #field_value_definitions )*
614                    }
615
616                    let mut field_values = FieldValues::default();
617
618                    loop {
619                        let field_id = senax_encoder::read_field_id_optimized(reader)?;
620                        if field_id == 0 {
621                            break;
622                        }
623                        match field_id {
624                            #( #match_arms )*
625                            _unknown_id => { senax_encoder::skip_value(reader)?; }
626                        }
627                    }
628
629                    Ok(#name {
630                        #( #struct_assignments )*
631                    })
632                }
633            }
634            Fields::Unnamed(fields) => {
635                let field_count = fields.unnamed.len();
636                let field_deencode = fields.unnamed.iter().map(|f| {
637                    let field_ty = &f.ty;
638                    quote! {
639                        <#field_ty>::decode(reader)?
640                    }
641                });
642                quote! {
643                    if reader.remaining() == 0 {
644                        return Err(senax_encoder::EncoderError::InsufficientData);
645                    }
646                    let tag = reader.get_u8();
647                    if tag != senax_encoder::TAG_STRUCT_UNNAMED {
648                        return Err(senax_encoder::EncoderError::Decode(format!("Expected struct unnamed tag ({}), got {}", senax_encoder::TAG_STRUCT_UNNAMED, tag)));
649                    }
650                    let count = <usize>::decode(reader)?;
651                    if count != #field_count {
652                        return Err(senax_encoder::EncoderError::Decode(format!("Field count mismatch for struct {}: expected {}, got {}", stringify!(#name), #field_count, count)));
653                    }
654                    Ok(#name(
655                        #(#field_deencode),*
656                    ))
657                }
658            }
659            Fields::Unit => quote! {
660                if reader.remaining() == 0 {
661                    return Err(senax_encoder::EncoderError::InsufficientData);
662                }
663                let tag = reader.get_u8();
664                if tag != senax_encoder::TAG_STRUCT_UNIT {
665                    return Err(senax_encoder::EncoderError::Decode(format!("Expected struct unit tag ({}), got {}", senax_encoder::TAG_STRUCT_UNIT, tag)));
666                }
667                Ok(#name)
668            },
669        },
670        Data::Enum(e) => {
671            let mut unit_variant_arms = Vec::new();
672            let mut named_variant_arms = Vec::new();
673            let mut unnamed_variant_arms = Vec::new();
674            let mut used_ids_enum_decode = HashMap::new();
675
676            for v in &e.variants {
677                let variant_name_str = v.ident.to_string();
678                let variant_attrs = get_field_attributes(&v.attrs, &variant_name_str);
679                let variant_id = variant_attrs.id;
680
681                if let Some(dup_variant) =
682                    used_ids_enum_decode.insert(variant_id, variant_name_str.clone())
683                {
684                    panic!("Variant ID (0x{:016X}) is duplicated for enum '{}'. Please specify a different ID for variant '{}' and '{}' using #[senax(id=...)].", 
685                          variant_id, name, dup_variant, variant_name_str);
686                }
687
688                let variant_ident = &v.ident;
689                match &v.fields {
690                    Fields::Named(fields) => {
691                        let field_idents: Vec<_> = fields
692                            .named
693                            .iter()
694                            .map(|f| f.ident.as_ref().unwrap().clone())
695                            .collect();
696                        let field_types: Vec<_> =
697                            fields.named.iter().map(|f| f.ty.clone()).collect();
698                        let field_attrs_list: Vec<_> = fields
699                            .named
700                            .iter()
701                            .map(|f| {
702                                get_field_attributes(
703                                    &f.attrs,
704                                    &f.ident.as_ref().unwrap().to_string(),
705                                )
706                            })
707                            .collect();
708
709                        let mut field_value_definitions_enum = Vec::new();
710                        let mut match_arms_enum_named = Vec::new();
711                        let mut struct_assignments_enum_named = Vec::new();
712
713                        for (ident, ty, attrs) in izip!(
714                            field_idents.iter(),
715                            field_types.iter(),
716                            field_attrs_list.iter()
717                        ) {
718                            if attrs.skip_decode {
719                                // Fields marked with skip_decode don't store values
720                            } else if is_option_type(ty) {
721                                field_value_definitions_enum.push(quote! { #ident: #ty, });
722                            } else {
723                                field_value_definitions_enum.push(quote! { #ident: Option<#ty>, });
724                            }
725
726                            if attrs.skip_decode {
727                                // Fields marked with skip_decode don't generate match arms
728                            } else if is_option_type(ty) {
729                                let inner_ty = extract_inner_type_from_option(ty).unwrap();
730                                let field_id = attrs.id;
731                                match_arms_enum_named.push(quote! {
732                                    x if x == #field_id => { field_values.#ident = Some(<#inner_ty>::decode(reader)?); }
733                                });
734                            } else {
735                                let field_id = attrs.id;
736                                match_arms_enum_named.push(quote! {
737                                    x if x == #field_id => { field_values.#ident = Some(<#ty>::decode(reader)?); }
738                                });
739                            }
740
741                            if attrs.skip_decode {
742                                // Fields marked with skip_decode use default values
743                                struct_assignments_enum_named
744                                    .push(quote! { #ident: Default::default(), });
745                            } else if is_option_type(ty) {
746                                struct_assignments_enum_named
747                                    .push(quote! { #ident: field_values.#ident, });
748                            } else if attrs.default || attrs.skip_default {
749                                // Fields marked with default or skip_default use default value if missing
750                                struct_assignments_enum_named.push(quote! {
751                                    #ident: field_values.#ident.unwrap_or_default(),
752                                });
753                            } else {
754                                struct_assignments_enum_named.push(quote! {
755                                    #ident: field_values.#ident.ok_or_else(|| senax_encoder::EncoderError::Decode(format!("Required field '{}' not found for variant {}::{}", stringify!(#ident), stringify!(#name), stringify!(#variant_ident))))?,
756                                });
757                            }
758                        }
759
760                        named_variant_arms.push(quote! {
761                            x if x == #variant_id => {
762                                #[derive(Default)]
763                                struct FieldValues { #(#field_value_definitions_enum)* }
764                                let mut field_values = FieldValues::default();
765                                loop {
766                                    let field_id = {
767                                        if reader.remaining() == 0 { break; }
768                                        let id = senax_encoder::read_field_id_optimized(reader)?;
769                                        if id == 0 { break; }
770                                        id
771                                    };
772                                    match field_id {
773                                        #(#match_arms_enum_named)*
774                                        _unknown_id => { senax_encoder::skip_value(reader)?; }
775                                    }
776                                }
777                                Ok(#name::#variant_ident { #(#struct_assignments_enum_named)* })
778                            }
779                        });
780                    }
781                    Fields::Unnamed(fields) => {
782                        let field_types: Vec<_> = fields.unnamed.iter().map(|f| &f.ty).collect();
783                        let field_count = field_types.len();
784                        unnamed_variant_arms.push(quote! {
785                            x if x == #variant_id => {
786                                let count = <usize>::decode(reader)?;
787                                if count != #field_count {
788                                    return Err(senax_encoder::EncoderError::Decode(format!("Field count mismatch for variant {}::{}: expected {}, got {}", stringify!(#name), stringify!(#variant_ident), #field_count, count)));
789                                }
790                                Ok(#name::#variant_ident(
791                                    #(
792                                        <#field_types>::decode(reader)?,
793                                    )*
794                                ))
795                            }
796                        });
797                    }
798                    Fields::Unit => {
799                        unit_variant_arms.push(quote! {
800                            x if x == #variant_id => {
801                                Ok(#name::#variant_ident)
802                            }
803                        });
804                    }
805                }
806            }
807            quote! {
808                if reader.remaining() == 0 {
809                    return Err(senax_encoder::EncoderError::InsufficientData);
810                }
811                let tag = reader.get_u8();
812                match tag {
813                    senax_encoder::TAG_ENUM => {
814                        let variant_id = senax_encoder::read_field_id_optimized(reader)?;
815                        match variant_id {
816                            #(#unit_variant_arms)*
817                            _ => Err(senax_encoder::EncoderError::Decode(format!("Unknown unit variant ID: 0x{:016X} for enum {}", variant_id, stringify!(#name))))
818                        }
819                    }
820                    senax_encoder::TAG_ENUM_NAMED => {
821                        let variant_id = senax_encoder::read_field_id_optimized(reader)?;
822                        match variant_id {
823                            #(#named_variant_arms)*
824                            _ => Err(senax_encoder::EncoderError::Decode(format!("Unknown named variant ID: 0x{:016X} for enum {}", variant_id, stringify!(#name))))
825                        }
826                    }
827                    senax_encoder::TAG_ENUM_UNNAMED => {
828                        let variant_id = senax_encoder::read_field_id_optimized(reader)?;
829                        match variant_id {
830                             #(#unnamed_variant_arms)*
831                            _ => Err(senax_encoder::EncoderError::Decode(format!("Unknown unnamed variant ID: 0x{:016X} for enum {}", variant_id, stringify!(#name))))
832                        }
833                    }
834                    unknown_tag => Err(senax_encoder::EncoderError::Decode(format!("Unknown enum tag: {} for enum {}", unknown_tag, stringify!(#name))))
835                }
836            }
837        }
838        Data::Union(_) => unimplemented!("Unions are not supported"),
839    };
840
841    TokenStream::from(quote! {
842        impl #impl_generics senax_encoder::Decoder for #name #ty_generics #where_clause {
843            fn decode(reader: &mut bytes::Bytes) -> senax_encoder::Result<Self> {
844                use bytes::{Buf, BufMut};
845                #decode_fields
846            }
847        }
848    })
849}