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/// Generate structure information text for CRC64 hashing
41///
42/// This function creates a deterministic text representation of the structure
43/// that includes type name, field names, and field types. This is used to
44/// generate a structure hash for pack format validation.
45///
46/// # Arguments
47///
48/// * `input` - The parsed derive input containing structure information
49///
50/// # Returns
51///
52/// A string containing the structure information
53fn generate_structure_info(input: &DeriveInput) -> String {
54    let mut info = String::new();
55    info.push_str(&format!("type:{}", input.ident));
56
57    match &input.data {
58        Data::Struct(s) => {
59            info.push_str("|struct");
60            match &s.fields {
61                Fields::Named(fields) => {
62                    info.push_str("|named");
63                    for field in &fields.named {
64                        let field_name = field.ident.as_ref().unwrap().to_string();
65                        let field_type = {
66                            let ty = &field.ty;
67                            quote!(#ty).to_string()
68                        };
69                        info.push_str(&format!("|{}:{}", field_name, field_type));
70                    }
71                }
72                Fields::Unnamed(fields) => {
73                    info.push_str("|unnamed");
74                    for (i, field) in fields.unnamed.iter().enumerate() {
75                        let field_type = {
76                            let ty = &field.ty;
77                            quote!(#ty).to_string()
78                        };
79                        info.push_str(&format!("|{}:{}", i, field_type));
80                    }
81                }
82                Fields::Unit => {
83                    info.push_str("|unit");
84                }
85            }
86        }
87        Data::Enum(e) => {
88            info.push_str("|enum");
89            for variant in &e.variants {
90                let variant_name = variant.ident.to_string();
91                info.push_str(&format!("|variant:{}", variant_name));
92                match &variant.fields {
93                    Fields::Named(fields) => {
94                        info.push_str("|named");
95                        for field in &fields.named {
96                            let field_name = field.ident.as_ref().unwrap().to_string();
97                            let field_type = {
98                                let ty = &field.ty;
99                                quote!(#ty).to_string()
100                            };
101                            info.push_str(&format!("|{}:{}", field_name, field_type));
102                        }
103                    }
104                    Fields::Unnamed(fields) => {
105                        info.push_str("|unnamed");
106                        for (i, field) in fields.unnamed.iter().enumerate() {
107                            let field_type = {
108                                let ty = &field.ty;
109                                quote!(#ty).to_string()
110                            };
111                            info.push_str(&format!("|{}:{}", i, field_type));
112                        }
113                    }
114                    Fields::Unit => {
115                        info.push_str("|unit");
116                    }
117                }
118            }
119        }
120        Data::Union(_) => {
121            info.push_str("|union");
122        }
123    }
124
125    info
126}
127
128/// Check if a variant has the #[default] attribute
129fn has_default_attribute(attrs: &[Attribute]) -> bool {
130    attrs.iter().any(|attr| attr.path().is_ident("default"))
131}
132
133/// Field attributes parsed from `#[senax(...)]` annotations
134///
135/// This struct represents the various attributes that can be applied to fields
136/// in structs and enum variants using the `#[senax(...)]` attribute macro.
137///
138/// # Fields
139///
140/// * `id` - The unique identifier for this field (computed from name or explicitly set)
141/// * `default` - Whether to use default values when the field is missing during decode
142/// * `skip_encode` - Whether to exclude this field from encoding
143/// * `skip_decode` - Whether to ignore this field during decoding
144/// * `skip_default` - Whether to use default value if field is missing
145/// * `rename` - Optional alternative name for ID calculation (maintains compatibility when renaming)
146#[derive(Debug, Clone)]
147#[allow(dead_code)] // The rename field is used indirectly in ID calculation
148struct FieldAttributes {
149    id: u64,
150    default: bool,
151    skip_encode: bool,
152    skip_decode: bool,
153    skip_default: bool,
154    rename: Option<String>,
155}
156
157/// Extract and parse `#[senax(...)]` attribute values from field attributes
158///
159/// This function parses the senax attributes applied to a field and returns
160/// a `FieldAttributes` struct containing all the parsed values.
161///
162/// # Arguments
163///
164/// * `attrs` - The attributes array from the field
165/// * `field_name` - The name of the field (used for ID calculation if no explicit ID is provided)
166///
167/// # Returns
168///
169/// A `FieldAttributes` struct with parsed values. If no explicit ID is provided,
170/// the ID is calculated using CRC64 hash of either the rename value or the field name.
171///
172/// # Supported Attributes
173///
174/// * `#[senax(id=1234)]` - Explicit field ID
175/// * `#[senax(default)]` - Use default value if field is missing during decode
176/// * `#[senax(skip_encode)]` - Skip this field during encoding
177/// * `#[senax(skip_decode)]` - Skip this field during decoding
178/// * `#[senax(skip_default)]` - Skip encoding if field value is default, use default if missing during decode
179/// * `#[senax(rename="name")]` - Alternative name for ID calculation
180///
181/// Multiple attributes can be combined: `#[senax(id=123, default, skip_encode)]`
182fn get_field_attributes(attrs: &[Attribute], field_name: &str) -> FieldAttributes {
183    let mut id = None;
184    let mut default = false;
185    let mut skip_encode = false;
186    let mut skip_decode = false;
187    let mut skip_default = false;
188    let mut rename = None;
189
190    for attr in attrs {
191        if attr.path().is_ident("senax") {
192            // Try to parse #[senax(id=1234, default, skip_encode, skip_decode, skip_default, rename="name")]
193            let parsed = attr.parse_args_with(|input: syn::parse::ParseStream| {
194                let mut parsed_id = None;
195                let mut parsed_default = false;
196                let mut parsed_skip_encode = false;
197                let mut parsed_skip_decode = false;
198                let mut parsed_skip_default = false;
199                let mut parsed_rename = None;
200
201                while !input.is_empty() {
202                    let ident = input.parse::<syn::Ident>()?;
203
204                    if ident == "id" {
205                        input.parse::<syn::Token![=]>()?;
206                        let lit = input.parse::<syn::LitInt>()?;
207                        if let Ok(id_val) = lit.base10_parse::<u64>() {
208                            if id_val == 0 {
209                                return Err(syn::Error::new(
210                                    lit.span(),
211                                    "Field ID 0 is reserved as a terminator",
212                                ));
213                            }
214                            parsed_id = Some(id_val);
215                        } else {
216                            return Err(syn::Error::new(lit.span(), "Failed to parse ID value"));
217                        }
218                    } else if ident == "default" {
219                        parsed_default = true;
220                    } else if ident == "skip_encode" {
221                        parsed_skip_encode = true;
222                    } else if ident == "skip_decode" {
223                        parsed_skip_decode = true;
224                    } else if ident == "skip_default" {
225                        parsed_skip_default = true;
226                    } else if ident == "rename" {
227                        input.parse::<syn::Token![=]>()?;
228                        let lit_str = input.parse::<syn::LitStr>()?;
229                        parsed_rename = Some(lit_str.value());
230                    } else {
231                        return Err(syn::Error::new(
232                            ident.span(),
233                            format!("Unknown attribute: {}", ident),
234                        ));
235                    }
236
237                    // Consume comma if present, otherwise end
238                    if input.peek(syn::Token![,]) {
239                        input.parse::<syn::Token![,]>()?;
240                    }
241                }
242
243                Ok((
244                    parsed_id,
245                    parsed_default,
246                    parsed_skip_encode,
247                    parsed_skip_decode,
248                    parsed_skip_default,
249                    parsed_rename,
250                ))
251            });
252
253            if let Ok((
254                parsed_id,
255                parsed_default,
256                parsed_skip_encode,
257                parsed_skip_decode,
258                parsed_skip_default,
259                parsed_rename,
260            )) = parsed
261            {
262                if let Some(id_val) = parsed_id {
263                    id = Some(id_val);
264                }
265                default = default || parsed_default;
266                skip_encode = skip_encode || parsed_skip_encode;
267                skip_decode = skip_decode || parsed_skip_decode;
268                skip_default = skip_default || parsed_skip_default;
269                if let Some(rename_val) = parsed_rename {
270                    rename = Some(rename_val);
271                }
272            } else {
273                eprintln!(
274                    "Warning: #[senax(...)] attribute for field '{}' is not in the correct format.",
275                    field_name
276                );
277            }
278        }
279    }
280
281    // ID calculation: Use explicit ID if provided, otherwise calculate CRC64 from rename or field name
282    let calculated_id = id.unwrap_or_else(|| {
283        let name_for_id = if let Some(ref rename_val) = rename {
284            rename_val.as_str()
285        } else {
286            field_name
287        };
288        calculate_id_from_name(name_for_id)
289    });
290
291    FieldAttributes {
292        id: calculated_id,
293        default,
294        skip_encode,
295        skip_decode,
296        skip_default,
297        rename,
298    }
299}
300
301/// Check if a type is `Option<T>`
302///
303/// This helper function determines whether a given type is wrapped in an `Option`.
304fn is_option_type(ty: &Type) -> bool {
305    if let Type::Path(type_path) = ty {
306        type_path
307            .path
308            .segments
309            .last()
310            .is_some_and(|seg| seg.ident == "Option")
311    } else {
312        false
313    }
314}
315
316/// Extract the inner type `T` from `Option<T>`
317///
318/// This helper function extracts the wrapped type from an `Option` type.
319/// Returns `None` if the type is not an `Option`.
320fn extract_inner_type_from_option(ty: &Type) -> Option<&Type> {
321    if let Type::Path(type_path) = ty {
322        if type_path
323            .path
324            .segments
325            .last()
326            .is_some_and(|seg| seg.ident == "Option")
327        {
328            if let PathArguments::AngleBracketed(args) =
329                &type_path.path.segments.last().unwrap().arguments
330            {
331                if let Some(GenericArgument::Type(inner_ty)) = args.args.first() {
332                    return Some(inner_ty);
333                }
334            }
335        }
336    }
337    None
338}
339
340/// Derive macro for implementing the `Encode` trait
341///
342/// This procedural macro automatically generates an implementation of the `Encode` trait
343/// for structs and enums. It supports various field attributes for customizing the
344/// encoding behavior.
345///
346/// # Supported Attributes
347///
348/// * `#[senax(id=N)]` - Set explicit field/variant ID
349/// * `#[senax(skip_encode)]` - Skip field during encoding
350/// * `#[senax(rename="name")]` - Use alternative name for ID calculation
351///
352/// # Examples
353///
354/// ```rust
355/// #[derive(Encode)]
356/// struct MyStruct {
357///     #[senax(id=1)]
358///     field1: i32,
359///     #[senax(skip_encode)]
360///     field2: String,
361/// }
362/// ```
363#[proc_macro_derive(Encode, attributes(senax))]
364pub fn derive_encode(input: TokenStream) -> TokenStream {
365    let input = parse_macro_input!(input as DeriveInput);
366    let name = &input.ident;
367    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
368
369    let mut default_variant_checks = Vec::new();
370
371    let encode_fields = match &input.data {
372        Data::Struct(s) => match &s.fields {
373            Fields::Named(fields) => {
374                let mut field_encode = Vec::new();
375                let mut used_ids_struct = HashSet::new();
376                for f in &fields.named {
377                    let field_name_str = f.ident.as_ref().unwrap().to_string();
378                    let field_attrs = get_field_attributes(&f.attrs, &field_name_str);
379
380                    // Skip fields marked with skip_encode
381                    if field_attrs.skip_encode {
382                        continue;
383                    }
384
385                    if !used_ids_struct.insert(field_attrs.id) {
386                        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);
387                    }
388
389                    let field_ident = &f.ident;
390                    let ty = &f.ty;
391                    let is_option = is_option_type(ty);
392                    let field_id = field_attrs.id;
393
394                    if is_option {
395                        field_encode.push(quote! {
396                            if let Some(val) = &self.#field_ident {
397                                senax_encoder::core::write_field_id_optimized(writer, #field_id)?;
398                                senax_encoder::Encoder::encode(&val, writer)?;
399                            }
400                        });
401                    } else if field_attrs.skip_default {
402                        // For skip_default fields, check if the value is default before encoding
403                        field_encode.push(quote! {
404                            if senax_encoder::Encoder::is_default(&self.#field_ident) == false {
405                                senax_encoder::core::write_field_id_optimized(writer, #field_id)?;
406                                senax_encoder::Encoder::encode(&self.#field_ident, writer)?;
407                            }
408                        });
409                    } else {
410                        field_encode.push(quote! {
411                            senax_encoder::core::write_field_id_optimized(writer, #field_id)?;
412                            senax_encoder::Encoder::encode(&self.#field_ident, writer)?;
413                        });
414                    }
415                }
416                quote! {
417                    writer.put_u8(senax_encoder::core::TAG_STRUCT_NAMED);
418                    #(#field_encode)*
419                    senax_encoder::core::write_field_id_optimized(writer, 0)?;
420                }
421            }
422            Fields::Unnamed(fields) => {
423                let field_count = fields.unnamed.len();
424                let field_encode = fields.unnamed.iter().enumerate().map(|(i, _)| {
425                    let index = syn::Index::from(i);
426                    quote! {
427                        senax_encoder::Encoder::encode(&self.#index, writer)?;
428                    }
429                });
430                quote! {
431                    writer.put_u8(senax_encoder::core::TAG_STRUCT_UNNAMED);
432                    let count: usize = #field_count;
433                    senax_encoder::Encoder::encode(&count, writer)?;
434                    #(#field_encode)*
435                }
436            }
437            Fields::Unit => quote! {
438                writer.put_u8(senax_encoder::core::TAG_STRUCT_UNIT);
439            },
440        },
441        Data::Enum(e) => {
442            let mut variant_encode = Vec::new();
443            let mut used_ids_enum = HashSet::new();
444
445            for v in &e.variants {
446                let variant_name_str = v.ident.to_string();
447                let variant_attrs = get_field_attributes(&v.attrs, &variant_name_str);
448                let variant_id = variant_attrs.id;
449                let is_default_variant = has_default_attribute(&v.attrs);
450
451                if !used_ids_enum.insert(variant_id) {
452                    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);
453                }
454
455                let variant_ident = &v.ident;
456
457                // Generate is_default check for this variant if it has #[default] attribute
458                if is_default_variant {
459                    match &v.fields {
460                        Fields::Named(fields) => {
461                            let field_idents: Vec<_> = fields
462                                .named
463                                .iter()
464                                .map(|f| f.ident.as_ref().unwrap())
465                                .collect();
466                            let field_default_checks: Vec<_> = field_idents
467                                .iter()
468                                .map(|ident| {
469                                    quote! { senax_encoder::Encoder::is_default(#ident) }
470                                })
471                                .collect();
472
473                            if field_default_checks.is_empty() {
474                                default_variant_checks.push(quote! {
475                                    #name::#variant_ident { .. } => true,
476                                });
477                            } else {
478                                default_variant_checks.push(quote! {
479                                    #name::#variant_ident { #(#field_idents),* } => {
480                                        #(#field_default_checks)&&*
481                                    },
482                                });
483                            }
484                        }
485                        Fields::Unnamed(fields) => {
486                            let field_count = fields.unnamed.len();
487                            let field_bindings: Vec<_> = (0..field_count)
488                                .map(|i| Ident::new(&format!("field{}", i), Span::call_site()))
489                                .collect();
490                            let field_default_checks: Vec<_> = field_bindings
491                                .iter()
492                                .map(|binding| {
493                                    quote! { senax_encoder::Encoder::is_default(#binding) }
494                                })
495                                .collect();
496
497                            if field_default_checks.is_empty() {
498                                default_variant_checks.push(quote! {
499                                    #name::#variant_ident(..) => true,
500                                });
501                            } else {
502                                default_variant_checks.push(quote! {
503                                    #name::#variant_ident(#(#field_bindings),*) => {
504                                        #(#field_default_checks)&&*
505                                    },
506                                });
507                            }
508                        }
509                        Fields::Unit => {
510                            default_variant_checks.push(quote! {
511                                #name::#variant_ident => true,
512                            });
513                        }
514                    }
515                }
516
517                match &v.fields {
518                    Fields::Named(fields) => {
519                        let field_idents: Vec<_> = fields
520                            .named
521                            .iter()
522                            .map(|f| f.ident.as_ref().unwrap())
523                            .collect();
524                        let mut field_encode = Vec::new();
525                        let mut used_ids_struct = HashSet::new();
526                        for f in &fields.named {
527                            let field_name_str = f.ident.as_ref().unwrap().to_string();
528                            let field_attrs = get_field_attributes(&f.attrs, &field_name_str);
529
530                            // Skip fields marked with skip_encode
531                            if field_attrs.skip_encode {
532                                continue;
533                            }
534
535                            if !used_ids_struct.insert(field_attrs.id) {
536                                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);
537                            }
538                            let field_ident = &f.ident;
539                            let ty = &f.ty;
540                            let is_option = is_option_type(ty);
541                            let field_id = field_attrs.id;
542                            if is_option {
543                                field_encode.push(quote! {
544                                    if let Some(val) = #field_ident {
545                                        senax_encoder::core::write_field_id_optimized(writer, #field_id)?;
546                                        senax_encoder::Encoder::encode(&val, writer)?;
547                                    }
548                                });
549                            } else if field_attrs.skip_default {
550                                // For skip_default fields, check if the value is default before encoding
551                                field_encode.push(quote! {
552                                    if senax_encoder::Encoder::is_default(#field_ident) == false {
553                                        senax_encoder::core::write_field_id_optimized(writer, #field_id)?;
554                                        senax_encoder::Encoder::encode(&#field_ident, writer)?;
555                                    }
556                                });
557                            } else {
558                                field_encode.push(quote! {
559                                    senax_encoder::core::write_field_id_optimized(writer, #field_id)?;
560                                    senax_encoder::Encoder::encode(&#field_ident, writer)?;
561                                });
562                            }
563                        }
564                        variant_encode.push(quote! {
565                            #name::#variant_ident { #(#field_idents),* } => {
566                                writer.put_u8(senax_encoder::core::TAG_ENUM_NAMED);
567                                senax_encoder::core::write_field_id_optimized(writer, #variant_id)?;
568                                #(#field_encode)*
569                                senax_encoder::core::write_field_id_optimized(writer, 0)?;
570                            }
571                        });
572                    }
573                    Fields::Unnamed(fields) => {
574                        let field_count = fields.unnamed.len();
575                        let field_bindings: Vec<_> = (0..field_count)
576                            .map(|i| Ident::new(&format!("field{}", i), Span::call_site()))
577                            .collect();
578                        let field_bindings_ref = &field_bindings;
579                        variant_encode.push(quote! {
580                            #name::#variant_ident( #(#field_bindings_ref),* ) => {
581                                writer.put_u8(senax_encoder::core::TAG_ENUM_UNNAMED);
582                                senax_encoder::core::write_field_id_optimized(writer, #variant_id)?;
583                                let count: usize = #field_count;
584                                senax_encoder::Encoder::encode(&count, writer)?;
585                                #(
586                                    senax_encoder::Encoder::encode(&#field_bindings_ref, writer)?;
587                                )*
588                            }
589                        });
590                    }
591                    Fields::Unit => {
592                        variant_encode.push(quote! {
593                            #name::#variant_ident => {
594                                writer.put_u8(senax_encoder::core::TAG_ENUM);
595                                senax_encoder::core::write_field_id_optimized(writer, #variant_id)?;
596                            }
597                        });
598                    }
599                }
600            }
601            quote! {
602                match self {
603                    #(#variant_encode)*
604                }
605            }
606        }
607        Data::Union(_) => unimplemented!("Unions are not supported"),
608    };
609
610    let is_default_impl = match &input.data {
611        Data::Enum(_) => {
612            if default_variant_checks.is_empty() {
613                quote! { false }
614            } else {
615                quote! {
616                    match self {
617                        #(#default_variant_checks)*
618                        _ => false,
619                    }
620                }
621            }
622        }
623        _ => quote! { false },
624    };
625
626    let encode_method = quote! {
627        fn encode(&self, writer: &mut bytes::BytesMut) -> senax_encoder::Result<()> {
628            use bytes::{Buf, BufMut};
629            #encode_fields
630            Ok(())
631        }
632
633        fn is_default(&self) -> bool {
634            #is_default_impl
635        }
636    };
637
638    TokenStream::from(quote! {
639        impl #impl_generics senax_encoder::Encoder for #name #ty_generics #where_clause {
640            #encode_method
641        }
642    })
643}
644
645/// Derive macro for implementing the `Decode` trait
646///
647/// This procedural macro automatically generates an implementation of the `Decode` trait
648/// for structs and enums. It supports various field attributes for customizing the
649/// decoding behavior and provides forward/backward compatibility.
650///
651/// # Supported Attributes
652///
653/// * `#[senax(id=N)]` - Set explicit field/variant ID
654/// * `#[senax(default)]` - Use default value if field is missing
655/// * `#[senax(skip_decode)]` - Skip field during decoding (use default value)
656/// * `#[senax(skip_default)]` - Use default value if field is missing (same as default for decode)
657/// * `#[senax(rename="name")]` - Use alternative name for ID calculation
658///
659/// # Examples
660///
661/// ```rust
662/// #[derive(Decode)]
663/// struct MyStruct {
664///     #[senax(id=1)]
665///     field1: i32,
666///     #[senax(default)]
667///     field2: String,
668///     #[senax(skip_decode)]
669///     field3: bool,
670/// }
671/// ```
672#[proc_macro_derive(Decode, attributes(senax))]
673pub fn derive_decode(input: TokenStream) -> TokenStream {
674    let input = parse_macro_input!(input as DeriveInput);
675    let name = &input.ident;
676    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
677
678    let decode_fields = match &input.data {
679        Data::Struct(s) => match &s.fields {
680            Fields::Named(fields) => {
681                let mut field_idents = Vec::new();
682                let mut field_original_types = Vec::new();
683                let mut field_ids_for_match = Vec::new();
684                let mut field_is_option_flags = Vec::new();
685                let mut field_attrs_list = Vec::new();
686                let mut used_ids_struct_decode = HashMap::new();
687
688                for f in &fields.named {
689                    let field_name_str = f.ident.as_ref().unwrap().to_string();
690                    let field_attrs = get_field_attributes(&f.attrs, &field_name_str);
691
692                    if let Some(dup_field_name) =
693                        used_ids_struct_decode.insert(field_attrs.id, field_name_str.clone())
694                    {
695                        panic!("Field ID (0x{:016X}) is duplicated for struct '{}'. Please specify a different ID for field '{}' and '{}' using #[senax(id=...)].", 
696                              field_attrs.id, name, dup_field_name, field_name_str);
697                    }
698
699                    field_idents.push(f.ident.as_ref().unwrap().clone());
700                    field_original_types.push(f.ty.clone());
701                    field_ids_for_match.push(field_attrs.id);
702                    field_is_option_flags.push(is_option_type(&f.ty));
703                    field_attrs_list.push(field_attrs);
704                }
705
706                let field_value_definitions = field_idents
707                    .iter()
708                    .zip(field_original_types.iter())
709                    .zip(field_attrs_list.iter())
710                    .filter_map(|((ident, original_ty), attrs)| {
711                        if attrs.skip_decode {
712                            // Fields marked with skip_decode don't store values
713                            None
714                        } else if is_option_type(original_ty) {
715                            Some(quote! { #ident: #original_ty, })
716                        } else {
717                            Some(quote! { #ident: Option<#original_ty>, })
718                        }
719                    });
720
721                let match_arms = field_idents
722                    .iter()
723                    .zip(field_original_types.iter())
724                    .zip(field_ids_for_match.iter())
725                    .zip(field_attrs_list.iter())
726                    .filter_map(|(((ident, original_ty), id_val), attrs)| {
727                        if attrs.skip_decode {
728                            // Fields marked with skip_decode don't generate match arms (values are skipped)
729                            None
730                        } else if is_option_type(original_ty) {
731                            let inner_ty = extract_inner_type_from_option(original_ty)
732                                .unwrap_or_else(|| {
733                                    panic!(
734                                        "Failed to extract inner type from Option for field {}",
735                                        ident
736                                    )
737                                });
738                            Some(quote! {
739                                x if x == #id_val => {
740                                    field_values.#ident = Some(<#inner_ty as senax_encoder::Decoder>::decode(reader)?);
741                                }
742                            })
743                        } else {
744                            Some(quote! {
745                                x if x == #id_val => {
746                                    field_values.#ident = Some(<#original_ty as senax_encoder::Decoder>::decode(reader)?);
747                                }
748                            })
749                        }
750                    });
751
752                let struct_assignments = field_idents
753                    .iter()
754                    .zip(field_is_option_flags.iter())
755                    .zip(field_attrs_list.iter())
756                    .map(|((ident, is_opt_flag), attrs)| {
757                        if attrs.skip_decode {
758                            // Fields marked with skip_decode use default values
759                            quote! {
760                                #ident: Default::default(),
761                            }
762                        } else if *is_opt_flag {
763                            quote! {
764                                #ident: field_values.#ident,
765                            }
766                        } else if attrs.default || attrs.skip_default {
767                            // Fields marked with default or skip_default use default value if missing
768                            quote! {
769                                #ident: field_values.#ident.unwrap_or_default(),
770                            }
771                        } else {
772                            quote! {
773                                #ident: field_values.#ident.ok_or_else(||
774                                    senax_encoder::EncoderError::StructDecode(
775                                        senax_encoder::StructDecodeError::MissingRequiredField {
776                                            field: stringify!(#ident),
777                                            struct_name: stringify!(#name),
778                                        }
779                                    )
780                                )?,
781                            }
782                        }
783                    });
784
785                quote! {
786                    if reader.remaining() == 0 {
787                        return Err(senax_encoder::EncoderError::InsufficientData);
788                    }
789                    let tag = reader.get_u8();
790                    if tag != senax_encoder::core::TAG_STRUCT_NAMED {
791                        return Err(senax_encoder::EncoderError::StructDecode(
792                            senax_encoder::StructDecodeError::InvalidTag {
793                                expected: senax_encoder::core::TAG_STRUCT_NAMED,
794                                actual: tag,
795                            }
796                        ));
797                    }
798
799                    #[derive(Default)]
800                    struct FieldValues {
801                        #( #field_value_definitions )*
802                    }
803
804                    let mut field_values = FieldValues::default();
805
806                    loop {
807                        let field_id = senax_encoder::core::read_field_id_optimized(reader)?;
808                        if field_id == 0 {
809                            break;
810                        }
811                        match field_id {
812                            #( #match_arms )*
813                            _unknown_id => { senax_encoder::core::skip_value(reader)?; }
814                        }
815                    }
816
817                    Ok(#name {
818                        #( #struct_assignments )*
819                    })
820                }
821            }
822            Fields::Unnamed(fields) => {
823                let field_count = fields.unnamed.len();
824                let field_decode = fields.unnamed.iter().map(|f| {
825                    let field_ty = &f.ty;
826                    quote! {
827                        <#field_ty as senax_encoder::Decoder>::decode(reader)?
828                    }
829                });
830                quote! {
831                    if reader.remaining() == 0 {
832                        return Err(senax_encoder::EncoderError::InsufficientData);
833                    }
834                    let tag = reader.get_u8();
835                    if tag != senax_encoder::core::TAG_STRUCT_UNNAMED {
836                        return Err(senax_encoder::EncoderError::StructDecode(
837                            senax_encoder::StructDecodeError::InvalidTag {
838                                expected: senax_encoder::core::TAG_STRUCT_UNNAMED,
839                                actual: tag,
840                            }
841                        ));
842                    }
843                    let count = <usize as senax_encoder::Decoder>::decode(reader)?;
844                    if count != #field_count {
845                        return Err(senax_encoder::EncoderError::StructDecode(
846                            senax_encoder::StructDecodeError::FieldCountMismatch {
847                                struct_name: stringify!(#name),
848                                expected: #field_count,
849                                actual: count,
850                            }
851                        ));
852                    }
853                    Ok(#name(
854                        #(#field_decode),*
855                    ))
856                }
857            }
858            Fields::Unit => quote! {
859                if reader.remaining() == 0 {
860                    return Err(senax_encoder::EncoderError::InsufficientData);
861                }
862                let tag = reader.get_u8();
863                if tag != senax_encoder::core::TAG_STRUCT_UNIT {
864                    return Err(senax_encoder::EncoderError::StructDecode(
865                        senax_encoder::StructDecodeError::InvalidTag {
866                            expected: senax_encoder::core::TAG_STRUCT_UNIT,
867                            actual: tag,
868                        }
869                    ));
870                }
871                Ok(#name)
872            },
873        },
874        Data::Enum(e) => {
875            let mut unit_variant_arms = Vec::new();
876            let mut named_variant_arms = Vec::new();
877            let mut unnamed_variant_arms = Vec::new();
878            let mut used_ids_enum_decode = HashMap::new();
879
880            for v in &e.variants {
881                let variant_name_str = v.ident.to_string();
882                let variant_attrs = get_field_attributes(&v.attrs, &variant_name_str);
883                let variant_id = variant_attrs.id;
884
885                if let Some(dup_variant) =
886                    used_ids_enum_decode.insert(variant_id, variant_name_str.clone())
887                {
888                    panic!("Variant ID (0x{:016X}) is duplicated for enum '{}'. Please specify a different ID for variant '{}' and '{}' using #[senax(id=...)].", 
889                          variant_id, name, dup_variant, variant_name_str);
890                }
891
892                let variant_ident = &v.ident;
893                match &v.fields {
894                    Fields::Named(fields) => {
895                        let field_idents: Vec<_> = fields
896                            .named
897                            .iter()
898                            .map(|f| f.ident.as_ref().unwrap().clone())
899                            .collect();
900                        let field_types: Vec<_> =
901                            fields.named.iter().map(|f| f.ty.clone()).collect();
902                        let field_attrs_list: Vec<_> = fields
903                            .named
904                            .iter()
905                            .map(|f| {
906                                get_field_attributes(
907                                    &f.attrs,
908                                    &f.ident.as_ref().unwrap().to_string(),
909                                )
910                            })
911                            .collect();
912
913                        let mut field_value_definitions_enum = Vec::new();
914                        let mut match_arms_enum_named = Vec::new();
915                        let mut struct_assignments_enum_named = Vec::new();
916
917                        for (ident, ty, attrs) in izip!(
918                            field_idents.iter(),
919                            field_types.iter(),
920                            field_attrs_list.iter()
921                        ) {
922                            if attrs.skip_decode {
923                                // Fields marked with skip_decode don't store values
924                            } else if is_option_type(ty) {
925                                field_value_definitions_enum.push(quote! { #ident: #ty, });
926                            } else {
927                                field_value_definitions_enum.push(quote! { #ident: Option<#ty>, });
928                            }
929
930                            if attrs.skip_decode {
931                                // Fields marked with skip_decode don't generate match arms
932                            } else if is_option_type(ty) {
933                                let inner_ty = extract_inner_type_from_option(ty).unwrap();
934                                let field_id = attrs.id;
935                                match_arms_enum_named.push(quote! {
936                                    x if x == #field_id => { field_values.#ident = Some(<#inner_ty as senax_encoder::Decoder>::decode(reader)?); }
937                                });
938                            } else {
939                                let field_id = attrs.id;
940                                match_arms_enum_named.push(quote! {
941                                    x if x == #field_id => { field_values.#ident = Some(<#ty as senax_encoder::Decoder>::decode(reader)?); }
942                                });
943                            }
944
945                            if attrs.skip_decode {
946                                // Fields marked with skip_decode use default values
947                                struct_assignments_enum_named
948                                    .push(quote! { #ident: Default::default(), });
949                            } else if is_option_type(ty) {
950                                struct_assignments_enum_named
951                                    .push(quote! { #ident: field_values.#ident, });
952                            } else if attrs.default || attrs.skip_default {
953                                // Fields marked with default or skip_default use default value if missing
954                                struct_assignments_enum_named.push(quote! {
955                                    #ident: field_values.#ident.unwrap_or_default(),
956                                });
957                            } else {
958                                struct_assignments_enum_named.push(quote! {
959                                    #ident: field_values.#ident.ok_or_else(||
960                                        senax_encoder::EncoderError::EnumDecode(
961                                            senax_encoder::EnumDecodeError::MissingRequiredField {
962                                                field: stringify!(#ident),
963                                                enum_name: stringify!(#name),
964                                                variant_name: stringify!(#variant_ident),
965                                            }
966                                        )
967                                    )?,
968                                });
969                            }
970                        }
971
972                        named_variant_arms.push(quote! {
973                            x if x == #variant_id => {
974                                #[derive(Default)]
975                                struct FieldValues { #(#field_value_definitions_enum)* }
976                                let mut field_values = FieldValues::default();
977                                loop {
978                                    let field_id = {
979                                        if reader.remaining() == 0 { break; }
980                                        let id = senax_encoder::core::read_field_id_optimized(reader)?;
981                                        if id == 0 { break; }
982                                        id
983                                    };
984                                    match field_id {
985                                        #(#match_arms_enum_named)*
986                                        _unknown_id => { senax_encoder::core::skip_value(reader)?; }
987                                    }
988                                }
989                                Ok(#name::#variant_ident { #(#struct_assignments_enum_named)* })
990                            }
991                        });
992                    }
993                    Fields::Unnamed(fields) => {
994                        let field_types: Vec<_> = fields.unnamed.iter().map(|f| &f.ty).collect();
995                        let field_count = field_types.len();
996                        unnamed_variant_arms.push(quote! {
997                            x if x == #variant_id => {
998                                let count = <usize as senax_encoder::Decoder>::decode(reader)?;
999                                if count != #field_count {
1000                                    return Err(senax_encoder::EncoderError::EnumDecode(
1001                                        senax_encoder::EnumDecodeError::FieldCountMismatch {
1002                                            enum_name: stringify!(#name),
1003                                            variant_name: stringify!(#variant_ident),
1004                                            expected: #field_count,
1005                                            actual: count,
1006                                        }
1007                                    ));
1008                                }
1009                                Ok(#name::#variant_ident(
1010                                    #(
1011                                        <#field_types as senax_encoder::Decoder>::decode(reader)?,
1012                                    )*
1013                                ))
1014                            }
1015                        });
1016                    }
1017                    Fields::Unit => {
1018                        unit_variant_arms.push(quote! {
1019                            x if x == #variant_id => {
1020                                Ok(#name::#variant_ident)
1021                            }
1022                        });
1023                    }
1024                }
1025            }
1026            quote! {
1027                if reader.remaining() == 0 {
1028                    return Err(senax_encoder::EncoderError::InsufficientData);
1029                }
1030                let tag = reader.get_u8();
1031                match tag {
1032                    senax_encoder::core::TAG_ENUM => {
1033                        let variant_id = senax_encoder::core::read_field_id_optimized(reader)?;
1034                        match variant_id {
1035                            #(#unit_variant_arms)*
1036                            _ => Err(senax_encoder::EncoderError::EnumDecode(
1037                                senax_encoder::EnumDecodeError::UnknownVariantId {
1038                                    variant_id,
1039                                    enum_name: stringify!(#name),
1040                                }
1041                            ))
1042                        }
1043                    }
1044                    senax_encoder::core::TAG_ENUM_NAMED => {
1045                        let variant_id = senax_encoder::core::read_field_id_optimized(reader)?;
1046                        match variant_id {
1047                            #(#named_variant_arms)*
1048                            _ => Err(senax_encoder::EncoderError::EnumDecode(
1049                                senax_encoder::EnumDecodeError::UnknownVariantId {
1050                                    variant_id,
1051                                    enum_name: stringify!(#name),
1052                                }
1053                            ))
1054                        }
1055                    }
1056                    senax_encoder::core::TAG_ENUM_UNNAMED => {
1057                        let variant_id = senax_encoder::core::read_field_id_optimized(reader)?;
1058                        match variant_id {
1059                             #(#unnamed_variant_arms)*
1060                            _ => Err(senax_encoder::EncoderError::EnumDecode(
1061                                senax_encoder::EnumDecodeError::UnknownVariantId {
1062                                    variant_id,
1063                                    enum_name: stringify!(#name),
1064                                }
1065                            ))
1066                        }
1067                    }
1068                    unknown_tag => Err(senax_encoder::EncoderError::EnumDecode(
1069                        senax_encoder::EnumDecodeError::UnknownTag {
1070                            tag: unknown_tag,
1071                            enum_name: stringify!(#name),
1072                        }
1073                    ))
1074                }
1075            }
1076        }
1077        Data::Union(_) => unimplemented!("Unions are not supported"),
1078    };
1079
1080    let decode_method = quote! {
1081        fn decode(reader: &mut bytes::Bytes) -> senax_encoder::Result<Self> {
1082            use bytes::{Buf, BufMut};
1083            #decode_fields
1084        }
1085    };
1086
1087    TokenStream::from(quote! {
1088        impl #impl_generics senax_encoder::Decoder for #name #ty_generics #where_clause {
1089            #decode_method
1090        }
1091    })
1092}
1093
1094/// Derive macro for implementing the `Pack` trait (Packer only)
1095///
1096/// This procedural macro automatically generates an implementation of the `Packer` trait
1097/// for structs and enums. It provides compact serialization without field IDs for structs.
1098///
1099/// # Examples
1100///
1101/// ```rust
1102/// #[derive(Pack)]
1103/// struct MyStruct {
1104///     field1: i32,
1105///     field2: String,
1106/// }
1107/// ```
1108#[proc_macro_derive(Pack, attributes(senax))]
1109pub fn derive_pack(input: TokenStream) -> TokenStream {
1110    let input = parse_macro_input!(input as DeriveInput);
1111    let name = &input.ident;
1112    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
1113
1114    // Generate structure information and CRC64 hash for pack format
1115    let structure_info = generate_structure_info(&input);
1116    let structure_hash = CRC64.checksum(structure_info.as_bytes());
1117
1118    // Generate pack implementation for structs and enums (no field IDs for struct fields)
1119    let pack_fields = match &input.data {
1120        Data::Struct(s) => match &s.fields {
1121            Fields::Named(fields) => {
1122                let field_encode = fields.named.iter().map(|f| {
1123                    let field_ident = &f.ident;
1124                    quote! {
1125                        senax_encoder::Packer::pack(&self.#field_ident, writer)?;
1126                    }
1127                });
1128                quote! {
1129                    // Write structure hash first for named structs
1130                    writer.put_u64_le(#structure_hash);
1131                    #(#field_encode)*
1132                }
1133            }
1134            Fields::Unnamed(fields) => {
1135                let field_count = fields.unnamed.len();
1136                let field_encode = fields.unnamed.iter().enumerate().map(|(i, _)| {
1137                    let index = syn::Index::from(i);
1138                    quote! {
1139                        senax_encoder::Packer::pack(&self.#index, writer)?;
1140                    }
1141                });
1142                quote! {
1143                    // Write field count for unnamed structs
1144                    let count: usize = #field_count;
1145                    senax_encoder::Encoder::encode(&count, writer)?;
1146                    #(#field_encode)*
1147                }
1148            }
1149            Fields::Unit => quote! {
1150                // Unit structs don't need any additional data
1151            },
1152        },
1153        Data::Enum(e) => {
1154            let mut variant_pack = Vec::new();
1155            let mut used_ids_enum_pack = HashSet::new();
1156
1157            for v in &e.variants {
1158                let variant_name_str = v.ident.to_string();
1159                let variant_attrs = get_field_attributes(&v.attrs, &variant_name_str);
1160                let variant_id = variant_attrs.id;
1161
1162                if !used_ids_enum_pack.insert(variant_id) {
1163                    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);
1164                }
1165
1166                let variant_ident = &v.ident;
1167
1168                match &v.fields {
1169                    Fields::Named(fields) => {
1170                        let field_idents: Vec<_> = fields
1171                            .named
1172                            .iter()
1173                            .map(|f| f.ident.as_ref().unwrap())
1174                            .collect();
1175                        // For pack, encode fields in order without field IDs
1176                        let field_pack = field_idents.iter().map(|field_ident| {
1177                            quote! {
1178                                senax_encoder::Packer::pack(#field_ident, writer)?;
1179                            }
1180                        });
1181                        variant_pack.push(quote! {
1182                            #name::#variant_ident { #(#field_idents),* } => {
1183                                // Write variant ID first, then structure hash for named enums
1184                                senax_encoder::core::write_field_id_optimized(writer, #variant_id)?;
1185                                writer.put_u64_le(#structure_hash);
1186                                #(#field_pack)*
1187                            }
1188                        });
1189                    }
1190                    Fields::Unnamed(fields) => {
1191                        let field_count = fields.unnamed.len();
1192                        let field_bindings: Vec<_> = (0..field_count)
1193                            .map(|i| Ident::new(&format!("field{}", i), Span::call_site()))
1194                            .collect();
1195                        let field_bindings_ref = &field_bindings;
1196                        variant_pack.push(quote! {
1197                            #name::#variant_ident( #(#field_bindings_ref),* ) => {
1198                                // Write variant ID first, then field count for unnamed enums
1199                                senax_encoder::core::write_field_id_optimized(writer, #variant_id)?;
1200                                let count: usize = #field_count;
1201                                senax_encoder::Encoder::encode(&count, writer)?;
1202                                #(
1203                                    senax_encoder::Packer::pack(&#field_bindings_ref, writer)?;
1204                                )*
1205                            }
1206                        });
1207                    }
1208                    Fields::Unit => {
1209                        variant_pack.push(quote! {
1210                            #name::#variant_ident => {
1211                                // Unit enums only need variant ID
1212                                senax_encoder::core::write_field_id_optimized(writer, #variant_id)?;
1213                            }
1214                        });
1215                    }
1216                }
1217            }
1218            quote! {
1219                match self {
1220                    #(#variant_pack)*
1221                }
1222            }
1223        }
1224        Data::Union(_) => unimplemented!("Unions are not supported"),
1225    };
1226
1227    let pack_method = quote! {
1228        fn pack(&self, writer: &mut bytes::BytesMut) -> senax_encoder::Result<()> {
1229            use bytes::{Buf, BufMut};
1230            #pack_fields
1231            Ok(())
1232        }
1233    };
1234
1235    TokenStream::from(quote! {
1236        impl #impl_generics senax_encoder::Packer for #name #ty_generics #where_clause {
1237            #pack_method
1238        }
1239    })
1240}
1241
1242/// Derive macro for implementing the `Unpack` trait (Unpacker only)
1243///
1244/// This procedural macro automatically generates an implementation of the `Unpacker` trait
1245/// for structs and enums. It provides compact deserialization that matches the Pack format.
1246///
1247/// # Examples
1248///
1249/// ```rust
1250/// #[derive(Unpack)]
1251/// struct MyStruct {
1252///     field1: i32,
1253///     field2: String,
1254/// }
1255/// ```
1256#[proc_macro_derive(Unpack, attributes(senax))]
1257pub fn derive_unpack(input: TokenStream) -> TokenStream {
1258    let input = parse_macro_input!(input as DeriveInput);
1259    let name = &input.ident;
1260    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
1261
1262    // Generate structure information and CRC64 hash for pack format validation
1263    let structure_info = generate_structure_info(&input);
1264    let structure_hash = CRC64.checksum(structure_info.as_bytes());
1265
1266    // Generate unpack implementation for structs and enums (no field IDs for struct fields)
1267    let unpack_fields = match &input.data {
1268        Data::Struct(s) => match &s.fields {
1269            Fields::Named(fields) => {
1270                let field_assignments = fields.named.iter().map(|f| {
1271                    let field_ident = &f.ident;
1272                    let field_ty = &f.ty;
1273                    quote! {
1274                        #field_ident: <#field_ty as senax_encoder::Unpacker>::unpack(reader)?,
1275                    }
1276                });
1277                quote! {
1278                    // Read and validate structure hash for named structs
1279                    if reader.remaining() < 8 {
1280                        return Err(senax_encoder::EncoderError::InsufficientData);
1281                    }
1282                    let received_hash = reader.get_u64_le();
1283                    if received_hash != #structure_hash {
1284                        return Err(senax_encoder::EncoderError::StructDecode(
1285                            senax_encoder::StructDecodeError::StructureHashMismatch {
1286                                struct_name: stringify!(#name),
1287                                expected: #structure_hash,
1288                                actual: received_hash,
1289                            }
1290                        ));
1291                    }
1292
1293                    Ok(#name {
1294                        #(#field_assignments)*
1295                    })
1296                }
1297            }
1298            Fields::Unnamed(fields) => {
1299                let expected_field_count = fields.unnamed.len();
1300                let field_decode = fields.unnamed.iter().map(|f| {
1301                    let field_ty = &f.ty;
1302                    quote! {
1303                        <#field_ty as senax_encoder::Unpacker>::unpack(reader)?
1304                    }
1305                });
1306                quote! {
1307                    // Read and validate field count for unnamed structs
1308                    let field_count = <usize as senax_encoder::Decoder>::decode(reader)?;
1309                    if field_count != #expected_field_count {
1310                        return Err(senax_encoder::EncoderError::StructDecode(
1311                            senax_encoder::StructDecodeError::FieldCountMismatch {
1312                                struct_name: stringify!(#name),
1313                                expected: #expected_field_count,
1314                                actual: field_count,
1315                            }
1316                        ));
1317                    }
1318
1319                    Ok(#name(
1320                        #(#field_decode),*
1321                    ))
1322                }
1323            }
1324            Fields::Unit => quote! {
1325                // Unit structs don't need any additional data
1326                Ok(#name)
1327            },
1328        },
1329        Data::Enum(e) => {
1330            let mut variant_unpack = Vec::new();
1331            let mut used_ids_enum_unpack = HashSet::new();
1332
1333            for v in &e.variants {
1334                let variant_name_str = v.ident.to_string();
1335                let variant_attrs = get_field_attributes(&v.attrs, &variant_name_str);
1336                let variant_id = variant_attrs.id;
1337
1338                if !used_ids_enum_unpack.insert(variant_id) {
1339                    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);
1340                }
1341
1342                let variant_ident = &v.ident;
1343                match &v.fields {
1344                    Fields::Named(fields) => {
1345                        let field_idents: Vec<_> = fields
1346                            .named
1347                            .iter()
1348                            .map(|f| f.ident.as_ref().unwrap().clone())
1349                            .collect();
1350                        let field_types: Vec<_> =
1351                            fields.named.iter().map(|f| f.ty.clone()).collect();
1352
1353                        // For unpack, decode fields in order without expecting field IDs
1354                        let field_assignments =
1355                            field_idents
1356                                .iter()
1357                                .zip(field_types.iter())
1358                                .map(|(ident, ty)| {
1359                                    quote! {
1360                                        #ident: <#ty as senax_encoder::Unpacker>::unpack(reader)?,
1361                                    }
1362                                });
1363
1364                        variant_unpack.push(quote! {
1365                            x if x == #variant_id => {
1366                                // Read and validate structure hash for named variants
1367                                if reader.remaining() < 8 {
1368                                    return Err(senax_encoder::EncoderError::InsufficientData);
1369                                }
1370                                let received_hash = reader.get_u64_le();
1371                                if received_hash != #structure_hash {
1372                                    return Err(senax_encoder::EncoderError::EnumDecode(
1373                                        senax_encoder::EnumDecodeError::StructureHashMismatch {
1374                                            enum_name: stringify!(#name),
1375                                            variant_name: stringify!(#variant_ident),
1376                                            expected: #structure_hash,
1377                                            actual: received_hash,
1378                                        }
1379                                    ));
1380                                }
1381                                Ok(#name::#variant_ident { #(#field_assignments)* })
1382                            }
1383                        });
1384                    }
1385                    Fields::Unnamed(fields) => {
1386                        let field_types: Vec<_> = fields.unnamed.iter().map(|f| &f.ty).collect();
1387                        let expected_field_count = field_types.len();
1388                        variant_unpack.push(quote! {
1389                            x if x == #variant_id => {
1390                                // Read and validate field count for unnamed variants
1391                                let field_count = <usize as senax_encoder::Decoder>::decode(reader)?;
1392                                if field_count != #expected_field_count {
1393                                    return Err(senax_encoder::EncoderError::EnumDecode(
1394                                        senax_encoder::EnumDecodeError::FieldCountMismatch {
1395                                            enum_name: stringify!(#name),
1396                                            variant_name: stringify!(#variant_ident),
1397                                            expected: #expected_field_count,
1398                                            actual: field_count,
1399                                        }
1400                                    ));
1401                                }
1402                                Ok(#name::#variant_ident(
1403                                    #(
1404                                        <#field_types as senax_encoder::Unpacker>::unpack(reader)?,
1405                                    )*
1406                                ))
1407                            }
1408                        });
1409                    }
1410                    Fields::Unit => {
1411                        variant_unpack.push(quote! {
1412                            x if x == #variant_id => {
1413                                Ok(#name::#variant_ident)
1414                            }
1415                        });
1416                    }
1417                }
1418            }
1419
1420            // Now we can support mixed variants since variant ID comes first
1421            quote! {
1422                let variant_id = senax_encoder::core::read_field_id_optimized(reader)?;
1423                match variant_id {
1424                    #(#variant_unpack)*
1425                    _ => Err(senax_encoder::EncoderError::EnumDecode(
1426                        senax_encoder::EnumDecodeError::UnknownVariantId {
1427                            variant_id,
1428                            enum_name: stringify!(#name),
1429                        }
1430                    ))
1431                }
1432            }
1433        }
1434        Data::Union(_) => unimplemented!("Unions are not supported"),
1435    };
1436
1437    let unpack_method = quote! {
1438        fn unpack(reader: &mut bytes::Bytes) -> senax_encoder::Result<Self> {
1439            use bytes::{Buf, BufMut};
1440            #unpack_fields
1441        }
1442    };
1443
1444    TokenStream::from(quote! {
1445        impl #impl_generics senax_encoder::Unpacker for #name #ty_generics #where_clause {
1446            #unpack_method
1447        }
1448    })
1449}