• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

facet-rs / facet / 14520225662

17 Apr 2025 04:18PM UTC coverage: 44.183% (+0.2%) from 43.969%
14520225662

Pull #283

github

fasterthanlime
Update derive macro to compute repr(C) offsets at derive-time.
Pull Request #283: Update derive macro to compute repr(C) offsets at derive-time.

27 of 27 new or added lines in 3 files covered. (100.0%)

1 existing line in 1 file now uncovered.

4721 of 10685 relevant lines covered (44.18%)

54.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.04
/facet-derive-emit/src/process_enum.rs
1
use super::*;
2

3
// mirrors facet_core::types::EnumRepr
4
#[derive(Clone, Copy)]
5
enum Discriminant {
6
    U8,
7
    U16,
8
    U32,
9
    U64,
10
    USize,
11
    I8,
12
    I16,
13
    I32,
14
    I64,
15
    ISize,
16
}
17

18
impl Discriminant {
19
    fn as_enum_repr(&self) -> &'static str {
32✔
20
        match self {
32✔
21
            Discriminant::U8 => "U8",
31✔
22
            Discriminant::U16 => "U16",
1✔
23
            Discriminant::U32 => "U32",
×
24
            Discriminant::U64 => "U64",
×
25
            Discriminant::USize => "USize",
×
26
            Discriminant::I8 => "I8",
×
27
            Discriminant::I16 => "I16",
×
28
            Discriminant::I32 => "I32",
×
29
            Discriminant::I64 => "I64",
×
30
            Discriminant::ISize => "ISize",
×
31
        }
32
    }
32✔
33

34
    fn as_rust_type(&self) -> &'static str {
51✔
35
        match self {
51✔
36
            Discriminant::U8 => "u8",
48✔
37
            Discriminant::U16 => "u16",
3✔
38
            Discriminant::U32 => "u32",
×
39
            Discriminant::U64 => "u64",
×
40
            Discriminant::USize => "usize",
×
41
            Discriminant::I8 => "i8",
×
42
            Discriminant::I16 => "i16",
×
43
            Discriminant::I32 => "i32",
×
44
            Discriminant::I64 => "i64",
×
45
            Discriminant::ISize => "isize",
×
46
        }
47
    }
51✔
48
}
49

50
struct ProcessedEnumBody {
51
    shadow_struct_defs: Vec<String>,
52
    variant_expressions: Vec<String>,
53
    repr_type: String,
54
}
55

56
type EnumVariant = Delimited<EnumVariantLike, Comma>;
57

