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

facet-rs / facet / 19992197531

06 Dec 2025 05:58PM UTC coverage: 58.742% (-0.005%) from 58.747%
19992197531

Pull #1118

github

web-flow
Merge 9a6a630f8 into 45a8cb1c3
Pull Request #1118: Reduce/cordon bloat in facet, introduce bloatbench

1142 of 3107 new or added lines in 61 files covered. (36.76%)

533 existing lines in 29 files now uncovered.

24225 of 41240 relevant lines covered (58.74%)

502.48 hits per line

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

90.29
/facet-macros-impl/src/process_struct.rs
1
//! Struct processing and vtable generation for the Facet derive macro.
2
//!
3
//! # Vtable Trait Detection
4
//!
5
//! The vtable contains function pointers for various trait implementations (Debug, Clone,
6
//! PartialEq, etc.). There are three ways these can be populated:
7
//!
8
//! ## 1. Derive Detection (Fastest - No Specialization)
9
//!
10
//! When `#[derive(Debug, Clone, Facet)]` is used, the macro can see the other derives
11
//! and knows those traits are implemented. It generates direct function pointers without
12
//! any specialization overhead.
13
//!
14
//! ```ignore
15
//! #[derive(Debug, Clone, Facet)]  // Debug and Clone detected from derives
16
//! struct Foo { ... }
17
//! ```
18
//!
19
//! ## 2. Explicit Declaration (No Specialization)
20
//!
21
//! For traits that are implemented manually (not via derive), use `#[facet(traits(...))]`:
22
//!
23
//! ```ignore
24
//! #[derive(Facet)]
25
//! #[facet(traits(Debug, PartialEq))]  // Explicit declaration
26
//! struct Foo { ... }
27
//!
28
//! impl Debug for Foo { ... }  // Manual implementation
29
//! impl PartialEq for Foo { ... }
30
//! ```
31
//!
32
//! This generates compile-time assertions to verify the traits are actually implemented.
33
//!
34
//! ## 3. Auto-Detection (Uses Specialization)
35
//!
36
//! For backward compatibility or when you don't want to list traits manually, use
37
//! `#[facet(auto_traits)]`. This uses the `impls!` macro to detect traits at compile
38
//! time via specialization tricks:
39
//!
40
//! ```ignore
41
//! #[derive(Debug, Facet)]
42
//! #[facet(auto_traits)]  // Auto-detect all other traits
43
//! struct Foo { ... }
44
//! ```
45
//!
46
//! **Note:** Auto-detection is slower to compile because it generates specialization
47
//! code for each trait. Use derive detection or explicit declaration when possible.
48
//!
49
//! ## Layered Resolution
50
//!
51
//! For each vtable entry, the macro checks sources in order:
52
//! 1. Is the trait in `#[derive(...)]`? → Use direct impl
53
//! 2. Is the trait in `#[facet(traits(...))]`? → Use direct impl
54
//! 3. Is `#[facet(auto_traits)]` present? → Use `impls!` detection
55
//! 4. Otherwise → Set to `None`
56
//!
57
//! Note: `#[facet(traits(...))]` and `#[facet(auto_traits)]` are mutually exclusive.
58
//! You can combine derives with either one:
59
//! ```ignore
60
//! #[derive(Debug, Clone, Facet)]  // Debug, Clone detected from derives
61
//! #[facet(traits(Display))]       // Display declared explicitly (manual impl)
62
//! struct Foo { ... }
63
//! ```
64

65
use quote::{format_ident, quote, quote_spanned};
66

67
use super::*;
68
use crate::parsed::{DeclaredTraits, KnownDerives, PAttrs};
69

70
/// Sources of trait information for vtable generation.
71
///
72
/// The vtable generation uses a layered approach:
73
/// 1. **Derives** - traits detected from `#[derive(...)]` next to `#[derive(Facet)]`
74
/// 2. **Declared** - traits explicitly listed in `#[facet(traits(...))]`
75
/// 3. **Implied** - traits implied by other attributes (e.g., `#[facet(default)]` implies Default)
76
/// 4. **Auto** - if `#[facet(auto_traits)]` is present, use `impls!` for remaining traits
77
/// 5. **None** - if none of the above apply, emit `None` for that trait
78
pub(crate) struct TraitSources<'a> {
79
    /// Traits detected from #[derive(...)] attributes
80
    pub known_derives: &'a KnownDerives,
81
    /// Traits explicitly declared via #[facet(traits(...))]
82
    pub declared_traits: Option<&'a DeclaredTraits>,
83
    /// Whether to auto-detect remaining traits via specialization
84
    pub auto_traits: bool,
85
    /// Whether `#[facet(default)]` is present (implies Default trait)
86
    pub facet_default: bool,
87
}
88

89
impl<'a> TraitSources<'a> {
90
    /// Create trait sources from parsed attributes
91
    pub fn from_attrs(attrs: &'a PAttrs) -> Self {
1,970✔
92
        Self {
1,970✔
93
            known_derives: &attrs.known_derives,
1,970✔
94
            declared_traits: attrs.declared_traits.as_ref(),
1,970✔
95
            auto_traits: attrs.auto_traits,
1,970✔
96
            facet_default: attrs.has_builtin("default"),
1,970✔
97
        }
1,970✔
98
    }
1,970✔
99

100
    /// Check if a trait is known from derives
101
    fn has_derive(&self, check: impl FnOnce(&KnownDerives) -> bool) -> bool {
17,788✔
102
        check(self.known_derives)
17,788✔
103
    }
17,788✔
104

105
    /// Check if a trait is explicitly declared
106
    fn has_declared(&self, check: impl FnOnce(&DeclaredTraits) -> bool) -> bool {
25,755✔
107
        self.declared_traits.is_some_and(check)
25,755✔
108
    }
25,755✔
109

110
    /// Check if we should use auto-detection for this trait
111
    fn should_auto(&self) -> bool {
17,725✔
112
        self.auto_traits
17,725✔
113
    }
17,725✔
114
}
115

