senax_encoder_derive/
lib.rs

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