58
/// Processes an enum to implement Facet
59
///
60
/// Example input:
61
/// ```rust
62
/// #[repr(u8)]
63
/// enum Color {
64
///     Red,
65
///     Green,
66
///     Blue(u8, u8),
67
///     Custom { r: u8, g: u8, b: u8 }
68
/// }
69
/// ```
70
pub(crate) fn process_enum(parsed: Enum) -> TokenStream {
35✔
71
    let enum_name = parsed.name.to_string();
35✔
72
    let (generics_def, generics_use) = generics_split_for_impl(parsed.generics.as_ref());
35✔
73
    let where_clauses = build_where_clauses(parsed.clauses.as_ref(), parsed.generics.as_ref());
35✔
74
    let type_params = build_type_params(parsed.generics.as_ref());
35✔
75

35✔
76
    // collect all `#repr(..)` attrs
35✔
77
    // either multiple attrs, or a single attr with multiple values
35✔
78
    let attr_iter = parsed
35✔
79
        .attributes
35✔
80
        .iter()
35✔
81
        .filter_map(|attr| {
57✔
82
            if let AttributeInner::Repr(repr_attr) = &attr.body.content {
57✔
83
                if repr_attr.attr.content.0.is_empty() {
35✔
84
                    // treat empty repr as non-existent
85
                    // (this shouldn't be possible, but just in case)
86
                    None
×
87
                } else {
88
                    Some(repr_attr)
35✔
89
                }
90
            } else {
91
                None
22✔
92
            }
93
        })
57✔
94
        .flat_map(|repr_attr| repr_attr.attr.content.0.iter());
35✔
95

96
    let mut repr_c = false;
35✔
97
    let mut discriminant_type = None;
35✔
98

99
    for attr in attr_iter {
70✔
100
        let attr = attr.value.to_string();
35✔
101
        match attr.as_str() {
35✔
102
            // this is #[repr(C)]
35✔
103
            "C" => repr_c = true,
35✔
104

105
            // set the repr type
106
            // NOTE: we're not worried about multiple
107
            // clashing types here -- that's rustc's problem
108
            "u8" => discriminant_type = Some(Discriminant::U8),
32✔
109
            "u16" => discriminant_type = Some(Discriminant::U16),
1✔
110
            "u32" => discriminant_type = Some(Discriminant::U32),
×
111
            "u64" => discriminant_type = Some(Discriminant::U64),
×
112
            "usize" => discriminant_type = Some(Discriminant::USize),
×
113
            "i8" => discriminant_type = Some(Discriminant::I8),
×
114
            "i16" => discriminant_type = Some(Discriminant::I16),
×
115
            "i32" => discriminant_type = Some(Discriminant::I32),
×
116
            "i64" => discriminant_type = Some(Discriminant::I64),
×
117
            "isize" => discriminant_type = Some(Discriminant::ISize),
×
118
            _ => {
119
                return r#"compile_error!("Facet only supports enums with a primitive representation (e.g. #[repr(u8)]) or C-style (e.g. #[repr(C)]")"#
×
120
            .into_token_stream()
×
121
            }
122
        }
123
    }
124

125
    let processed_body = match (repr_c, discriminant_type) {
35✔
126
        (true, _) => {
127
            // C-style enum, no discriminant type
128
            process_c_style_enum(
3✔
129
                &enum_name,
3✔
130
                &parsed.body.content.0,
3✔
131
                discriminant_type,
3✔
132
                &generics_def,
3✔
133
                &generics_use,
3✔
134
                &where_clauses,
3✔
135
            )
136
        }
137
        (false, Some(discriminant_type)) => process_primitive_enum(
32✔
138
            &enum_name,
32✔
139
            &parsed.body.content.0,
32✔
140
            discriminant_type,
32✔
141
            &generics_def,
32✔
142
            &generics_use,
32✔
143
            &where_clauses,
32✔
144
        ),
145
        _ => {
146
            return r#"compile_error!("Enums must have an explicit representation (e.g. #[repr(u8)] or #[repr(C)]) to be used with Facet")"#
×
147
            .into_token_stream()
×
148
        }
149
    };
150

151
    let ProcessedEnumBody {
152
        shadow_struct_defs,
35✔
153
        variant_expressions,
35✔
154
        repr_type,
35✔
155
    } = processed_body;
35✔
156

35✔
157
    // Join the shadow struct definitions and variant expressions
35✔
158
    let shadow_structs = shadow_struct_defs.join("\n\n");
35✔
159
    let variants = variant_expressions.join(", ");
35✔
160

161
    let static_decl = if parsed.generics.is_none() {
35✔
162
        generate_static_decl(&enum_name)
30✔
163
    } else {
164
        String::new()
5✔
165
    };
166
    let maybe_container_doc = build_maybe_doc(&parsed.attributes);
35✔
167

35✔
168
    // Generate the impl
35✔
169
    let output = format!(
35✔
170
        r#"
35✔
171
{static_decl}
35✔
172

35✔
173
#[automatically_derived]
35✔
174
unsafe impl<{generics_def}> ::facet::Facet for {enum_name}<{generics_use}> {where_clauses} {{
35✔
175
    const SHAPE: &'static ::facet::Shape = &const {{
35✔
176
        // Define all shadow structs at the beginning of the const block
35✔
177
        // to ensure they're in scope for offset_of! macros
35✔
178
        {shadow_structs}
35✔
179

35✔
180
        let __facet_variants: &'static [::facet::Variant] = &const {{[
35✔
181
            {variants}
35✔
182
        ]}};
35✔
183

35✔
184
        ::facet::Shape::builder()
35✔
185
            .id(::facet::ConstTypeId::of::<Self>())
35✔
186
            .layout(::core::alloc::Layout::new::<Self>())
35✔
187
            {type_params}
35✔
188
            .vtable(::facet::value_vtable!(
35✔
189
                Self,
35✔
190
                |f, _opts| ::core::fmt::Write::write_str(f, "{enum_name}")
35✔
191
            ))
35✔
192
            .def(::facet::Def::Enum(::facet::EnumDef::builder()
35✔
193
                // Use variant expressions that just reference the shadow structs
35✔
194
                // which are now defined above
35✔
195
                .variants(__facet_variants)
35✔
196
                .repr(::facet::EnumRepr::{repr_type})
35✔
197
                .build()))
35✔
198
            {maybe_container_doc}
35✔
199
            .build()
35✔
200
    }};
