1
use proc_macro2::{Span, TokenStream};
2
use quote::{quote, quote_spanned};
3
use syn::{spanned::Spanned, Data, DeriveInput, Fields, Ident, Meta, GenericParam, TypeParam, 
4
    WherePredicate, Type, TypeParamBound, TraitBound, Path, PathSegment, Generics, punctuated::Punctuated};
5

            
6
1464
pub(crate) fn has_skip_attr(field: &syn::Field) -> bool {
7
1492
    field.attrs.iter().any(|attr| {
8
56
        if attr.path().is_ident("jetstream") {
9
56
            if let Ok(()) = attr.parse_nested_meta(|meta| {
10
56
                if meta.path.is_ident("skip") {
11
8
                    Ok(())
12
                } else {
13
48
                    Err(meta.error("expected `skip`"))
14
                }
15
56
            }) {
16
8
                return true;
17
48
            }
18
        }
19
48
        false
20
1492
    })
21
1464
}
22

            
23
130
pub(crate) fn extract_jetstream_type(input: &DeriveInput) -> Option<Ident> {
24
670
    for attr in &input.attrs {
25
540
        if attr.path().is_ident("jetstream_type") {
26
            if let Ok(Meta::Path(path)) = attr.parse_args() {
27
                if let Some(ident) = path.get_ident() {
28
                    return Some(ident.clone());
29
                }
30
            }
31
540
        }
32
    }
33
130
    None
34
130
}
35

            
36
// Add WireFormat bounds to generic type parameters
37
8
pub(crate) fn add_wireformat_bounds(
38
8
    generics: &Generics,
39
8
    predicates: &mut Punctuated<WherePredicate, syn::token::Comma>,
40
8
) {
41
22
    for param in &generics.params {
42
14
        if let GenericParam::Type(TypeParam { ident, .. }) = param {
43
14
            let ty = Type::Path(syn::TypePath {
44
14
                qself: None,
45
14
                path: Path {
46
14
                    leading_colon: None,
47
14
                    segments: {
48
14
                        let mut segments = Punctuated::new();
49
14
                        segments.push(PathSegment {
50
14
                            ident: ident.clone(),
51
14
                            arguments: syn::PathArguments::None,
52
14
                        });
53
14
                        segments
54
14
                    },
55
14
                },
56
14
            });
57
14

            
58
14
            // Create the WireFormat trait bound
59
14
            let trait_path = syn::parse_str::<Path>("jetstream_wireformat::WireFormat").unwrap();
60
14
            let trait_bound = TypeParamBound::Trait(TraitBound {
61
14
                paren_token: None,
62
14
                modifier: syn::TraitBoundModifier::None,
63
14
                lifetimes: None,
64
14
                path: trait_path,
65
14
            });
66
14

            
67
14
            // Create the where predicate: T: WireFormat
68
14
            let mut bounds = Punctuated::new();
69
14
            bounds.push(trait_bound);
70
14
            
71
14
            let predicate = WherePredicate::Type(syn::PredicateType {
72
14
                lifetimes: None,
73
14
                bounded_ty: ty,
74
14
                colon_token: syn::token::Colon::default(),
75
14
                bounds,
76
14
            });
77
14
            
78
14
            predicates.push(predicate);
79
14
        }
80
    }
81
8
}
82

            
83
130
pub(crate) fn wire_format_inner(input: DeriveInput) -> TokenStream {
84
130
    let jetstream_type = extract_jetstream_type(&input);
85
130
    let container = input.ident.clone();
86
130
    
87
130
    // Extract generics information
88
130
    let generics = input.generics;
89
130
    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
90
    
91
    // Create a where clause for WireFormat bounds on generic types
92
130
    let where_clause = match where_clause {
93
        Some(where_clause) => {
94
            let mut predicates = where_clause.predicates.clone();
95
            add_wireformat_bounds(&generics, &mut predicates);
96
            Some(syn::WhereClause {
97
                where_token: syn::token::Where::default(),
98
                predicates,
99
            })
100
        }
101
130
        None if !generics.params.is_empty() => {
102
8
            let mut predicates = syn::punctuated::Punctuated::new();
103
8
            add_wireformat_bounds(&generics, &mut predicates);
104
8
            Some(syn::WhereClause {
105
8
                where_token: syn::token::Where::default(),
106
8
                predicates,
107
8
            })
108
        }
109
122
        None => None,
110
    };
111
    
112
191
    let where_clause_tokens = where_clause.map_or_else(|| quote! {}, |wc| quote! { #wc });
113

            
114
    // Generate message type implementation
115
130
    let message_impl = if let Some(msg_type) = jetstream_type {
116
        quote! {
117
           impl #impl_generics jetstream_wireformat::Message for #container #ty_generics #where_clause_tokens {
118
               const MESSAGE_TYPE: u8 = #msg_type;
119
           }
120
        }
121
    } else {
122
130
        quote! {}
123
    };
124

            
125
130
    let byte_size_impl = byte_size_sum(&input.data);
126
130
    let encode_impl = encode_wire_format(&input.data);
127
130
    let decode_impl = decode_wire_format(&input.data, &container);
128
130

            
129
130
    // Previously we used a scope for the module, but now we use a const block
130
130
    // let scope = format!("wire_format_{}", container).to_lowercase();
131
130
    // let scope = Ident::new(&scope, Span::call_site());
132
130
    
133
130
    // Use the container directly (not through type alias) to properly handle generics
134
130
    quote! {
135
130
        const _: () = {
136
130
            extern crate std;
137
130
            use std::io;
138
130
            use std::result::Result::Ok;
139
130
            use jetstream_wireformat::WireFormat;
140
130

            
141
130
            impl #impl_generics WireFormat for #container #ty_generics #where_clause_tokens {
142
130
                fn byte_size(&self) -> u32 {
143
130
                    #byte_size_impl
144
130
                }
145
130

            
146
130
                fn encode<W: io::Write>(&self, _writer: &mut W) -> io::Result<()> {
147
130
                    #encode_impl
148
130
                }
149
130

            
150
130
                fn decode<R: io::Read>(_reader: &mut R) -> io::Result<Self> {
151
130
                    #decode_impl
152
130
                }
153
130
            }
154
130
            #message_impl
155
130
        };
156
130
    }
157
130
}
158

            
159
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
160
pub(crate) struct Options {
161
    /// #[jetstream(with(impl WireFormat))]
162
    with: Option<syn::Path>,
163
    /// #[jetstream(with_encode(impl WireFormat))]
164
    encode: Option<syn::Path>,
165
    /// #[jetstream(with_decode(impl WireFormat))]
166
    decode: Option<syn::Path>,
167
    /// #[jetstream(with_byte_size(FnOnce(As<T> -> u32)))]
168
    byte_size: Option<syn::Path>,
169
    /// #[jetstream(from(impl From<WireFormat>))]
170
    from: Option<syn::Path>,
171
    /// #[jetstream(into(impl Into<WireFormat>))]
172
    into: Option<syn::Path>,
173
    /// #[jetstream(as(impl As<WireFormat>))]
174
    as_: Option<syn::Path>,
175
}
176

            
177
1092
pub(crate) fn extract_field_options(field: &syn::Field) -> Options {
178
1092
    let mut options = Options {
179
1092
        ..Default::default()
180
1092
    };
181

            
182
1128
    for attr in &field.attrs {
183
36
        if attr.path().is_ident("jetstream") {
184
54
            attr.parse_nested_meta(|meta| {
185
36
                if meta.path.is_ident("with") {
186
                    let content;
187
18
                    syn::parenthesized!(content in meta.input);
188
18
                    let path: syn::Path = content.parse()?;
189
18
                    options.with = Some(path);
190
18
                    return Ok(());
191
18
                }
192
18
                if meta.path.is_ident("with_encode") {
193
                    let content;
194
                    syn::parenthesized!(content in meta.input);
195
                    let path: syn::Path = content.parse()?;
196
                    options.encode = Some(path);
197
                    return Ok(());
198
18
                }
199
18
                if meta.path.is_ident("with_decode") {
200
                    let content;
201
                    syn::parenthesized!(content in meta.input);
202
                    let path: syn::Path = content.parse()?;
203
                    options.decode = Some(path);
204
                    return Ok(());
205
18
                }
206
18
                if meta.path.is_ident("with_byte_size") {
207
                    let content;
208
                    syn::parenthesized!(content in meta.input);
209
                    let path: syn::Path = content.parse()?;
210
                    options.byte_size = Some(path);
211
                    return Ok(());
212
18
                }
213
18
                if meta.path.is_ident("from") {
214
                    let content;
215
6
                    syn::parenthesized!(content in meta.input);
216
6
                    let path: syn::Path = content.parse()?;
217
6
                    options.from = Some(path);
218
6
                    return Ok(());
219
12
                }
220
12
                if meta.path.is_ident("into") {
221
                    let content;
222
12
                    syn::parenthesized!(content in meta.input);
223
12
                    let path: syn::Path = content.parse()?;
224
12
                    options.into = Some(path);
225
12
                    return Ok(());
226
                }
227
                if meta.path.is_ident("as") {
228
                    let content;
229
                    syn::parenthesized!(content in meta.input);
230
                    let path: syn::Path = content.parse()?;
231
                    options.as_ = Some(path);
232
                    return Ok(());
233
                }
234
                if meta.path.is_ident("skip") {
235
                    return Ok(());
236
                }
237
                Err(meta.error("unrecognized jetstream attribute"))
238
54
            })
239
36
            .ok();
240
36
        }
241
    }
242

            
243
1092
    options
244
1092
}
245

            
246
130
pub(crate) fn byte_size_sum(data: &Data) -> TokenStream {
247
130
    if let Data::Struct(ref data) = *data {
248
128
        if let Fields::Named(ref fields) = data.fields {
249
120
            let fields =
250
408
                fields.named.iter().filter(|f| !has_skip_attr(f)).map(|f| {
251
346
                    let field = &f.ident;
252
346
                    let span = field.span();
253
346
                    let options = extract_field_options(f);
254

            
255
346
                    if let Some(byte_size_fn) = options.byte_size {
256
                        quote_spanned! {span=>
257
                            #byte_size_fn(&self.#field)
258
                        }
259
346
                    } else if let Some(with_fn) = options.with {
260
2
                        quote_spanned! {span=>
261
2
                            #with_fn::byte_size(&self.#field)
262
2
                        }
263
                    } else {
264
344
                        quote_spanned! {span=>
265
344
                            WireFormat::byte_size(&self.#field)
266
344
                        }
267
                    }
268
406
                });
269
120

            
270
120
            quote! {
271
120
                0 #(+ #fields)*
272
120
            }
273
8
        } else if let Fields::Unnamed(unnamed) = &data.fields {
274
8
            let fields = unnamed
275
8
                .unnamed
276
8
                .iter()
277
8
                .enumerate()
278
12
                .filter(|(_, f)| !has_skip_attr(f))
279
12
                .map(|(i, f)| {
280
8
                    let index = syn::Index::from(i);
281
8
                    let options = extract_field_options(f);
282

            
283
8
                    if let Some(byte_size_fn) = options.byte_size {
284
                        quote! {
285
                            #byte_size_fn(&self.#index)
286
                        }
287
8
                    } else if let Some(with_fn) = options.with {
288
                        quote! {
289
                            #with_fn::byte_size(&self.#index)
290
                        }
291
                    } else {
292
8
                        quote! {
293
8
                            WireFormat::byte_size(&self.#index)
294
8
                        }
295
                    }
296
12
                });
297
8

            
298
8
            quote! {
299
8
                0 #(+ #fields)*
300
8
            }
301
        } else {
302
            unimplemented!();
303
        }
304
2
    } else if let Data::Enum(ref data) = *data {
305
9
        let variants = data.variants.iter().map(|variant| {
306
8
            let variant_ident = &variant.ident;
307
8
            match &variant.fields {
308
2
                Fields::Named(fields) => {
309
2
                    let field_idents = fields
310
2
                        .named
311
2
                        .iter()
312
2
                        .filter(|f| !has_skip_attr(f))
313
2
                        .map(|f| (f, &f.ident))
314
2
                        .collect::<Vec<_>>();
315
2
                    
316
2
                    let size_calcs = field_idents.iter().map(|(f, ident)| {
317
2
                        let options = extract_field_options(f);
318
2
                        if let Some(byte_size_fn) = options.byte_size {
319
                            quote! { + #byte_size_fn(#ident) }
320
2
                        } else if let Some(with_fn) = options.with {
321
2
                            quote! { + #with_fn::byte_size(#ident) }
322
                        } else {
323
                            quote! { + WireFormat::byte_size(#ident) }
324
                        }
325
2
                    });
326
2
                    
327
2
                    let field_idents = field_idents.iter().map(|(_, ident)| ident);
328
2
                    
329
2
                    quote! {
330
2
                        Self::#variant_ident { #(ref #field_idents),* } => {
331
2
                            1 #(#size_calcs)*
332
2
                        }
333
2
                    }
334
                }
335
6
                Fields::Unnamed(fields) => {
336
6
                    let refs_with_fields = fields
337
6
                        .unnamed
338
6
                        .iter()
339
6
                        .enumerate()
340
8
                        .filter(|(_, f)| !has_skip_attr(f))
341
8
                        .map(|(i, f)| (f, format!("__{}", i)))
342
6
                        .collect::<Vec<_>>();
343
6
                    
344
8
                    let size_calcs = refs_with_fields.iter().map(|(f, name)| {
345
8
                        let ident = Ident::new(name, Span::call_site());
346
8
                        let options = extract_field_options(f);
347
                        
348
8
                        if let Some(byte_size_fn) = options.byte_size {
349
                            quote! { + #byte_size_fn(#ident) }
350
8
                        } else if let Some(with_fn) = options.with {
351
2
                            quote! { + #with_fn::byte_size(#ident) }
352
                        } else {
353
6
                            quote! { + WireFormat::byte_size(#ident) }
354
                        }
355
8
                    });
356
6
                    
357
6
                    let refs = refs_with_fields.iter().map(|(_, name)|
358
8
                        Ident::new(name, Span::call_site())
359
6
                    );
360
6
                    
361
6
                    quote! {
362
6
                        Self::#variant_ident(#(ref #refs),*) => {
363
6
                            1 #(#size_calcs)*
364
6
                        }
365
6
                    }
366
                }
367
                Fields::Unit => {
368
                    quote! {
369
                        Self::#variant_ident => 1
370
                    }
371
                }
372
            }
373
9
        });
374
2

            
375
2
        quote! {
376
2
            match self {
377
2
                #(#variants),*
378
2
            }
379
2
        }
380
    } else {
381
        unimplemented!();
382
    }
383
130
}
384

            
385
130
pub(crate) fn encode_wire_format(data: &Data) -> TokenStream {
386
130
    if let Data::Struct(ref data) = *data {
387
128
        if let Fields::Named(ref fields) = data.fields {
388
120
            let fields =
389
408
                fields.named.iter().filter(|f| !has_skip_attr(f)).map(|f| {
390
346
                    let field = &f.ident;
391
346
                    let span = field.span();
392
346
                    let options = extract_field_options(f);
393
                    
394
346
                    if let Some(encode_fn) = options.encode {
395
                        quote_spanned! {span=>
396
                            #encode_fn(&self.#field, _writer)?;
397
                        }
398
346
                    } else if let Some(with_fn) = options.with {
399
2
                        quote_spanned! {span=>
400
2
                            #with_fn::encode(&self.#field, _writer)?;
401
2
                        }
402
344
                    } else if let Some(into_fn) = options.into {
403
4
                        quote_spanned! {span=>
404
4
                            WireFormat::encode(&(#into_fn(&self.#field)), _writer)?;
405
4
                        }
406
340
                    } else if let Some(as_fn) = options.as_ {
407
                        quote_spanned! {span=>
408
                            WireFormat::encode(&#as_fn(&self.#field), _writer)?;
409
                        }
410
                    } else {
411
340
                        quote_spanned! {span=>
412
340
                            WireFormat::encode(&self.#field, _writer)?;
413
340
                        }
414
                    }
415
406
                });
416
120

            
417
120
            quote! {
418
120
                #(#fields)*
419
120
                Ok(())
420
120
            }
421
8
        } else if let Fields::Unnamed(unnamed) = &data.fields {
422
8
            let fields = unnamed
423
8
                .unnamed
424
8
                .iter()
425
8
                .enumerate()
426
12
                .filter(|(_, f)| !has_skip_attr(f))
427
12
                .map(|(i, f)| {
428
8
                    let index = syn::Index::from(i);
429
8
                    let options = extract_field_options(f);
430
                    
431
8
                    if let Some(encode_fn) = options.encode {
432
                        quote! {
433
                            #encode_fn(&self.#index, _writer)?;
434
                        }
435
8
                    } else if let Some(with_fn) = options.with {
436
                        quote! {
437
                            #with_fn::encode(&self.#index, _writer)?;
438
                        }
439
8
                    } else if let Some(into_fn) = options.into {
440
                        quote! {
441
                            WireFormat::encode(&(#into_fn(&self.#index)), _writer)?;
442
                        }
443
8
                    } else if let Some(as_fn) = options.as_ {
444
                        quote! {
445
                            WireFormat::encode(&#as_fn(&self.#index), _writer)?;
446
                        }
447
                    } else {
448
8
                        quote! {
449
8
                            WireFormat::encode(&self.#index, _writer)?;
450
8
                        }
451
                    }
452
12
                });
453
8

            
454
8
            quote! {
455
8
                #(#fields)*
456
8
                Ok(())
457
8
            }
458
        } else {
459
            unimplemented!();
460
        }
461
2
    } else if let Data::Enum(ref data) = *data {
462
2
        let variants =
463
9
            data.variants.iter().enumerate().map(|(idx, variant)| {
464
8
                let variant_ident = &variant.ident;
465
8
                let idx = idx as u8;
466
8

            
467
8
                match &variant.fields {
468
2
                    Fields::Named(ref fields) => {
469
2
                        let field_idents_with_fields = fields
470
2
                            .named
471
2
                            .iter()
472
2
                            .filter(|f| !has_skip_attr(f))
473
2
                            .map(|f| (f, &f.ident))
474
2
                            .collect::<Vec<_>>();
475
2
                        
476
2
                        let encode_stmts = field_idents_with_fields.iter().map(|(f, ident)| {
477
2
                            let options = extract_field_options(f);
478
                            
479
2
                            if let Some(encode_fn) = options.encode {
480
                                quote! { #encode_fn(#ident, _writer)?; }
481
2
                            } else if let Some(with_fn) = options.with {
482
2
                                quote! { #with_fn::encode(#ident, _writer)?; }
483
                            } else if let Some(into_fn) = options.into {
484
                                quote! { WireFormat::encode(&(#into_fn(#ident)), _writer)?; }
485
                            } else if let Some(as_fn) = options.as_ {
486
                                quote! { WireFormat::encode(&#as_fn(#ident), _writer)?; }
487
                            } else {
488
                                quote! { WireFormat::encode(#ident, _writer)?; }
489
                            }
490
2
                        });
491
2
                        
492
2
                        let field_idents = field_idents_with_fields.iter().map(|(_, ident)| ident);
493
2

            
494
2
                        quote! {
495
2
                            Self::#variant_ident { #(ref #field_idents),* } => {
496
2
                                WireFormat::encode(&(#idx), _writer)?;
497
2
                                #(#encode_stmts)*
498
2
                            }
499
2
                        }
500
                    }
501
6
                    Fields::Unnamed(ref fields) => {
502
6
                        let field_refs_with_fields = fields
503
6
                            .unnamed
504
6
                            .iter()
505
6
                            .enumerate()
506
8
                            .filter(|(_, f)| !has_skip_attr(f))
507
8
                            .map(|(i, f)| (f, format!("__{}", i)))
508
6
                            .collect::<Vec<_>>();
509
6
                        
510
8
                        let encode_stmts = field_refs_with_fields.iter().map(|(f, name)| {
511
8
                            let ident = Ident::new(name, Span::call_site());
512
8
                            let options = extract_field_options(f);
513
                            
514
8
                            if let Some(encode_fn) = options.encode {
515
                                quote! { #encode_fn(#ident, _writer)?; }
516
8
                            } else if let Some(with_fn) = options.with {
517
2
                                quote! { #with_fn::encode(#ident, _writer)?; }
518
6
                            } else if let Some(into_fn) = options.into {
519
                                quote! { WireFormat::encode(&(#into_fn(#ident)), _writer)?; }
520
6
                            } else if let Some(as_fn) = options.as_ {
521
                                quote! { WireFormat::encode(&#as_fn(#ident), _writer)?; }
522
                            } else {
523
6
                                quote! { WireFormat::encode(#ident, _writer)?; }
524
                            }
525
8
                        });
526
6
                        
527
6
                        let field_refs = field_refs_with_fields.iter().map(|(_, name)| 
528
8
                            Ident::new(name, Span::call_site())
529
6
                        );
530
6
                        
531
6
                        quote! {
532
6
                            Self::#variant_ident(#(ref #field_refs),*) => {
533
6
                                WireFormat::encode(&(#idx), _writer)?;
534
6
                                #(#encode_stmts)*
535
6
                            }
536
6
                        }
537
                    }
538
                    Fields::Unit => {
539
                        quote! {
540
                            Self::#variant_ident => {
541
                                WireFormat::encode(&(#idx), _writer)?;
542
                            }
543
                        }
544
                    }
545
                }
546
9
            });
547
2

            
548
2
        quote! {
549
2
            match self {
550
2
                #(#variants),*
551
2
            }
552
2
            Ok(())
553
2
        }
554
    } else {
555
        unimplemented!();
556
    }
557
130
}
558

            
559
130
pub(crate) fn decode_wire_format(data: &Data, container: &Ident) -> TokenStream {
560
130
    if let Data::Struct(ref data) = *data {
561
128
        if let Fields::Named(ref fields) = data.fields {
562
120
            let all_fields = fields.named.iter().collect::<Vec<_>>();
563
120
            let non_skipped_values =
564
408
                fields.named.iter().filter(|f| !has_skip_attr(f)).map(|f| {
565
346
                    let field = &f.ident;
566
346
                    let span = field.span();
567
346
                    let options = extract_field_options(f);
568
                    
569
346
                    if let Some(decode_fn) = options.decode {
570
                        quote_spanned! {span=>
571
                            let #field = #decode_fn(_reader)?;
572
                        }
573
346
                    } else if let Some(with_fn) = options.with {
574
2
                        quote_spanned! {span=>
575
2
                            let #field = #with_fn::decode(_reader)?;
576
2
                        }
577
344
                    } else if let Some(from_fn) = options.from {
578
2
                        quote_spanned! {span=>
579
2
                            let #field = #from_fn(WireFormat::decode(_reader)?);
580
2
                        }
581
                    } else {
582
342
                        quote_spanned! {span=>
583
342
                            let #field = WireFormat::decode(_reader)?;
584
342
                        }
585
                    }
586
406
                });
587
120

            
588
408
            let members = all_fields.iter().map(|f| {
589
348
                let field = &f.ident;
590
348
                if has_skip_attr(f) {
591
2
                    quote! {
592
2
                        #field: Default::default(),
593
2
                    }
594
                } else {
595
346
                    quote! {
596
346
                        #field: #field,
597
346
                    }
598
                }
599
408
            });
600
120

            
601
120
            quote! {
602
120
                #(#non_skipped_values)*
603
120
                Ok(#container {
604
120
                    #(#members)*
605
120
                })
606
120
            }
607
8
        } else if let Fields::Unnamed(unnamed) = &data.fields {
608
8
            let all_fields = unnamed
609
8
                .unnamed
610
8
                .iter()
611
8
                .enumerate()
612
12
                .map(|(i, f)| (i, has_skip_attr(f)))
613
8
                .collect::<Vec<_>>();
614
8

            
615
8
            let non_skipped_values = unnamed
616
8
                .unnamed
617
8
                .iter()
618
8
                .enumerate()
619
12
                .filter(|(_, f)| !has_skip_attr(f))
620
12
                .map(|(i, f)| {
621
8
                    let ident = Ident::new(&format!("__{}", i), Span::call_site());
622
8
                    let options = extract_field_options(f);
623
                    
624
8
                    if let Some(decode_fn) = options.decode {
625
                        quote! {
626
                            let #ident = #decode_fn(_reader)?;
627
                        }
628
8
                    } else if let Some(with_fn) = options.with {
629
                        quote! {
630
                            let #ident = #with_fn::decode(_reader)?;
631
                        }
632
8
                    } else if let Some(from_fn) = options.from {
633
                        quote! {
634
                            let #ident = #from_fn(WireFormat::decode(_reader)?);
635
                        }
636
                    } else {
637
8
                        quote! {
638
8
                            let #ident = WireFormat::decode(_reader)?;
639
8
                        }
640
                    }
641
12
                });
642
8

            
643
12
            let members = all_fields.iter().map(|(i, is_skipped)| {
644
8
                let ident = if *is_skipped {
645
                    quote! { Default::default() }
646
                } else {
647
8
                    let ident =
648
8
                        Ident::new(&format!("__{}", i), Span::call_site());
649
8
                    quote! { #ident }
650
                };
651
8
                quote! { #ident }
652
12
            });
653
8

            
654
8
            quote! {
655
8
                #(#non_skipped_values)*
656
8
                Ok(#container(
657
8
                    #(#members,)*
658
8
                ))
659
8
            }
660
        } else {
661
            unimplemented!();
662
        }
663
2
    } else if let Data::Enum(ref data) = *data {
664
2
        let mut variant_matches = data
665
2
            .variants
666
2
            .iter()
667
2
            .enumerate()
668
9
            .map(|(idx, variant)| {
669
8
                let variant_ident = &variant.ident;
670
8
                let idx = idx as u8;
671
8

            
672
8
                match &variant.fields {
673
2
                    Fields::Named(ref fields) => {
674
2
                        let field_decodes =
675
2
                            fields.named.iter().filter(|f| !has_skip_attr(f)).map(|f| {
676
2
                                let field_ident = &f.ident;
677
2
                                let options = extract_field_options(f);
678
                                
679
2
                                if let Some(decode_fn) = options.decode {
680
                                    quote! { let #field_ident = #decode_fn(_reader)?; }
681
2
                                } else if let Some(with_fn) = options.with {
682
2
                                    quote! { let #field_ident = #with_fn::decode(_reader)?; }
683
                                } else if let Some(from_fn) = options.from {
684
                                    quote! { let #field_ident = #from_fn(WireFormat::decode(_reader)?); }
685
                                } else {
686
                                    quote! { let #field_ident = WireFormat::decode(_reader)?; }
687
                                }
688
2
                            });
689
2
                        
690
2
                        let field_names = fields.named.iter().map(|f| {
691
2
                            let field_ident = &f.ident;
692
2
                            if has_skip_attr(f) {
693
                                quote! { #field_ident: Default::default() }
694
                            } else {
695
                                // Just use the field name directly for the shorthand syntax
696
2
                                quote! { #field_ident }
697
                            }
698
2
                        });
699
2

            
700
2
                        quote! {
701
2
                            #idx => {
702
2
                                #(#field_decodes)*
703
2
                                Ok(Self::#variant_ident { #(#field_names),* })
704
2
                            }
705
2
                        }
706
                    }
707
6
                    Fields::Unnamed(ref fields) => {
708
6
                        let field_decodes = fields
709
6
                            .unnamed
710
6
                            .iter()
711
6
                            .enumerate()
712
8
                            .filter(|(_, f)| !has_skip_attr(f))
713
8
                            .map(|(i, f)| {
714
8
                                let field_name = Ident::new(&format!("__{}", i), Span::call_site());
715
8
                                let options = extract_field_options(f);
716
                                
717
8
                                if let Some(decode_fn) = options.decode {
718
                                    quote! { let #field_name = #decode_fn(_reader)?; }
719
8
                                } else if let Some(with_fn) = options.with {
720
2
                                    quote! { let #field_name = #with_fn::decode(_reader)?; }
721
6
                                } else if let Some(from_fn) = options.from {
722
                                    quote! { let #field_name = #from_fn(WireFormat::decode(_reader)?); }
723
                                } else {
724
6
                                    quote! { let #field_name = WireFormat::decode(_reader)?; }
725
                                }
726
8
                            });
727
6
                            
728
8
                        let field_names = fields.unnamed.iter().enumerate().map(|(i, f)| {
729
8
                            if has_skip_attr(f) {
730
                                quote! { Default::default() }
731
                            } else {
732
8
                                let field_name = Ident::new(&format!("__{}", i), Span::call_site());
733
8
                                quote! { #field_name }
734
                            }
735
8
                        });
736
6

            
737
6
                        quote! {
738
6
                            #idx => {
739
6
                                #(#field_decodes)*
740
6
                                Ok(Self::#variant_ident(#(#field_names),*))
741
6
                            }
742
6
                        }
743
                    }
744
                    Fields::Unit => {
745
                        quote! {
746
                            #idx => Ok(Self::#variant_ident)
747
                        }
748
                    }
749
                }
750
9
            })
751
2
            .collect::<Vec<_>>();
752
2

            
753
2
        variant_matches.push(quote! {
754
2
              _ => Err(::std::io::Error::new(::std::io::ErrorKind::InvalidData, "invalid variant index"))
755
2
          });
756
2

            
757
2
        quote! {
758
2
            let variant_index: u8 = WireFormat::decode(_reader)?;
759
2
            match variant_index {
760
2
                #(#variant_matches),*
761
2
            }
762
2
        }
763
    } else {
764
        unimplemented!();
765
    }
766
130
}
767