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