closed_trait/lib.rs
1#![doc = include_str!("../README.md")]
2#![no_std]
3
4pub use closed_trait_macros::{enumerate, if_implements_fn, sealed};
5
6/// A type that can be turned into the enum of its sealed trait.
7///
8/// [`enumerate`] implements this for every permitted type, and makes `Enumerable<TheSealedTrait>` a
9/// supertrait of the sealed trait. Naming the enum in the bound is what lets a caller reach it
10/// through the trait alone:
11///
12/// ```
13/// # use closed_trait::{enumerate, sealed};
14///
15/// struct Square;
16///
17/// #[enumerate]
18/// #[sealed(Square)]
19/// trait Shape {}
20///
21/// impl Shape for Square {}
22///
23/// // No import: the supertrait bound carries `into_enum` in with `S: Shape`.
24/// fn describe<S: Shape>(s: S) {
25/// match s.into_enum() {
26/// AnyShape::Square(s) => { /* .. */ }
27/// }
28/// }
29/// # fn main() { describe(Square); }
30/// ```
31///
32/// Note that `Enumerable` did not have to be imported above: the supertrait bound brings
33/// `into_enum` into scope through `S: TheSealedTrait`. Calling it on a concrete type rather than a
34/// generic one does need the import.
35///
36/// `From` is implemented alongside it in the other direction, so `From::from` and `Into::into` work
37/// too.
38pub trait Enumerable<Enum> {
39 /// Wraps `self` in the variant of `Enum` that holds this type.
40 fn into_enum(self) -> Enum;
41}
42
43/// A type that can lend itself to the *borrowing* enum of its sealed trait.
44///
45/// [`enumerate`] implements this for every permitted type and makes
46/// `for<'a> EnumerableRef<'a, TheSealedTraitRef<'a>>` a supertrait. The lifetime is a parameter of
47/// the trait rather than of the method, so the higher-ranked bound is nameable in the supertrait
48/// list, which is what lets a caller reach the enum from a plain `&S`:
49///
50/// ```
51/// # use closed_trait::{enumerate, sealed};
52/// # use closed_trait::EnumerableRef;
53///
54/// struct Square;
55///
56/// #[enumerate]
57/// #[sealed(Square)]
58/// trait Shape {}
59///
60/// impl Shape for Square {}
61///
62/// # fn main() {
63/// let s = □
64/// match s.as_enum_ref() {
65/// AnyShapeRef::Square(s) => { /* .. */ }
66/// }
67/// # }
68/// ```
69///
70/// [`Enumerable`] cannot do this: `into_enum` takes `self`, so reaching the owned enum means owning
71/// the value. The borrowing enum is also the cheaper one to pass, being a pointer and a discriminant
72/// rather than as large as the biggest permitted type.
73pub trait EnumerableRef<'a, EnumRef> {
74 /// Wraps `&self` in the variant of `EnumRef` that holds this type.
75 fn as_enum_ref(&'a self) -> EnumRef;
76}
77
78/// A type that can lend itself *mutably* to the borrowing enum of its sealed trait.
79///
80/// The counterpart of [`EnumerableRef`], reached from a `&mut S` the same way:
81///
82/// ```
83/// # use closed_trait::{enumerate, sealed};
84/// # use closed_trait::EnumerableMut;
85///
86/// struct Square;
87///
88/// #[enumerate]
89/// #[sealed(Square)]
90/// trait Shape {}
91///
92/// impl Shape for Square {}
93///
94/// # fn main() {
95/// let mut s = &mut Square;
96/// match s.as_enum_mut() {
97/// AnyShapeMut::Square(s) => { /* .. */ }
98/// }
99/// # }
100/// ```
101///
102/// Unlike the shared enum this one is neither `Clone` nor `Copy`, a unique reference being neither.
103pub trait EnumerableMut<'a, EnumMut> {
104 /// Wraps `&mut self` in the variant of `EnumMut` that holds this type.
105 fn as_enum_mut(&'a mut self) -> EnumMut;
106}