35✔
201
}}
35✔
202
        "#,
35✔
203
    );
35✔
204

35✔
205
    // Output generated code
35✔
206
    // Don't use panic for debugging as it makes code unreachable
35✔
207

35✔
208
    // Return the generated code
35✔
209
    output.into_token_stream()
35✔
210
}
35✔
211

212
/// C-style enums (i.e. #[repr(C)], #[repr(C, u*)] and #[repr(C, i*)]) are laid out
213
/// as a #[repr(C)] struct with two fiels: the discriminant and the union of all the variants.
214
///
215
/// See: <https://doc.rust-lang.org/reference/type-layout.html#r-layout.repr.primitive.adt>
216
///
217
/// To calculate the offsets of each variant, we create a shadow struct that mimics this
218
/// structure and use the `offset_of!` macro to calculate the offsets of each field.
219
fn process_c_style_enum(
3✔
220
    enum_name: &str,
3✔
221
    variants: &[EnumVariant],
3✔
222
    discriminant_type: Option<Discriminant>,
3✔
223
    generics_def: &str,
3✔
224
    generics_use: &str,
3✔
225
    where_clauses: &str,
3✔
226
) -> ProcessedEnumBody {
3✔
227
    // Collect shadow struct definitions separately from variant expressions
3✔
228
    let mut shadow_struct_defs = Vec::new();
3✔
229
    let mut variant_expressions = Vec::new();
3✔
230

3✔
231
    // first, create an enum to represent the discriminant type
3✔
232
    let shadow_discriminant_name = format!("__ShadowDiscriminant{enum_name}");
3✔
233
    let all_variant_names = variants
3✔
234
        .iter()
3✔
235
        .map(|var_like| match &var_like.value {
10✔
236
            EnumVariantLike::Unit(unit) => unit.name.to_string(),
3✔
237
            EnumVariantLike::Tuple(tuple) => tuple.name.to_string(),
4✔
238
            EnumVariantLike::Struct(struct_var) => struct_var.name.to_string(),
3✔
239
        })
10✔
240
        .collect::<Vec<_>>()
3✔
241
        .join(", ");
3✔
242
    shadow_struct_defs.push(format!(
3✔
243
        "#[repr({repr})] enum {shadow_discriminant_name} {{ {all_variant_names} }}",
3✔
244
        // repr is either C or the explicit discriminant type
3✔
245
        repr = discriminant_type.map(|d| d.as_rust_type()).unwrap_or("C")
3✔
246
    ));
3✔
247

3✔
248
    // we'll also generate a shadow union for the fields
3✔
249
    let shadow_union_name = format!("__ShadowFields{enum_name}");
3✔
250
    let all_union_fields = variants
3✔
251
        .iter()
3✔
252
        .map(|var_like| match &var_like.value {
10✔
253
            EnumVariantLike::Unit(unit) => unit.name.to_string(),
3✔
254
            EnumVariantLike::Tuple(tuple) => tuple.name.to_string(),
4✔
255
            EnumVariantLike::Struct(struct_var) => struct_var.name.to_string(),
3✔
256
        })
10✔
257
        .map(|variant_name| {
10✔
258
            format!(
10✔
259
                "{variant_name}: std::mem::ManuallyDrop<__ShadowField{enum_name}_{variant_name}>"
10✔
260
            )
10✔
261
        })
10✔
262
        .collect::<Vec<_>>()
3✔
263
        .join(", ");
3✔
264

3✔
265
    shadow_struct_defs.push(format!(
3✔
266
        "#[repr(C)] union {shadow_union_name} {{ {all_union_fields} }}",
3✔
267
    ));
3✔
268

3✔
269
    // Create a shadow struct to represent the enum layout
3✔
270
    let shadow_repr_name = format!("__ShadowRepr{enum_name}");
3✔
271

3✔
272
    shadow_struct_defs.push(format!(
3✔
273
        "#[repr(C)] struct {shadow_repr_name} {{
3✔
274
            _discriminant: {shadow_discriminant_name},
3✔
275
            _fields: {shadow_union_name},
3✔
276
        }}",
3✔
277
    ));
