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

facet-rs / facet / 20024290994

08 Dec 2025 10:08AM UTC coverage: 58.613% (+0.01%) from 58.6%
20024290994

push

github

fasterthanlime
feat: compute variance automatically from field types

This implements automatic variance computation for derived types:

- Change `Shape.variance` from `fn() -> Variance` to `fn(&'static Shape) -> Variance`
  to allow variance functions to walk type structure without capturing generics

- Add `Shape::computed_variance()` that walks struct fields, enum variants,
  and inner shapes (for Box, Vec, Option, etc.) to compute variance

- Use thread-local cycle detection to prevent stack overflow with recursive types.
  When a cycle is detected, returns `Covariant` (identity for `combine`)

- Update derive macros to use `.variance(Shape::computed_variance)`
  instead of generating per-type variance computation code

- Update `Box<T>` to use computed variance (depends on T's variance)
  instead of hardcoded `Invariant`

- Add variance tests for recursive types

Closes #1171

44 of 60 new or added lines in 3 files covered. (73.33%)

487 existing lines in 23 files now uncovered.

24730 of 42192 relevant lines covered (58.61%)

544.95 hits per line

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

0.0
/facet-core/src/impls_std/path.rs
1
use crate::Variance;
2
use crate::*;
3

4
unsafe impl Facet<'_> for std::path::PathBuf {
5
    const SHAPE: &'static Shape = &const {
6
        Shape {
7
            id: Shape::id_of::<Self>(),
8
            layout: Shape::layout_of::<Self>(),
9
            vtable: value_vtable!(std::path::PathBuf, |f, _opts| write!(
×
UNCOV
10
                f,
×
11
                "{}",
UNCOV
12
                Self::SHAPE.type_identifier
×
13
            )),
14
            ty: Type::User(UserType::Opaque),
15
            def: Def::Scalar,
16
            type_identifier: "PathBuf",
17
            type_params: &[],
18
            doc: &[],
19
            attributes: &[],
20
            type_tag: None,
21
            inner: None,
22
            proxy: None,
23
            // PathBuf has no lifetime parameters, so it's covariant
24
            variance: Variance::COVARIANT,
25
        }
26
    };
27
}
28

29
unsafe impl Facet<'_> for std::path::Path {
30
    const SHAPE: &'static Shape = &const {
31
        Shape {
32
            id: Shape::id_of::<Self>(),
33
            layout: Shape::UNSIZED_LAYOUT,
UNCOV
34
            vtable: value_vtable!(std::path::Path, |f, _opts| write!(
×
35
                f,
×
36
                "{}",
UNCOV
37
                Self::SHAPE.type_identifier
×
38
            )),
39
            ty: Type::User(UserType::Opaque),
40
            def: Def::Scalar,
41
            type_identifier: "Path",
42
            type_params: &[],
43
            doc: &[],
44
            attributes: &[],
45
            type_tag: None,
46
            inner: None,
47
            proxy: None,
48
            // Path has no lifetime parameters, so it's covariant
49
            variance: Variance::COVARIANT,
50
        }
51
    };
52
}
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