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

facet-rs / facet / 14470508630

15 Apr 2025 01:20PM UTC coverage: 29.303% (+0.02%) from 29.283%
14470508630

Pull #231

github

web-flow
Merge 5496fa194 into 285300375
Pull Request #231: Start splitting facet-derive into parse & emit

2 of 34 new or added lines in 2 files covered. (5.88%)

176 existing lines in 2 files now uncovered.

2048 of 6989 relevant lines covered (29.3%)

30.66 hits per line

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

0.0
/facet-derive/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 {
UNCOV
19
    fn as_enum_repr(&self) -> &'static str {
×
20
        match self {
×
21
            Discriminant::U8 => "U8",
×
22
            Discriminant::U16 => "U16",
×
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
    }
33

UNCOV
34
    fn as_rust_type(&self) -> &'static str {
×
35
        match self {
×
36
            Discriminant::U8 => "u8",
×
37
            Discriminant::U16 => "u16",
×
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
    }
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
/// ```
UNCOV
70
pub(crate) fn process_enum(parsed: Enum) -> proc_macro::TokenStream {
×
71
    let enum_name = parsed.name.to_string();
×
72
    let (generics_def, generics_use) = generics_split_for_impl(parsed.generics.as_ref());
×
73
    let where_clauses = parsed
×
74
        .clauses
×
75
        .as_ref()
UNCOV
76
        .map_or(String::new(), ToString::to_string);
×
77

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

UNCOV
98
    let mut repr_c = false;
×
99
    let mut discriminant_type = None;
×
100

UNCOV
101
    for attr in attr_iter {
×
102
        let attr = attr.value.to_string();
×
103
        match attr.as_str() {
×
104
            // this is #[repr(C)]
UNCOV
105
            "C" => repr_c = true,
×
106

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

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

155
    let ProcessedEnumBody {
UNCOV
156
        shadow_struct_defs,
×
157
        variant_expressions,
×
158
        repr_type,
×
159
    } = processed_body;
×
160

161
    // Join the shadow struct definitions and variant expressions
UNCOV
162
    let shadow_structs = shadow_struct_defs.join("\n\n");
×
163
    let variants = variant_expressions.join(", ");
×
164

UNCOV
165
    let static_decl = if parsed.generics.is_none() {
×
166
        generate_static_decl(&enum_name)
×
167
    } else {
UNCOV
168
        String::new()
×
169
    };
UNCOV
170
    let maybe_container_doc = build_maybe_doc(&parsed.attributes);
×
171

172
    // Generate the impl
UNCOV
173
    let output = format!(
×
174
        r#"
175
{static_decl}
176

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

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

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

207
    // Return the generated code
UNCOV
208
    output.into_token_stream().into()
×
209
}
210

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

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

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

UNCOV
264
    shadow_struct_defs.push(format!(
×
265
        "#[repr(C)] union {shadow_union_name} {{ {all_union_fields} }}",
×
266
    ));
267

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

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

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

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

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

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

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

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

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

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

347
                // Add variant expression - now with discriminant
UNCOV
348
                variant_expressions.push(format!(
×
349
                    "{{
×
350
                        let fields: &'static [::facet::Field] = &const {{[
×
351
                            {fields}
×
352
                        ]}};
353

UNCOV
354
                        ::facet::Variant::builder()
×
355
                            .name({variant_name:?})
×
356
                            .discriminant({discriminant_value})
×
357
                            .offset(::core::mem::offset_of!({shadow_repr_name}, _fields))
×
358
                            .fields(::facet::Struct::builder().tuple().fields(fields).build(),
×
359
                            {maybe_doc}
×
360
                            .build()
×
361
                    }}",
×
362
                ));
363
            }