278

279
    // Process each variant using enumerate to get discriminant values
280
    for (discriminant_value, var_like) in variants.iter().enumerate() {
10✔
281
        match &var_like.value {
10✔
282
            EnumVariantLike::Unit(unit) => {
3✔
283
                let variant_name = unit.name.to_string();
3✔
284
                let maybe_doc = build_maybe_doc(&unit.attributes);
3✔
285

3✔
286
                // Generate shadow struct for this tuple variant to calculate offsets
3✔
287
                let shadow_struct_name = format!("__ShadowField{enum_name}_{variant_name}");
3✔
288

3✔
289
                // Add shadow struct definition
3✔
290
                shadow_struct_defs.push(format!("#[repr(C)] struct {shadow_struct_name};",));
3✔
291

3✔
292
                // variant offset is offset of the `_fields` union
3✔
293
                variant_expressions.push(format!(
3✔
294
                    "::facet::Variant::builder()
3✔
295
                    .name({variant_name:?})
3✔
296
                    .discriminant({discriminant_value})
3✔
297
                    .fields(::facet::Struct::builder().unit().build())
3✔
298
                    {maybe_doc}
3✔
299
                    .build()",
3✔
300
                ));
3✔
301
            }
3✔
302
            EnumVariantLike::Tuple(tuple) => {
4✔
303
                let variant_name = tuple.name.to_string();
4✔
304
                let maybe_doc = build_maybe_doc(&tuple.attributes);
4✔
305

4✔
306
                // Generate shadow struct for this tuple variant to calculate offsets
4✔
307
                let shadow_struct_name = format!("__ShadowField{enum_name}_{variant_name}");
4✔
308

4✔
309
                // Build the list of fields and types for the shadow struct
4✔
310
                let fields_with_types = tuple
4✔
311
                    .fields
4✔
312
                    .content
4✔
313
                    .0
4✔
314
                    .iter()
4✔
315
                    .enumerate()
4✔
316
                    .map(|(idx, field)| {
5✔
317
                        let typ = VerbatimDisplay(&field.value.typ).to_string();
5✔
318
                        format!("_{}: {}", idx, typ)
5✔
319
                    })
5✔
320
                    .collect::<Vec<String>>()
4✔
321
                    .join(", ");
4✔
322

4✔
323
                // Add shadow struct definition
4✔
324
                shadow_struct_defs.push(format!(
4✔
325
                    "#[repr(C)] struct {shadow_struct_name}<{generics_def}> {where_clauses} {{  {fields_with_types} }}",
4✔
326
                ));
4✔
327

4✔
328
                let variant_offset =
4✔
329
                    format!("::core::mem::offset_of!({shadow_repr_name}, _fields)");
4✔
330

4✔
331
                // Build the list of field types with calculated offsets
4✔
332
                let fields = tuple
4✔
333
                    .fields
4✔
334
                    .content
4✔
335
                    .0
4✔
336
                    .iter()
4✔
337
                    .enumerate()
4✔
338
                    .map(|(idx, field)| {
5✔
339
                        let field_name = format!("_{idx}");
5✔
340
                        gen_struct_field(
5✔
341
                            &field_name,
5✔
342
                            &shadow_struct_name,
5✔
343
                            generics_use,
5✔
344
                            &field.value.attributes,
5✔
345
                            Some(&variant_offset),
5✔
346
                        )
5✔
347
                    })
5✔
348
                    .collect::<Vec<String>>()
4✔
349
                    .join(", ");
4✔
350

4✔
351
                // Add variant expression - now with discriminant
4✔
352
                variant_expressions.push(format!(
4✔
353
                    "{{
4✔
354
                        let fields: &'static [::facet::Field] = &const {{[
4✔
355
                            {fields}
4✔
356
                        ]}};
4✔
357

4✔
358
                        ::facet::Variant::builder()
4✔
359
                            .name({variant_name:?})
4✔
360
                            .discriminant({discriminant_value})
4✔
361
                            .fields(::facet::Struct::builder().tuple().fields(fields).build())
4✔
362
                            {maybe_doc}
4✔
363
                            .build()
4✔
364
                    }}",