116
/// Generates the vtable for a type based on trait sources.
117
///
118
/// Uses a layered approach for each trait:
119
/// 1. If known from derives → direct impl (no specialization)
120
/// 2. If explicitly declared → direct impl (no specialization)
121
/// 3. If auto_traits enabled → use `impls!` macro for detection
122
/// 4. Otherwise → None
123
pub(crate) fn gen_vtable(
1,970✔
124
    facet_crate: &TokenStream,
1,970✔
125
    type_name_fn: &TokenStream,
1,970✔
126
    sources: &TraitSources<'_>,
1,970✔
127
) -> TokenStream {
1,970✔
128
    // Helper to generate a direct implementation (no specialization)
129
    let direct_display = quote! {
1,970✔
130
        Some(|data, f| {
131
            let data = unsafe { data.get::<Self>() };
132
            core::fmt::Display::fmt(data, f)
133
        })
134
    };
135
    let direct_debug = quote! {
1,970✔
136
        Some(|data, f| {
137
            let data = unsafe { data.get::<Self>() };
138
            core::fmt::Debug::fmt(data, f)
139
        })
140
    };
141
    let direct_default = quote! {
1,970✔
142
        Some(|target| unsafe {
143
            target.put(<Self as core::default::Default>::default())
144
        })
145
    };
146
    let direct_clone = quote! {
1,970✔
147
        Some(|src, dst| unsafe {
148
            let src = src.get::<Self>();
149
            dst.put(<Self as core::clone::Clone>::clone(src))
150
        })
151
    };
152
    let direct_partial_eq = quote! {
1,970✔
153
        Some(|left, right| {
154
            let left = unsafe { left.get::<Self>() };
155
            let right = unsafe { right.get::<Self>() };
156
            <Self as core::cmp::PartialEq>::eq(left, right)
157
        })
158
    };
159
    let direct_partial_ord = quote! {
1,970✔
160
        Some(|left, right| {
161
            let left = unsafe { left.get::<Self>() };
162
            let right = unsafe { right.get::<Self>() };
163
            <Self as core::cmp::PartialOrd>::partial_cmp(left, right)
164
        })
165
    };
166
    let direct_ord = quote! {
1,970✔
167
        Some(|left, right| {
168
            let left = unsafe { left.get::<Self>() };
169
            let right = unsafe { right.get::<Self>() };
170
            <Self as core::cmp::Ord>::cmp(left, right)
171
        })
172
    };
173
    let direct_hash = quote! {
1,970✔
174
        Some(|value, hasher| {
175
            let value = unsafe { value.get::<Self>() };
176
            <Self as core::hash::Hash>::hash(value, hasher)
177
        })
178
    };
179

180
    // Auto-detection versions using spez
181
    let auto_display = quote! {
1,970✔
182
        if #facet_crate::spez::impls!(Self: core::fmt::Display) {
183
            Some(|data, f| {
184
                let data = unsafe { data.get::<Self>() };
185
                use #facet_crate::spez::*;
186
                (&&Spez(data)).spez_display(f)
187
            })
188
        } else {
189
            None
190
        }
191
    };
192
    let auto_debug = quote! {
1,970✔
193
        if #facet_crate::spez::impls!(Self: core::fmt::Debug) {
194
            Some(|data, f| {
195
                let data = unsafe { data.get::<Self>() };
196
                use #facet_crate::spez::*;
197
                (&&Spez(data)).spez_debug(f)
198
            })
199
        } else {
200
            None
201
        }
202
    };
203
    let auto_default = quote! {
1,970✔
204
        if #facet_crate::spez::impls!(Self: core::default::Default) {
205
            Some(|target| unsafe {
206
                use #facet_crate::spez::*;
207
                (&&SpezEmpty::<Self>::SPEZ).spez_default_in_place(target)
208
            })
209
        } else {
210
            None
211
        }
212
    };
213
    let auto_clone = quote! {
1,970✔
214
        if #facet_crate::spez::impls!(Self: core::clone::Clone) {
215
            Some(|src, dst| unsafe {
216
                use #facet_crate::spez::*;
217
                let src = src.get::<Self>();
218
                (&&Spez(src)).spez_clone_into(dst)
219
            })
220
        } else {
221
            None
222
        }
223
    };
224
    let auto_partial_eq = quote! {
1,970✔
225
        if #facet_crate::spez::impls!(Self: core::cmp::PartialEq) {
226
            Some(|left, right| {
227
                let left = unsafe { left.get::<Self>() };
228
                let right = unsafe { right.get::<Self>() };
229
                use #facet_crate::spez::*;
230
                (&&Spez(left)).spez_partial_eq(&&Spez(right))
231
            })
232
        } else {
233
            None
234
        }
235
    };
236
    let auto_partial_ord = quote! {
1,970✔
237
        if #facet_crate::spez::impls!(Self: core::cmp::PartialOrd) {
238
            Some(|left, right| {
239
                let left = unsafe { left.get::<Self>() };
240
                let right = unsafe { right.get::<Self>() };
241
                use #facet_crate::spez::*;
242
                (&&Spez(left)).spez_partial_cmp(&&Spez(right))
243
            })
244
        } else {
245
            None
246
        }
247
    };
248
    let auto_ord = quote! {
1,970✔
249
        if #facet_crate::spez::impls!(Self: core::cmp::Ord) {
250
            Some(|left, right| {
251
                let left = unsafe { left.get::<Self>() };
252
                let right = unsafe { right.get::<Self>() };
253
                use #facet_crate::spez::*;
254
                (&&Spez(left)).spez_cmp(&&Spez(right))
255
            })
256
        } else {
257
            None
258
        }
259
    };
260
    let auto_hash = quote! {
1,970✔
261
        if #facet_crate::spez::impls!(Self: core::hash::Hash) {
262
            Some(|value, hasher| {
263
                let value = unsafe { value.get::<Self>() };
264
                use #facet_crate::spez::*;
265
                (&&Spez(value)).spez_hash(&mut { hasher })
266
            })
267
        } else {
268
            None
269
        }
270
    };
271
    let auto_parse = quote! {
1,970✔
272
        if #facet_crate::spez::impls!(Self: core::str::FromStr) {
273
            Some(|s, target| {
274
                use #facet_crate::spez::*;
275
                unsafe { (&&SpezEmpty::<Self>::SPEZ).spez_parse(s, target) }
276
            })
277
        } else {
278
            None
279
        }
280
    };
281

282
    let none = quote! { None };
1,970✔
283

284
    // For each trait: derive > declared > auto > none
285
    // Display: no derive exists, so check declared then auto
286
    let display_entry = if sources.has_declared(|d| d.display) {
1,970✔
NEW
287
        direct_display
×
288
    } else if sources.should_auto() {
1,970✔
289
        auto_display
29✔
290
    } else {
291
        none.clone()
1,941✔
292
    };
293

294
    // Debug: check derive, then declared, then auto
295
    let debug_entry = if sources.has_derive(|d| d.debug) || sources.has_declared(|d| d.debug) {
1,970✔
296
        direct_debug
2✔
297
    } else if sources.should_auto() {
1,968✔
298
        auto_debug
29✔
299
    } else {
300
        none.clone()
1,939✔
301
    };