UNCOV
364
            EnumVariantLike::Struct(struct_var) => {
×
365
                let variant_name = struct_var.name.to_string();
×
366
                let maybe_doc = build_maybe_doc(&struct_var.attributes);
×
367

368
                // Generate shadow struct for this struct variant to calculate offsets
UNCOV
369
                let shadow_struct_name = format!("__ShadowField{}_{}", enum_name, variant_name);
×
370

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

385
                // Add shadow struct definition
UNCOV
386
                shadow_struct_defs.push(format!(
×
387
                    "#[repr(C)] struct {shadow_struct_name}<{generics_def}> {where_clauses} {{  {fields_with_types} }}"
×
388
                ));
389

390
                // Build the list of field types with calculated offsets
UNCOV
391
                let fields = struct_var
×
392
                    .fields
×
393
                    .content
×
394
                    .0
×
395
                    .iter()
UNCOV
396
                    .map(|field| {
×
397
                        let field_name = field.value.name.to_string();
×
398
                        gen_struct_field(
×
399
                            &field_name,
×
400
                            &shadow_struct_name,
×
401
                            generics_use,
×
402
                            &field.value.attributes,
×
403
                        )
404
                    })
405
                    .collect::<Vec<String>>()
406
                    .join(", ");
407

408
                // Add variant expression - now with discriminant
UNCOV
409
                variant_expressions.push(format!(
×
410
                    "{{
×
411
                        let fields: &'static [::facet::Field] = &const {{[
×
412
                            {fields}
×
413
                        ]}};
414

UNCOV
415
                        ::facet::Variant::builder()
×
416
                            .name({variant_name:?})
×
417
                            .discriminant(discriminant_value)
×
418
                            .offset(::core::mem::offset_of!({shadow_repr_name}, _fields))
×
419
                            .fields(::facet::Struct::builder().struct_().fields(fields).build(),
×
420
                            {maybe_doc}
×
421
                            .build()
×
422
                    }}",
×
423
                ));
424
            }
425
        }
426
    }
427

428
    ProcessedEnumBody {
429
        shadow_struct_defs,
430
        variant_expressions,
UNCOV
431
        repr_type: discriminant_type.map_or_else(
×
432
            || format!("from_discriminant_size::<{shadow_discriminant_name}>()"),
433
            |d| d.as_enum_repr().to_string(),
434
        ),
435
    }
436
}
437

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

457
    // Process each variant using enumerate to get discriminant values
UNCOV
458
    for (discriminant_value, var_like) in variants.iter().enumerate() {
×
459
        match &var_like.value {
×
460
            EnumVariantLike::Unit(unit) => {
×
461
                let variant_name = unit.name.to_string();
×
462
                let maybe_doc = build_maybe_doc(&unit.attributes);
×
463

UNCOV
464
                variant_expressions.push(format!(
×
465
                    "::facet::Variant::builder()
×
466
                    .name({variant_name:?})
×
467
                    .discriminant({discriminant_value})
×
468
                    .offset(0)
×
469
                    .fields(::facet::Struct::builder().unit().build())
×
470
                    {maybe_doc}
×
471
                    .build()",
×
472
                ));
473
            }
UNCOV
474
            EnumVariantLike::Tuple(tuple) => {
×
475
                let variant_name = tuple.name.to_string();
×
476
                let maybe_doc = build_maybe_doc(&tuple.attributes);
×
477

478
                // Generate shadow struct for this tuple variant to calculate offsets
UNCOV
479
                let shadow_struct_name = format!("__Shadow{}_{}", enum_name, variant_name);
×
480

481
                // Build the list of fields and types for the shadow struct
UNCOV
482
                let fields_with_types = tuple
×
483
                    .fields
×
484
                    .content
×
485
                    .0
×
486
                    .iter()
487
                    .enumerate()
UNCOV
488
                    .map(|(idx, field)| {
×
489
                        let typ = VerbatimDisplay(&field.value.typ).to_string();
×
490
                        format!("_{}: {}", idx, typ)
×
491
                    })
492
                    .collect::<Vec<String>>()
493
                    .join(", ");
494

495
                // Add shadow struct definition
UNCOV
496
                shadow_struct_defs.push(format!(
×
497
                    "#[repr(C)] struct {shadow_struct_name}<{generics_def}> {where_clauses}  {{ _discriminant: {}, {fields_with_types} }}",
×
498
                    discriminant_type.as_rust_type(),
×
499
                ));
500

501
                // Build the list of field types with calculated offsets
UNCOV
502
                let fields = tuple
×
503
                    .fields
×
504
                    .content
×
505
                    .0
×
506
                    .iter()
507
                    .enumerate()
UNCOV
508
                    .map(|(idx, field)| {
×
509
                        let field_name = format!("_{idx}");
×
510
                        gen_struct_field(
×
511
                            &field_name,
×
512
                            &shadow_struct_name,
×
513
                            generics_use,
×
514
                            &field.value.attributes,
×
515
                        )
516
                    })
517
                    .collect::<Vec<String>>()
518
                    .join(", ");
519

520
                // Add variant expression - now with discriminant
UNCOV
521
                variant_expressions.push(format!(
×
522
                    "{{
×
523
                        let fields: &'static [::facet::Field] = &const {{[
×
524
                            {fields}
×
525
                        ]}};
526

UNCOV
527
                        ::facet::Variant::builder()
×
528
                            .name({variant_name:?})
×
529
                            .discriminant({discriminant_value})
×
530
                            .offset(0)
×
531
                            .fields(::facet::Struct::builder().tuple().fields(fields).build())
×
532
                            {maybe_doc}
×
533
                            .build()
×
534
                    }}",