4✔
365
                ));
366
            }
367
            EnumVariantLike::Struct(struct_var) => {
3✔
368
                let variant_name = struct_var.name.to_string();
3✔
369
                let maybe_doc = build_maybe_doc(&struct_var.attributes);
3✔
370

3✔
371
                // Generate shadow struct for this struct variant to calculate offsets
3✔
372
                let shadow_struct_name = format!("__ShadowField{}_{}", enum_name, variant_name);
3✔
373

3✔
374
                // Build the list of fields and types
3✔
375
                let fields_with_types = struct_var
3✔
376
                    .fields
3✔
377
                    .content
3✔
378
                    .0
3✔
379
                    .iter()
3✔
380
                    .map(|field| {
6✔
381
                        let name = field.value.name.to_string();
6✔
382
                        let typ = VerbatimDisplay(&field.value.typ).to_string();
6✔
383
                        format!("{}: {}", name, typ)
6✔
384
                    })
6✔
385
                    .collect::<Vec<String>>()
3✔
386
                    .join(", ");
3✔
387

3✔
388
                // Add shadow struct definition
3✔
389
                shadow_struct_defs.push(format!(
3✔
390
                    "#[repr(C)] struct {shadow_struct_name}<{generics_def}> {where_clauses} {{  {fields_with_types} }}"
3✔
391
                ));
3✔
392

3✔
393
                let variant_offset =
3✔
394
                    format!("::core::mem::offset_of!({shadow_repr_name}, _fields)");
3✔
395

3✔
396
                // Build the list of field types with calculated offsets
3✔
397
                let fields = struct_var
3✔
398
                    .fields
3✔
399
                    .content
3✔
400
                    .0
3✔
401
                    .iter()
3✔
402
                    .map(|field| {
6✔
403
                        let field_name = field.value.name.to_string();
6✔
404
                        gen_struct_field(
6✔
405
                            &field_name,
6✔
406
                            &shadow_struct_name,
6✔
407
                            generics_use,
6✔
408
                            &field.value.attributes,
6✔
409
                            Some(&variant_offset),
6✔
410
                        )
6✔
411
                    })
6✔
412
                    .collect::<Vec<String>>()
3✔
413
                    .join(", ");
3✔
414

3✔
415
                // Add variant expression - now with discriminant
3✔
416
                variant_expressions.push(format!(
3✔
417
                    "{{
3✔
418
                        let fields: &'static [::facet::Field] = &const {{[
3✔
419
                            {fields}
3✔
420
                        ]}};
3✔
421

3✔
422
                        ::facet::Variant::builder()
3✔
423
                            .name({variant_name:?})
3✔
424
                            .discriminant({discriminant_value})
3✔
425
                            .fields(::facet::Struct::builder().struct_().fields(fields).build())
3✔
426
                            {maybe_doc}
3✔
427
                            .build()
3✔
428
                    }}",
3✔
429
                ));
430
            }
431
        }
432
    }
433