302

303
    // Default: check derive, then declared, then facet(default), then auto
304
    // Note: #[facet(default)] implies the type implements Default
305
    let default_entry = if sources.has_derive(|d| d.default)
1,970✔
306
        || sources.has_declared(|d| d.default)
1,970✔
307
        || sources.facet_default
1,970✔
308
    {
309
        direct_default
3✔
310
    } else if sources.should_auto() {
1,967✔
311
        auto_default
29✔
312
    } else {
313
        none.clone()
1,938✔
314
    };
315

316
    // Clone: check derive (including Copy which implies Clone), then declared, then auto
317
    let clone_entry = if sources.has_derive(|d| d.clone || d.copy)
1,970✔
318
        || sources.has_declared(|d| d.clone || d.copy)
1,970✔
319
    {
NEW
320
        direct_clone
×
321
    } else if sources.should_auto() {
1,970✔
322
        auto_clone
29✔
323
    } else {
324
        none.clone()
1,941✔
325
    };
326

327
    // PartialEq: check derive, then declared, then auto
328
    let partial_eq_entry =
1,970✔
329
        if sources.has_derive(|d| d.partial_eq) || sources.has_declared(|d| d.partial_eq) {
1,970✔
NEW
330
            direct_partial_eq
×
331
        } else if sources.should_auto() {
1,970✔
332
            auto_partial_eq
29✔
333
        } else {
334
            none.clone()
1,941✔
335
        };
336

337
    // PartialOrd: check derive, then declared, then auto
338
    let partial_ord_entry =
1,970✔
339
        if sources.has_derive(|d| d.partial_ord) || sources.has_declared(|d| d.partial_ord) {
1,970✔
NEW
340
            direct_partial_ord
×
341
        } else if sources.should_auto() {
1,970✔
342
            auto_partial_ord
29✔
343
        } else {
344
            none.clone()
1,941✔
345
        };
346

347
    // Ord: check derive, then declared, then auto
348
    let ord_entry = if sources.has_derive(|d| d.ord) || sources.has_declared(|d| d.ord) {
1,970✔
NEW
349
        direct_ord
×
350
    } else if sources.should_auto() {
1,970✔
351
        auto_ord
29✔
352
    } else {
353
        none.clone()
1,941✔
354
    };
355

356
    // Hash: check derive, then declared, then auto
357
    let hash_entry = if sources.has_derive(|d| d.hash) || sources.has_declared(|d| d.hash) {
1,970✔
NEW
358
        direct_hash
×
359
    } else if sources.should_auto() {
1,970✔
360
        auto_hash
29✔
361
    } else {
362
        none.clone()
1,941✔
363
    };
364

365
    // Parse (FromStr): no derive exists, only auto-detect if enabled
366
    let parse_entry = if sources.should_auto() {
1,970✔
367
        auto_parse
29✔
368
    } else {
369
        none.clone()
1,941✔
370
    };
371

372
    // Marker traits - these set bitflags in MarkerTraits
373
    // Copy: derive (Copy implies Clone), declared, or auto
374
    let has_copy =
1,970✔
375
        sources.has_derive(|d| d.copy) || sources.has_declared(|d| d.copy) || sources.auto_traits;
1,970✔
376
    // Send: declared or auto (no standard derive for Send)
377
    let has_send = sources.has_declared(|d| d.send) || sources.auto_traits;
1,970✔
378
    // Sync: declared or auto (no standard derive for Sync)
379
    let has_sync = sources.has_declared(|d| d.sync) || sources.auto_traits;
1,970✔
380
    // Eq: derive (PartialEq + Eq), declared, or auto
381
    let has_eq =
1,970✔
382
        sources.has_derive(|d| d.eq) || sources.has_declared(|d| d.eq) || sources.auto_traits;
1,970✔
383
    // Unpin: declared or auto (no standard derive for Unpin)
384
    let has_unpin = sources.has_declared(|d| d.unpin) || sources.auto_traits;
1,970✔
385

386
    // Build markers expression
387
    let markers_entry = if has_copy || has_send || has_sync || has_eq || has_unpin {
1,970✔
388
        // At least one marker trait might be set
389
        let copy_check = if has_copy
29✔
390
            && sources.auto_traits
29✔
391
            && !sources.has_derive(|d| d.copy)
29✔
392
            && !sources.has_declared(|d| d.copy)
29✔
393
        {
394
            // Auto-detect Copy
395
            quote! {
29✔
396
                if #facet_crate::spez::impls!(Self: core::marker::Copy) {
397
                    markers = markers.with_copy();
398
                }
399
            }
NEW
400
        } else if sources.has_derive(|d| d.copy) || sources.has_declared(|d| d.copy) {
×
401
            // Directly known to be Copy
NEW
402
            quote! { markers = markers.with_copy(); }
×
403
        } else {
NEW
404
            quote! {}
×
405
        };
406

407
        let send_check = if has_send && sources.auto_traits && !sources.has_declared(|d| d.send) {
29✔
408
            quote! {
29✔
409
                if #facet_crate::spez::impls!(Self: core::marker::Send) {
410
                    markers = markers.with_send();
411
                }
412
            }
NEW
413
        } else if sources.has_declared(|d| d.send) {
×
NEW
414
            quote! { markers = markers.with_send(); }
×
415
        } else {
NEW
416
            quote! {}
×
417
        };
418

419
        let sync_check = if has_sync && sources.auto_traits && !sources.has_declared(|d| d.sync) {
29✔
420
            quote! {
29✔
421
                if #facet_crate::spez::impls!(Self: core::marker::Sync) {
422
                    markers = markers.with_sync();
423
                }
424
            }
NEW
425
        } else if sources.has_declared(|d| d.sync) {
×
NEW
426
            quote! { markers = markers.with_sync(); }
×
427
        } else {
NEW
428
            quote! {}
×
429
        };
430

431
        let eq_check = if has_eq
29✔
432
            && sources.auto_traits
29✔
433
            && !sources.has_derive(|d| d.eq)
29✔
434
            && !sources.has_declared(|d| d.eq)
29✔
435
        {
436
            quote! {
29✔
437
                if #facet_crate::spez::impls!(Self: core::cmp::Eq) {
438
                    markers = markers.with_eq();
439
                }
440
            }
NEW
441
        } else if sources.has_derive(|d| d.eq) || sources.has_declared(|d| d.eq) {
×
NEW
442
            quote! { markers = markers.with_eq(); }
×
443
        } else {
NEW
444
            quote! {}
×
445
        };
446

447
        let unpin_check = if has_unpin && sources.auto_traits && !sources.has_declared(|d| d.unpin)
29✔
448
        {
449
            quote! {
29✔
450
                if #facet_crate::spez::impls!(Self: core::marker::Unpin) {
451
                    markers = markers.with_unpin();
452
                }
453
            }
NEW
454
        } else if sources.has_declared(|d| d.unpin) {
×
NEW
455
            quote! { markers = markers.with_unpin(); }
×
456
        } else {
NEW
457
            quote! {}
×
458
        };
459

460
        quote! {{
29✔
461
            let mut markers = #facet_crate::MarkerTraits::EMPTY;
462
            #copy_check
463
            #send_check
464
            #sync_check
465
            #eq_check
466
            #unpin_check
467
            markers
468
        }}
469
    } else {
470
        quote! { #facet_crate::MarkerTraits::EMPTY }
1,941✔
471
    };
472

473
    quote! {
1,970✔
474
        #facet_crate::ValueVTable::builder(#type_name_fn)
475
            .drop_in_place(#facet_crate::ValueVTable::drop_in_place_for::<Self>())
476
            .display_opt({ #display_entry })
477
            .debug_opt({ #debug_entry })
478
            .default_in_place_opt({ #default_entry })
479
            .clone_into_opt({ #clone_entry })
480
            .partial_eq_opt({ #partial_eq_entry })
481
            .partial_ord_opt({ #partial_ord_entry })
482
            .ord_opt({ #ord_entry })
483
            .hash_opt({ #hash_entry })
484
            .parse_opt({ #parse_entry })
485
            .markers({ #markers_entry })
486
            .build()
487
    }
488
}
1,970✔
489

490
/// Generate trait bounds for static assertions.
491
/// Returns a TokenStream of bounds like `core::fmt::Debug + core::clone::Clone`
492
/// that can be used in a where clause.
493
///
494
/// `facet_default` is true when `#[facet(default)]` is present, which implies Default.
495
pub(crate) fn gen_trait_bounds(
1,970✔
496
    declared: Option<&DeclaredTraits>,
1,970✔
497
    facet_default: bool,
1,970✔
498
) -> Option<TokenStream> {
1,970✔
499
    let mut bounds = Vec::new();
1,970✔
500

501
    if let Some(declared) = declared {
1,970✔
502
        if declared.display {
2✔
NEW
503
            bounds.push(quote! { core::fmt::Display });
×
504
        }
2✔
505
        if declared.debug {
2✔
506
            bounds.push(quote! { core::fmt::Debug });
2✔
507
        }
2✔
508
        if declared.clone {
2✔
NEW
509
            bounds.push(quote! { core::clone::Clone });
×
510
        }
2✔
511
        if declared.copy {
2✔
NEW
512
            bounds.push(quote! { core::marker::Copy });
×
513
        }
2✔
514
        if declared.partial_eq {
2✔
NEW
515
            bounds.push(quote! { core::cmp::PartialEq });
×
516
        }
2✔
517
        if declared.eq {
2✔
NEW
518
            bounds.push(quote! { core::cmp::Eq });
×
519
        }
2✔
520
        if declared.partial_ord {
2✔
NEW
521
            bounds.push(quote! { core::cmp::PartialOrd });
×
522
        }
2✔
523
        if declared.ord {
2✔
NEW
524
            bounds.push(quote! { core::cmp::Ord });
×
525
        }
2✔
526
        if declared.hash {
2✔
NEW
527
            bounds.push(quote! { core::hash::Hash });
×
528
        }
2✔
529
        if declared.default {
2✔
NEW
530
            bounds.push(quote! { core::default::Default });
×
531
        }
2✔
532
        if declared.send {
2✔
NEW
533
            bounds.push(quote! { core::marker::Send });
×
534
        }
2✔
535
        if declared.sync {
2✔
NEW
536
            bounds.push(quote! { core::marker::Sync });
×
537
        }
2✔
538
        if declared.unpin {
2✔
NEW
539
            bounds.push(quote! { core::marker::Unpin });
×
540
        }
2✔
541
    }
1,968✔
542

543
    // #[facet(default)] implies Default trait
544
    if facet_default && !declared.is_some_and(|d| d.default) {
1,970✔
545
        bounds.push(quote! { core::default::Default });
3✔
546
    }
1,967✔
547

548
    if bounds.is_empty() {
1,970✔
549
        None
1,965✔
550
    } else {
551
        Some(quote! { #(#bounds)+* })
5✔
552
    }
553
}
1,970✔
554

555
/// Generates the `::facet::Field` definition `TokenStream` from a `PStructField`.
556
pub(crate) fn gen_field_from_pfield(
3,377✔
557
    field: &PStructField,
3,377✔
558
    struct_name: &Ident,
3,377✔
559
    bgp: &BoundedGenericParams,
3,377✔
560
    base_offset: Option<TokenStream>,
3,377✔
561
    facet_crate: &TokenStream,
3,377✔
562
) -> TokenStream {
3,377✔
563
    let field_name_effective = &field.name.effective;
3,377✔
564
    let field_name_raw = &field.name.raw;
3,377✔
565
    let field_type = &field.ty;
3,377✔
566

567
    let bgp_without_bounds = bgp.display_without_bounds();
3,377✔
568

569
    let doc_lines: Vec<String> = field
3,377✔
570
        .attrs
3,377✔
571
        .doc
3,377✔
572
        .iter()
3,377✔
573
        .map(|doc| doc.as_str().replace("\\\"", "\""))
3,377✔
574
        .collect();
3,377✔
575

576
    // Generate the shape expression directly using the field type
577
    // For opaque fields, wrap in Opaque<T>
578
    // NOTE: Uses short alias from `use #facet_crate::𝟋::*` in the enclosing const block
579
    let shape_expr = if field.attrs.has_builtin("opaque") {
3,377✔
580
        quote! { <#facet_crate::Opaque<#field_type> as 𝟋Fct>::SHAPE }
33✔
581
    } else {
582
        quote! { <#field_type as 𝟋Fct>::SHAPE }
3,344✔
583
    };
584

585
    // All attributes go through grammar dispatch
586
    // Note: deserialize_with and serialize_with have been REMOVED from the grammar.
587
    // Use #[facet(proxy = Type)] for custom serialization instead.
588
    let mut attribute_list: Vec<TokenStream> = field
3,377✔
589
        .attrs
3,377✔
590
        .facet
3,377✔
591
        .iter()
3,377✔
592
        .map(|attr| {
3,377✔
593
            let ext_attr = emit_attr_for_field(attr, field_name_raw, field_type, facet_crate);
1,464✔
594
            quote! { #ext_attr }
1,464✔
595
        })
1,464✔
596
        .collect();
3,377✔
597

598
    // Generate proxy conversion function pointers when proxy attribute is present
599
    if let Some(attr) = field
3,377✔
600
        .attrs
3,377✔
601
        .facet
3,377✔
602
        .iter()
3,377✔
603
        .find(|a| a.is_builtin() && a.key_str() == "proxy")
3,377✔
604
    {
39✔
605
        let proxy_type = &attr.args;
39✔
606

39✔
607
        // Generate __proxy_in: converts proxy -> field type via TryFrom
39✔
608
        attribute_list.push(quote! {
39✔
609
            #facet_crate::ExtensionAttr {
39✔
610
                ns: ::core::option::Option::None,
39✔
611
                key: "__proxy_in",
39✔
612
                data: &const {
39✔
613
                    extern crate alloc as __alloc;
39✔
614
                    unsafe fn __proxy_convert_in<'mem>(
39✔
615
                        proxy_ptr: #facet_crate::PtrConst<'mem>,
39✔
616
                        field_ptr: #facet_crate::PtrUninit<'mem>,
39✔
617
                    ) -> ::core::result::Result<#facet_crate::PtrMut<'mem>, __alloc::string::String> {
39✔
618
                        let proxy: #proxy_type = proxy_ptr.read();
39✔
619
                        match <#field_type as ::core::convert::TryFrom<#proxy_type>>::try_from(proxy) {
39✔
620
                            ::core::result::Result::Ok(value) => ::core::result::Result::Ok(field_ptr.put(value)),
39✔
621
                            ::core::result::Result::Err(e) => ::core::result::Result::Err(__alloc::string::ToString::to_string(&e)),
39✔
622
                        }
39✔
623
                    }
39✔
624
                    __proxy_convert_in as #facet_crate::ProxyConvertInFn
39✔
625
                } as *const #facet_crate::ProxyConvertInFn as *const (),
39✔
626
                shape: <() as #facet_crate::Facet>::SHAPE,
39✔
627
            }
39✔
628
        });
39✔
629

39✔
630
        // Generate __proxy_out: converts &field type -> proxy via TryFrom
39✔
631
        attribute_list.push(quote! {
39✔
632
            #facet_crate::ExtensionAttr {
39✔
633
                ns: ::core::option::Option::None,
39✔
634
                key: "__proxy_out",
39✔
635
                data: &const {
39✔
636
                    extern crate alloc as __alloc;
39✔
637
                    unsafe fn __proxy_convert_out<'mem>(
39✔
638
                        field_ptr: #facet_crate::PtrConst<'mem>,
39✔
639
                        proxy_ptr: #facet_crate::PtrUninit<'mem>,
39✔
640
                    ) -> ::core::result::Result<#facet_crate::PtrMut<'mem>, __alloc::string::String> {
39✔
641
                        let field_ref: &#field_type = field_ptr.get();
39✔
642
                        match <#proxy_type as ::core::convert::TryFrom<&#field_type>>::try_from(field_ref) {
39✔
643
                            ::core::result::Result::Ok(proxy) => ::core::result::Result::Ok(proxy_ptr.put(proxy)),
39✔
644
                            ::core::result::Result::Err(e) => ::core::result::Result::Err(__alloc::string::ToString::to_string(&e)),
39✔
645
                        }
39✔
646
                    }
39✔
647
                    __proxy_convert_out as #facet_crate::ProxyConvertOutFn
39✔
648
                } as *const #facet_crate::ProxyConvertOutFn as *const (),
39✔
649
                shape: <() as #facet_crate::Facet>::SHAPE,
39✔
650
            }
39✔
651
        });
39✔
652
    }
3,338✔
653

654
    let maybe_attributes = if attribute_list.is_empty() {
3,377✔
655
        quote! { &[] }
2,241✔
656
    } else {
657
        quote! { &const {[#(#attribute_list),*]} }
1,136✔
658
    };
659

660
    let maybe_field_doc = if doc_lines.is_empty() {
3,377✔
661
        quote! { &[] }
3,313✔
662
    } else {
663
        quote! { &[#(#doc_lines),*] }
64✔
664
    };
665

666
    // Calculate the final offset, incorporating the base_offset if present
667
    let final_offset = match base_offset {
3,377✔
668
        Some(base) => {
127✔
669
            quote! { #base + ::core::mem::offset_of!(#struct_name #bgp_without_bounds, #field_name_raw) }
127✔
670
        }
671
        None => {
672
            quote! { ::core::mem::offset_of!(#struct_name #bgp_without_bounds, #field_name_raw) }
3,250✔
673
        }
674
    };
675

676
    // Use FieldBuilder for more compact generated code
677
    // NOTE: Uses short alias from `use #facet_crate::𝟋::*` in the enclosing const block
678
    let builder = quote! {
3,377✔
679
        𝟋FldB::new(
680
            #field_name_effective,
681
            || #shape_expr,
682
            #final_offset,
683
        )
684
    };
685

686
    // Only chain .attributes() and .doc() if they have values
687
    let has_attrs = !attribute_list.is_empty();
3,377✔
688
    let has_doc = !doc_lines.is_empty();
3,377✔
689

690
    if has_attrs && has_doc {
3,377✔
691
        quote! { #builder.attributes(#maybe_attributes).doc(#maybe_field_doc).build() }
49✔
692
    } else if has_attrs {
3,328✔
693
        quote! { #builder.attributes(#maybe_attributes).build() }
1,087✔
694
    } else if has_doc {
2,241✔
695
        quote! { #builder.doc(#maybe_field_doc).build() }
15✔
696
    } else {
697
        quote! { #builder.build() }
2,226✔
698
    }
699
}
3,377✔
700

701
/// Processes a regular struct to implement Facet
702
///
703
/// Example input:
704
/// ```rust
705
/// struct Blah {
706
///     foo: u32,
707
///     bar: String,
708
/// }
709
/// ```
710
pub(crate) fn process_struct(parsed: Struct) -> TokenStream {
1,694✔
711
    let ps = PStruct::parse(&parsed); // Use the parsed representation
1,694✔
712

713
    // Emit any collected errors as compile_error! with proper spans
714
    if !ps.container.attrs.errors.is_empty() {
1,694✔
715
        let errors = ps.container.attrs.errors.iter().map(|e| {
×
716
            let msg = &e.message;
×
717
            let span = e.span;
×
718
            quote_spanned! { span => compile_error!(#msg); }
×
719
        });
×
720
        return quote! { #(#errors)* };
×
721
    }
1,694✔
722

723
    let struct_name_ident = format_ident!("{}", ps.container.name);
1,694✔
724
    let struct_name = &ps.container.name;
1,694✔
725
    let struct_name_str = struct_name.to_string();
1,694✔
726

727
    let opaque = ps.container.attrs.has_builtin("opaque");
1,694✔
728

729
    // Get the facet crate path (custom or default ::facet)
730
    let facet_crate = ps.container.attrs.facet_crate();
1,694✔
731

732
    let type_name_fn =
1,694✔
733
        generate_type_name_fn(struct_name, parsed.generics.as_ref(), opaque, &facet_crate);
1,694✔
734

735
    // Determine trait sources and generate vtable accordingly
736
    let trait_sources = TraitSources::from_attrs(&ps.container.attrs);
1,694✔
737
    let vtable_code = gen_vtable(&facet_crate, &type_name_fn, &trait_sources);
1,694✔
738
    let vtable_init = quote! { const { #vtable_code } };
1,694✔
739

740
    // TODO: I assume the `PrimitiveRepr` is only relevant for enums, and does not need to be preserved?
741
    let repr = match &ps.container.attrs.repr {
1,694✔
742
        PRepr::Transparent => quote! { #facet_crate::Repr::transparent() },
4✔
743
        PRepr::Rust(_) => quote! { #facet_crate::Repr::default() },
1,689✔
744
        PRepr::C(_) => quote! { #facet_crate::Repr::c() },
1✔
745
        PRepr::RustcWillCatch => {
746
            // rustc will emit an error for the invalid repr.
747
            // Return empty TokenStream so we don't add misleading errors.
748
            return quote! {};
×
749
        }
750
    };
751

752
    // Use PStruct for kind and fields
753
    let (kind, fields_vec) = match &ps.kind {
1,694✔
754
        PStructKind::Struct { fields } => {
1,591✔
755
            let kind = quote!(𝟋Sk::Struct);
1,591✔
756
            let fields_vec = fields
1,591✔
757
                .iter()
1,591✔
758
                .map(|field| {
2,665✔
759
                    gen_field_from_pfield(field, struct_name, &ps.container.bgp, None, &facet_crate)
2,665✔
760
                })
2,665✔
761
                .collect::<Vec<_>>();
1,591✔
762
            (kind, fields_vec)
1,591✔
763
        }
764
        PStructKind::TupleStruct { fields } => {
95✔
765
            let kind = quote!(𝟋Sk::TupleStruct);
95✔
766
            let fields_vec = fields
95✔
767
                .iter()
95✔
768
                .map(|field| {
118✔
769
                    gen_field_from_pfield(field, struct_name, &ps.container.bgp, None, &facet_crate)
118✔
770
                })
118✔
771
                .collect::<Vec<_>>();
95✔
772
            (kind, fields_vec)
95✔
773
        }
774
        PStructKind::UnitStruct => {
775
            let kind = quote!(𝟋Sk::Unit);
8✔
776
            (kind, vec![])
8✔
777
        }
778
    };
779

780
    // Still need original AST for where clauses and type params for build_ helpers
781
    let where_clauses_ast = match &parsed.kind {
1,694✔
782
        StructKind::Struct { clauses, .. } => clauses.as_ref(),
1,591✔
783
        StructKind::TupleStruct { clauses, .. } => clauses.as_ref(),
95✔
784
        StructKind::UnitStruct { clauses, .. } => clauses.as_ref(),
8✔
785
    };
786
    let where_clauses = build_where_clauses(
1,694✔
787
        where_clauses_ast,
1,694✔
788
        parsed.generics.as_ref(),
1,694✔
789
        opaque,
1,694✔
790
        &facet_crate,
1,694✔
791
    );
792
    let type_params = build_type_params(parsed.generics.as_ref(), opaque, &facet_crate);
1,694✔
793

794
    // Static decl using PStruct BGP
795
    let static_decl = if ps.container.bgp.params.is_empty() {
1,694✔
796
        generate_static_decl(struct_name, &facet_crate)
1,628✔
797
    } else {
798
        TokenStream::new()
66✔
799
    };
800

801
    // Doc comments from PStruct - returns value for struct literal
802
    let doc_field = if ps.container.attrs.doc.is_empty() {
1,694✔
803
        quote! { &[] }
1,662✔
804
    } else {
805
        let doc_lines = ps.container.attrs.doc.iter().map(|s| quote!(#s));
118✔
806
        quote! { &[#(#doc_lines),*] }
32✔
807
    };
808

809
    // Container attributes - most go through grammar dispatch
810
    // Filter out `invariants` and `crate` since they're handled specially
811
    // Returns value for struct literal
812
    let attributes_field = {
1,694✔
813
        let items: Vec<TokenStream> = ps
1,694✔
814
            .container
1,694✔
815
            .attrs
1,694✔
816
            .facet
1,694✔
817
            .iter()
1,694✔
818
            .filter(|attr| {
1,694✔
819
                // These attributes are handled specially and not emitted to runtime:
820
                // - invariants: populates vtable.invariants
821
                // - crate: sets the facet crate path
822
                // - traits: compile-time directive for vtable generation
823
                // - auto_traits: compile-time directive for vtable generation
824
                if attr.is_builtin() {
163✔
825
                    let key = attr.key_str();
148✔
826
                    !matches!(
34✔
827
                        key.as_str(),
148✔
828
                        "invariants" | "crate" | "traits" | "auto_traits"
148✔
829
                    )
830
                } else {
831
                    true
15✔
832
                }
833
            })
163✔
834
            .map(|attr| {
1,694✔
835
                let ext_attr = emit_attr(attr, &facet_crate);
129✔
836
                quote! { #ext_attr }
129✔
837
            })
129✔
838
            .collect();
1,694✔
839

840
        if items.is_empty() {
1,694✔
841
            quote! { &[] }
1,585✔
842
        } else {
843
            quote! { &const {[#(#items),*]} }
109✔
844
        }
845
    };
846

847
    // Type tag from PStruct - returns value for struct literal
848
    let type_tag_field = {
1,694✔
849
        if let Some(type_tag) = ps.container.attrs.get_builtin_args("type_tag") {
1,694✔
850
            quote! { Some(#type_tag) }
8✔
851
        } else {
852
            quote! { None }
1,686✔
853
        }
854
    };
855

856
    // Invariants from PStruct - extract invariant function expressions
857
    let invariant_maybe = {
1,694✔
858
        let invariant_exprs: Vec<&TokenStream> = ps
1,694✔
859
            .container
1,694✔
860
            .attrs
1,694✔
861
            .facet
1,694✔
862
            .iter()
1,694✔
863
            .filter(|attr| attr.is_builtin() && attr.key_str() == "invariants")
1,694✔
864
            .map(|attr| &attr.args)
1,694✔
865
            .collect();
1,694✔
866

867
        if !invariant_exprs.is_empty() {
1,694✔
868
            let tests = invariant_exprs.iter().map(|expr| {
3✔
869
                quote! {
3✔
870
                    if !#expr(value) {
871
                        return false;
872
                    }
873
                }
874
            });
3✔
875

876
            let bgp_display = ps.container.bgp.display_without_bounds();
3✔
877
            quote! {
3✔
878
                unsafe fn invariants<'mem>(value: #facet_crate::PtrConst<'mem>) -> bool {
879
                    let value = value.get::<#struct_name_ident #bgp_display>();
880
                    #(#tests)*
881
                    true
882
                }
883

884
                {
885
                    vtable.invariants = Some(invariants);
886
                }
887
            }
888
        } else {
889
            quote! {}
1,691✔
890
        }
891
    };
892

893
    // Transparent logic using PStruct
894
    let inner_field = if ps.container.attrs.has_builtin("transparent") {
1,694✔
895
        match &ps.kind {
36✔
896
            PStructKind::TupleStruct { fields } => {
36✔
897
                if fields.len() > 1 {
36✔
898
                    return quote! {
×
899
                        compile_error!("Transparent structs must be tuple structs with zero or one field");
900
                    };
901
                }
36✔
902
                fields.first().cloned() // Use first field if it exists, None otherwise (ZST case)
36✔
903
            }
904
            _ => {
905
                return quote! {
×
906
                    compile_error!("Transparent structs must be tuple structs");
907
                };
908
            }
909
        }
910
    } else {
911
        None
1,658✔
912
    };
913

914
    // Add try_from_inner implementation for transparent types
915
    let try_from_inner_code = if ps.container.attrs.has_builtin("transparent") {
1,694✔
916
        if let Some(inner_field) = &inner_field {
36✔
917
            if !inner_field.attrs.has_builtin("opaque") {
36✔
918
                // Transparent struct with one field
919
                let inner_field_type = &inner_field.ty;
34✔
920
                let bgp_without_bounds = ps.container.bgp.display_without_bounds();
34✔
921

922
                quote! {
34✔
923
                    // Define the try_from function for the value vtable
924
                    unsafe fn try_from<'src, 'dst>(
925
                        src_ptr: #facet_crate::PtrConst<'src>,
926
                        src_shape: &'static #facet_crate::Shape,
927
                        dst: #facet_crate::PtrUninit<'dst>
928
                    ) -> Result<#facet_crate::PtrMut<'dst>, #facet_crate::TryFromError> {
929
                        // Try the inner type's try_from function if it exists
930
                        let inner_result = match <#inner_field_type as #facet_crate::Facet>::SHAPE.vtable.try_from {
931
                            Some(inner_try) => unsafe { (inner_try)(src_ptr, src_shape, dst) },
932
                            None => Err(#facet_crate::TryFromError::UnsupportedSourceShape {
933
                                src_shape,
934
                                expected: const { &[ &<#inner_field_type as #facet_crate::Facet>::SHAPE ] },
935
                            })
936
                        };
937

938
                        match inner_result {
939
                            Ok(result) => Ok(result),
940
                            Err(_) => {
941
                                // If inner_try failed, check if source shape is exactly the inner shape
942
                                if src_shape != <#inner_field_type as #facet_crate::Facet>::SHAPE {
943
                                    return Err(#facet_crate::TryFromError::UnsupportedSourceShape {
944
                                        src_shape,
945
                                        expected: const { &[ &<#inner_field_type as #facet_crate::Facet>::SHAPE ] },
946
                                    });
947
                                }
948
                                // Read the inner value and construct the wrapper.
949
                                let inner: #inner_field_type = unsafe { src_ptr.read() };
950
                                Ok(unsafe { dst.put(inner) }) // Construct wrapper
951
                            }
952
                        }
953
                    }
954

955
                    // Define the try_into_inner function for the value vtable
956
                    unsafe fn try_into_inner<'src, 'dst>(
957
                        src_ptr: #facet_crate::PtrMut<'src>,
958
                        dst: #facet_crate::PtrUninit<'dst>
959
                    ) -> Result<#facet_crate::PtrMut<'dst>, #facet_crate::TryIntoInnerError> {
960
                        let wrapper = unsafe { src_ptr.get::<#struct_name_ident #bgp_without_bounds>() };
961
                        Ok(unsafe { dst.put(wrapper.0.clone()) }) // Assume tuple struct field 0
962
                    }
963

964
                    // Define the try_borrow_inner function for the value vtable
965
                    unsafe fn try_borrow_inner<'src>(
966
                        src_ptr: #facet_crate::PtrConst<'src>
967
                    ) -> Result<#facet_crate::PtrConst<'src>, #facet_crate::TryBorrowInnerError> {
968
                        let wrapper = unsafe { src_ptr.get::<#struct_name_ident #bgp_without_bounds>() };
969
                        // Return a pointer to the inner field (field 0 for tuple struct)
970
                        Ok(#facet_crate::PtrConst::new(::core::ptr::NonNull::from(&wrapper.0)))
971
                    }
972

973
                    {
974
                        vtable.try_from = Some(try_from);
975
                        vtable.try_into_inner = Some(try_into_inner);
976
                        vtable.try_borrow_inner = Some(try_borrow_inner);
977
                    }
978
                }
979
            } else {
980
                quote! {} // No try_from can be done for opaque
2✔
981
            }
982
        } else {
983
            // Transparent ZST struct (like struct Unit;)
984
            quote! {
×
985
                // Define the try_from function for the value vtable (ZST case)
986
                unsafe fn try_from<'src, 'dst>(
987
                    src_ptr: #facet_crate::PtrConst<'src>,
988
                    src_shape: &'static #facet_crate::Shape,
989
                    dst: #facet_crate::PtrUninit<'dst>
990
                ) -> Result<#facet_crate::PtrMut<'dst>, #facet_crate::TryFromError> {
991
                    if src_shape.layout.size() == 0 {
992
                         Ok(unsafe { dst.put(#struct_name_ident) }) // Construct ZST
993
                    } else {
994
                        Err(#facet_crate::TryFromError::UnsupportedSourceShape {
995
                            src_shape,
996
                            expected: const { &[ <() as #facet_crate::Facet>::SHAPE ] }, // Expect unit-like shape
997
                        })
998
                    }
999
                }
1000

1001
                {
1002
                    vtable.try_from = Some(try_from);
1003
                }
1004

1005
                // ZSTs cannot be meaningfully borrowed or converted *into* an inner value
1006
                // try_into_inner and try_borrow_inner remain None
1007
            }
1008
        }
1009
    } else {
1010
        quote! {} // Not transparent
1,658✔
1011
    };
1012

1013
    // Generate the inner shape field value for transparent types
1014
    let inner_field_val = if ps.container.attrs.has_builtin("transparent") {
1,694✔
1015
        let inner_shape_val = if let Some(inner_field) = &inner_field {
36✔
1016
            let ty = &inner_field.ty;
36✔
1017
            if inner_field.attrs.has_builtin("opaque") {
36✔
1018
                quote! { <#facet_crate::Opaque<#ty> as #facet_crate::Facet>::SHAPE }
2✔
1019
            } else {
1020
                quote! { <#ty as #facet_crate::Facet>::SHAPE }
34✔
1021
            }
1022
        } else {
1023
            // Transparent ZST case
1024
            quote! { <() as #facet_crate::Facet>::SHAPE }
×
1025
        };
1026
        quote! { Some(#inner_shape_val) }
36✔
1027
    } else {
1028
        quote! { None }
1,658✔
1029
    };
1030

1031
    // Generics from PStruct
1032
    let facet_bgp = ps
1,694✔
1033
        .container
1,694✔
1034
        .bgp
1,694✔
1035
        .with_lifetime(LifetimeName(format_ident!("__facet")));
1,694✔
1036
    let bgp_def = facet_bgp.display_with_bounds();
1,694✔
1037
    let bgp_without_bounds = ps.container.bgp.display_without_bounds();
1,694✔
1038

1039
    let (ty_field, fields) = if opaque {
1,694✔
1040
        (
2✔
1041
            quote! {
2✔
1042
                #facet_crate::Type::User(#facet_crate::UserType::Opaque)
2✔
1043
            },
2✔
1044
            quote! {},
2✔
1045
        )
2✔
1046
    } else {
1047
        // Optimize: use &[] for empty fields to avoid const block overhead
1048
        if fields_vec.is_empty() {
1,692✔
1049
            (
19✔
1050
                quote! {
19✔
1051
                    𝟋Ty::User(𝟋UTy::Struct(
19✔
1052
                        𝟋STyB::new(#kind, &[]).repr(#repr).build()
19✔
1053
                    ))
19✔
1054
                },
19✔
1055
                quote! {},
19✔
1056
            )
19✔
1057
        } else {
1058
            // Inline the const block directly into the builder call
1059
            (
1060
                quote! {
1,673✔
1061
                    𝟋Ty::User(𝟋UTy::Struct(
1062
                        𝟋STyB::new(#kind, &const {[#(#fields_vec),*]}).repr(#repr).build()
1063
                    ))
1064
                },
1065
                quote! {},
1,673✔
1066
            )
1067
        }
1068
    };
1069

1070
    // Generate code to suppress dead_code warnings on structs constructed via reflection.
1071
    // When structs are constructed via reflection (e.g., facet_args::from_std_args()),
1072
    // the compiler doesn't see them being used and warns about dead code.
1073
    // This function ensures the struct type is "used" from the compiler's perspective.
1074
    // See: https://github.com/facet-rs/facet/issues/996
1075
    let dead_code_suppression = quote! {
1,694✔
1076
        const _: () = {
1077
            #[allow(dead_code, clippy::multiple_bound_locations)]
1078
            fn __facet_use_struct #bgp_def (__v: &#struct_name_ident #bgp_without_bounds) #where_clauses {
1079
                let _ = __v;
1080
            }
1081
        };
1082
    };
1083

1084
    // Generate static assertions for declared traits (catches lies at compile time)
1085
    // We put this in a generic function outside the const block so it can reference generic parameters
1086
    let facet_default = ps.container.attrs.has_builtin("default");
1,694✔
1087
    let trait_assertion_fn = if let Some(bounds) =
1,694✔
1088
        gen_trait_bounds(ps.container.attrs.declared_traits.as_ref(), facet_default)
1,694✔
1089
    {
1090
        // Note: where_clauses already includes "where" keyword if non-empty
1091
        // We need to add the trait bounds as an additional constraint
1092
        quote! {
5✔
1093
            const _: () = {
1094
                #[allow(dead_code, clippy::multiple_bound_locations)]
1095
                fn __facet_assert_traits #bgp_def (_: &#struct_name_ident #bgp_without_bounds)
1096
                where
1097
                    #struct_name_ident #bgp_without_bounds: #bounds
1098
                {}
1099
            };
1100
        }
1101
    } else {
1102
        quote! {}
1,689✔
1103
    };
1104

1105
    // Final quote block using refactored parts
1106
    let result = quote! {
1,694✔
1107
        #static_decl
1108

1109
        #dead_code_suppression
1110

1111
        #trait_assertion_fn
1112

1113
        #[automatically_derived]
1114
        unsafe impl #bgp_def #facet_crate::Facet<'__facet> for #struct_name_ident #bgp_without_bounds #where_clauses {
1115
            const SHAPE: &'static #facet_crate::Shape = &const {
1116
                use #facet_crate::𝟋::*;
1117
                #fields
1118

1119
                𝟋Shp {
1120
                    id: 𝟋Shp::id_of::<Self>(),
1121
                    layout: 𝟋Shp::layout_of::<Self>(),
1122
                    vtable: {
1123
                        let mut vtable = #vtable_init;
1124
                        #invariant_maybe
1125
                        #try_from_inner_code // Use the generated code for transparent types
1126
                        vtable
1127
                    },
1128
                    ty: #ty_field,
1129
                    def: 𝟋Def::Undefined,
1130
                    type_identifier: #struct_name_str,
1131
                    type_params: #type_params,
1132
                    doc: #doc_field,
1133
                    attributes: #attributes_field,
1134
                    type_tag: #type_tag_field,
1135
                    inner: #inner_field_val,
1136
                }
1137
            };
1138
        }
1139
    };
1140

1141
    result
1,694✔
1142
}
1,694✔
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