×
535
                ));
536
            }
UNCOV
537
            EnumVariantLike::Struct(struct_var) => {
×
538
                let variant_name = struct_var.name.to_string();
×
539
                let maybe_doc = build_maybe_doc(&struct_var.attributes);
×
540

541
                // Generate shadow struct for this struct variant to calculate offsets
UNCOV
542
                let shadow_struct_name = format!("__Shadow{}_{}", enum_name, variant_name);
×
543

544
                // Build the list of fields and types
UNCOV
545
                let fields_with_types = struct_var
×
546
                    .fields
×
547
                    .content
×
548
                    .0
×
549
                    .iter()
UNCOV
550
                    .map(|field| {
×
551
                        let name = field.value.name.to_string();
×
552
                        let typ = VerbatimDisplay(&field.value.typ).to_string();
×
553
                        format!("{}: {}", name, typ)
×
554
                    })
555
                    .collect::<Vec<String>>()
556
                    .join(", ");
557

558
                // Add shadow struct definition
UNCOV
559
                shadow_struct_defs.push(format!(
×
560
                    "#[repr(C)] struct {shadow_struct_name}<{generics_def}> {where_clauses} {{ _discriminant: {}, {fields_with_types} }}",
×
561
                    discriminant_type.as_rust_type(),
×
562
                ));
563

564
                // Build the list of field types with calculated offsets
UNCOV
565
                let fields = struct_var
×
566
                    .fields
×
567
                    .content
×
568
                    .0
×
569
                    .iter()
UNCOV
570
                    .map(|field| {
×
571
                        let field_name = field.value.name.to_string();
×
572
                        gen_struct_field(
×
573
                            &field_name,
×
574
                            &shadow_struct_name,
×
575
                            generics_use,
×
576
                            &field.value.attributes,
×
577
                        )
578
                    })
579
                    .collect::<Vec<String>>()
580
                    .join(", ");
581

582
                // Add variant expression - now with discriminant
583
                // variant offset is zero since all fields are
584
                // already computed relative to the discriminant
UNCOV
585
                variant_expressions.push(format!(
×
586
                    "{{
×
587
                        let fields: &'static [::facet::Field] = &const {{[
×
588
                            {fields}
×
589
                        ]}};
590

UNCOV
591
                        ::facet::Variant::builder()
×
592
                            .name({variant_name:?})
×
593
                            .discriminant({discriminant_value})
×
594
                            .offset(0)
×
595
                            .fields(::facet::Struct::builder().struct_().fields(fields).build())
×
596
                            {maybe_doc}
×
597
                            .build()
×
598
                    }}",
×
599
                ));
600
            }
601
        }
602
    }
603

604
    ProcessedEnumBody {
605
        shadow_struct_defs,
606
        variant_expressions,
UNCOV
607
        repr_type: discriminant_type.as_enum_repr().to_string(),
×
608
    }
609
}
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