434
    ProcessedEnumBody {
435
        shadow_struct_defs,
3✔
436
        variant_expressions,
3✔
437
        repr_type: discriminant_type.map_or_else(
3✔
438
            || format!("from_discriminant_size::<{shadow_discriminant_name}>()"),
3✔
UNCOV
439
            |d| d.as_enum_repr().to_string(),
×
440
        ),
441
    }
442
}
3✔
443

444
/// Primitive enums (i.e. #[repr(u*)] and #[repr(i*)]) are laid out
445
/// as a union of all the variants, with the discriminant as an "inner" tag in the struct.
446
///
447
/// See: <https://doc.rust-lang.org/reference/type-layout.html#r-layout.repr.primitive.adt>
448
///
449
/// To calculate the offsets of each variant, we create a shadow struct that mimics this
450
/// structure and use the `offset_of!` macro to calculate the offsets of each field.
451
fn process_primitive_enum(
32✔
452
    enum_name: &str,
32✔
453
    variants: &[EnumVariant],
32✔
454
    discriminant_type: Discriminant,
32✔
455
    generics_def: &str,
32✔
456
    generics_use: &str,
32✔
457
    where_clauses: &str,
32✔
458
) -> ProcessedEnumBody {
32✔
459
    // Collect shadow struct definitions separately from variant expressions
32✔
460
    let mut shadow_struct_defs = Vec::new();
32✔
461
    let mut variant_expressions = Vec::new();
32✔
462

463
    // Process each variant using enumerate to get discriminant values
464
    for (discriminant_value, var_like) in variants.iter().enumerate() {
78✔
465
        match &var_like.value {
78✔
466
            EnumVariantLike::Unit(unit) => {
27✔
467
                let variant_name = unit.name.to_string();
27✔
468
                let maybe_doc = build_maybe_doc(&unit.attributes);
27✔
469

27✔
470
                variant_expressions.push(format!(
27✔
471
                    "::facet::Variant::builder()
27✔
472
                    .name({variant_name:?})
27✔
473
                    .discriminant({discriminant_value})
27✔
474
                    .fields(::facet::Struct::builder().unit().build())
27✔
475
                    {maybe_doc}
27✔
476
                    .build()",
27✔
477
                ));
27✔
478
            }
27✔
479
            EnumVariantLike::Tuple(tuple) => {
28✔
480
                let variant_name = tuple.name.to_string();
28✔
481
                let maybe_doc = build_maybe_doc(&tuple.attributes);
28✔
482

28✔
483
                // Generate shadow struct for this tuple variant to calculate offsets
28✔
484
                let shadow_struct_name = format!("__Shadow{}_{}", enum_name, variant_name);
28✔
485

28✔
486
                // Build the list of fields and types for the shadow struct
28✔
487
                let fields_with_types = tuple
28✔
488
                    .fields
28✔
489
                    .content
28✔
490
                    .0
28✔
491
                    .iter()
28✔
492
                    .enumerate()
28✔
493
                    .map(|(idx, field)| {
33✔
494
                        let typ = VerbatimDisplay(&field.value.typ).to_string();
33✔
495
                        format!("_{}: {}", idx, typ)
33✔
496
                    })
33✔
497
                    .collect::<Vec<String>>()
28✔
498
                    .join(", ");
28✔
499

28✔
500
                // Add shadow struct definition
28✔
501
                shadow_struct_defs.push(format!(
28✔
502
                    "#[repr(C)] struct {shadow_struct_name}<{generics_def}> {where_clauses}  {{ _discriminant: {}, {fields_with_types} }}",
28✔
503
                    discriminant_type.as_rust_type(),
28✔
504
                ));
28✔
505

28✔
506
                // Build the list of field types with calculated offsets
28✔
507
                let fields = tuple
28✔
508
                    .fields
28✔
509
                    .content
28✔
510
                    .0
28✔
511
                    .iter()
28✔
512
                    .enumerate()
28✔
513
                    .map(|(idx, field)| {
33✔
514
                        let field_name = format!("_{idx}");
33✔
515
                        gen_struct_field(
33✔
516
                            &field_name,
33✔
517
                            &shadow_struct_name,
33✔
518
                            generics_use,
33✔
519
                            &field.value.attributes,
33✔
520
                            None,
33✔
521
                        )
33✔
522
                    })
33✔
523
                    .collect::<Vec<String>>()
28✔
524
                    .join(", ");
28✔
525

28✔
526
                // Add variant expression - now with discriminant
28✔
527
                variant_expressions.push(format!(
28✔
528
                    "{{
28✔
529
                        let fields: &'static [::facet::Field] = &const {{[
28✔
530
                            {fields}
28✔
531
                        ]}};
28✔
532

28✔
533
                        ::facet::Variant::builder()
28✔
534
                            .name({variant_name:?})
28✔
535
                            .discriminant({discriminant_value})
28✔
536
                            .fields(::facet::Struct::builder().tuple().fields(fields).build())
28✔
537
                            {maybe_doc}
28✔
538
                            .build()
28✔
539
                    }}",
28✔
540
                ));
541
            }
542
            EnumVariantLike::Struct(struct_var) => {
23✔
543
                let variant_name = struct_var.name.to_string();
23✔
544
                let maybe_doc = build_maybe_doc(&struct_var.attributes);
23✔
545

23✔
546
                // Generate shadow struct for this struct variant to calculate offsets
23✔
547
                let shadow_struct_name = format!("__Shadow{}_{}", enum_name, variant_name);
23✔
548

23✔
549
                // Build the list of fields and types
23✔
550
                let fields_with_types = struct_var
23✔
551
                    .fields
23✔
552
                    .content
23✔
553
                    .0
23✔
554
                    .iter()
23✔
555
                    .map(|field| {
37✔
556
                        let name = field.value.name.to_string();
37✔
557
                        let typ = VerbatimDisplay(&field.value.typ).to_string();
37✔
558
                        format!("{}: {}", name, typ)
37✔
559
                    })
37✔
560
                    .collect::<Vec<String>>()
23✔
561
                    .join(", ");
23✔
562

23✔
563
                // Add shadow struct definition
23✔
564
                shadow_struct_defs.push(format!(
23✔
565
                    "#[repr(C)] struct {shadow_struct_name}<{generics_def}> {where_clauses} {{ _discriminant: {}, {fields_with_types} }}",
23✔
566
                    discriminant_type.as_rust_type(),
23✔
567
                ));
23✔
568

23✔
569
                // Build the list of field types with calculated offsets
23✔
570
                let fields = struct_var
23✔
571
                    .fields
23✔
572
                    .content
23✔
573
                    .0
23✔
574
                    .iter()
23✔
575
                    .map(|field| {
37✔
576
                        let field_name = field.value.name.to_string();
37✔
577
                        gen_struct_field(
37✔
578
                            &field_name,
37✔
579
                            &shadow_struct_name,
37✔
580
                            generics_use,
37✔
581
                            &field.value.attributes,
37✔
582
                            None,
37✔
583
                        )
37✔
584
                    })
37✔
585
                    .collect::<Vec<String>>()
23✔
586
                    .join(", ");
23✔
587

23✔
588
                // Add variant expression - now with discriminant
23✔
589
                // variant offset is zero since all fields are
23✔
590
                // already computed relative to the discriminant
23✔
591
                variant_expressions.push(format!(
23✔
592
                    "{{
23✔
593
                        let fields: &'static [::facet::Field] = &const {{[
23✔
594
                            {fields}
23✔
595
                        ]}};
23✔
596

23✔
597
                        ::facet::Variant::builder()
23✔
598
                            .name({variant_name:?})
23✔
599
                            .discriminant({discriminant_value})
23✔
600
                            .fields(::facet::Struct::builder().struct_().fields(fields).build())
23✔
601
                            {maybe_doc}
23✔
602
                            .build()
23✔
603
                    }}",
23✔
604
                ));
605
            }
606
        }
607
    }
608

609
    ProcessedEnumBody {
32✔
610
        shadow_struct_defs,
32✔
611
        variant_expressions,
32✔
612
        repr_type: discriminant_type.as_enum_repr().to_string(),
32✔
613
    }
32✔
614
}
32✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc