typewit/type_witness_traits.rs
1#[allow(unused_imports)]
2use crate::TypeEq;
3
4use core::marker::PhantomData;
5
6
7/// Gets a [type witness](crate#what-are-type-witnesses) for `Self`.
8///
9#[doc = explain_type_witness!()]
10///
11/// This trait is a helper to write [`W: MakeTypeWitness<Arg = T>`](MakeTypeWitness)
12/// with the `T` and `W` type parameters flipped,
13/// most useful in supertrait bounds.
14///
15/// This trait can't be implemented outside of `typewit`.
16///
17/// # Example
18///
19/// This example shows how one can make a `const fn` that converts both
20/// `&str` and `&[u8]` to `&str`
21///
22/// (this example requires Rust 1.64.0)
23///
24#[cfg_attr(not(feature = "rust_stable"), doc = "```ignore")]
25#[cfg_attr(feature = "rust_stable", doc = "```rust")]
26/// use typewit::{HasTypeWitness, TypeWitnessTypeArg, MakeTypeWitness, TypeEq};
27///
28/// fn main() {
29/// assert_eq!(str_try_from("hello"), Ok("hello"));
30///
31/// assert_eq!(str_try_from(&[b'w', b'o', b'r', b'l', b'd']), Ok("world"));
32///
33/// assert_eq!(str_try_from(b"foo bar" as &[_]), Ok("foo bar"));
34/// }
35///
36/// pub const fn str_try_from<'a, T, const L: usize>(
37/// input: T
38/// ) -> Result<&'a str, std::str::Utf8Error>
39/// where
40/// T: StrTryFrom<'a, L>
41/// {
42/// // `T::WITNESS` expands to
43/// // `<T as HasTypeWitness<StrTryFromWitness<'a, L, T>>::WITNESS`
44/// match T::WITNESS {
45/// StrTryFromWitness::Str(te) => {
46/// // `te` (a `TypeEq<T, &'a str>`) allows coercing between `T` and `&'a str`.
47/// let string: &str = te.to_right(input);
48/// Ok(string)
49/// }
50/// StrTryFromWitness::Bytes(te) => {
51/// let bytes: &[u8] = te.to_right(input);
52/// std::str::from_utf8(bytes)
53/// }
54/// StrTryFromWitness::Array(te) => {
55/// let slice: &[u8] = te.to_right(input);
56/// str_try_from(slice)
57/// }
58/// }
59/// }
60///
61///
62/// // trait alias pattern
63/// pub trait StrTryFrom<'a, const L: usize>:
64/// Copy + HasTypeWitness<StrTryFromWitness<'a, L, Self>>
65/// {}
66///
67/// impl<'a, T, const L: usize> StrTryFrom<'a, L> for T
68/// where
69/// T: Copy + HasTypeWitness<StrTryFromWitness<'a, L, T>>
70/// {}
71///
72/// // This macro declares a type witness enum
73/// typewit::simple_type_witness! {
74/// // Declares `enum StrTryFromWitness<'a, const L: usize, __Wit>`
75/// // (the `__Wit` type parameter is implicitly added after all generics)
76/// // `#[non_exhausitve]` allows adding more supported types.
77/// #[non_exhaustive]
78/// pub enum StrTryFromWitness<'a, const L: usize> {
79/// // This variant requires `__Wit == &'a str`
80/// //
81/// // The `<'a, 0>` here changes this macro from generating
82/// // `impl<'a, const L: usize> MakeTypeWitness for StrTryFromWitness<'a, L, &'a [u8]>`
83/// // to
84/// // `impl<'a> MakeTypeWitness for StrTryFromWitness<'a, 0, &'a [u8]>`
85/// // which allows the compiler to infer generic arguments when
86/// // using the latter `MakeTypeWitness` impl`
87/// Str<'a, 0> = &'a str,
88///
89/// // This variant requires `__Wit == &'a [u8]`
90/// Bytes<'a, 0> = &'a [u8],
91///
92/// // This variant requires `__Wit == &'a [u8; L]`
93/// Array = &'a [u8; L],
94/// }
95/// }
96/// ```
97pub trait HasTypeWitness<W: TypeWitnessTypeArg<Arg = Self>> {
98 /// A constant of the type witness
99 const WITNESS: W;
100
101 // prevents dependencies from implementing this trait
102 #[doc(hidden)]
103 const __PRIV_KO9Y329U2U: priv_::__Priv<Self, W>;
104}
105
106impl<T, W> HasTypeWitness<W> for T
107where
108 T: ?Sized,
109 W: MakeTypeWitness<Arg = T>,
110{
111 const WITNESS: W = W::MAKE;
112
113 #[doc(hidden)]
114 const __PRIV_KO9Y329U2U: priv_::__Priv<Self, W> = priv_::__Priv(PhantomData, PhantomData);
115}
116
117mod priv_ {
118 use core::marker::PhantomData;
119
120 #[doc(hidden)]
121 pub struct __Priv<T: ?Sized, W>(
122 pub(super) PhantomData<fn() -> PhantomData<W>>,
123 pub(super) PhantomData<fn() -> PhantomData<T>>,
124 );
125}
126
127
128
129////////////////////////////////////////////////
130
131/// Gets the type argument that this [type witness](crate#what-are-type-witnesses) witnesses.
132///
133/// [**example shared with `MakeTypeWitness`**](MakeTypeWitness#example)
134///
135#[doc = explain_type_witness!()]
136///
137/// This trait should be implemented generically,
138/// as generic as the type definition of the implementor,
139/// doing so will help type inference.
140///
141pub trait TypeWitnessTypeArg {
142 /// The type parameter used for type witnesses.
143 ///
144 /// Usually, enums that implement this trait have
145 /// variants with [`TypeEq`]`<`[`Self::Arg`]`, SomeType>` fields.
146 type Arg: ?Sized;
147}
148
149/// Constructs this [type witness](crate#what-are-type-witnesses).
150///
151#[doc = explain_type_witness!()]
152///
153/// This trait can be automatically implemented for simple type witnesses
154/// by declaring the type witness with the [`simple_type_witness`] macro.
155///
156/// # Example
157///
158/// (this example requires Rust 1.61.0)
159#[cfg_attr(not(feature = "rust_1_61"), doc = "```ignore")]
160#[cfg_attr(feature = "rust_1_61", doc = "```rust")]
161/// use typewit::{TypeWitnessTypeArg, MakeTypeWitness, TypeEq};
162///
163/// const fn default<'a, T, const L: usize>() -> T
164/// where
165/// Defaultable<'a, L, T>: MakeTypeWitness
166/// {
167/// match MakeTypeWitness::MAKE {
168/// // `te` is a `TypeEq<T, i32>`, which allows coercing between `T` and `i32`.
169/// // `te.to_left(...)` goes from `i32` to `T`.
170/// Defaultable::I32(te) => te.to_left(3),
171///
172/// // `te` is a `TypeEq<T, bool>`
173/// Defaultable::Bool(te) => te.to_left(true),
174///
175/// // `te` is a `TypeEq<T, &'a str>`
176/// Defaultable::Str(te) => te.to_left("empty"),
177///
178/// // `te` is a `TypeEq<T, [u32; L]>`
179/// Defaultable::Array(te) => te.to_left([5; L]),
180/// }
181/// }
182///
183/// let number: i32 = default();
184/// assert_eq!(number, 3);
185///
186/// let boolean: bool = default();
187/// assert_eq!(boolean, true);
188///
189/// let string: &str = default();
190/// assert_eq!(string, "empty");
191///
192/// let array: [u32; 3] = default();
193/// assert_eq!(array, [5, 5, 5]);
194///
195///
196/// // This enum is a type witness (documented in the root module)
197/// #[non_exhaustive]
198/// enum Defaultable<'a, const L: usize, T> {
199/// // This variant requires `T == i32`
200/// I32(TypeEq<T, i32>),
201///
202/// // This variant requires `T == bool`
203/// Bool(TypeEq<T, bool>),
204///
205/// // This variant requires `T == &'a str`
206/// Str(TypeEq<T, &'a str>),
207///
208/// // This variant requires `T == [u32; L]`
209/// Array(TypeEq<T, [u32; L]>),
210/// }
211///
212/// impl<T, const L: usize> TypeWitnessTypeArg for Defaultable<'_, L, T> {
213/// // this aids type inference for what type parameter is witnessed
214/// type Arg = T;
215/// }
216///
217/// // Specifying dummy values for the generics that the `I32` variant doesn't use,
218/// // so that they don't have to be specified when this impl is used.
219/// impl MakeTypeWitness for Defaultable<'_, 0, i32> {
220/// // The `TypeEq<T, i32>` field can be constructed because `T == i32` here.
221/// const MAKE: Self = Self::I32(TypeEq::NEW);
222/// }
223///
224/// impl MakeTypeWitness for Defaultable<'_, 0, bool> {
225/// const MAKE: Self = Self::Bool(TypeEq::NEW);
226/// }
227///
228/// impl<'a> MakeTypeWitness for Defaultable<'a, 0, &'a str> {
229/// const MAKE: Self = Self::Str(TypeEq::NEW);
230/// }
231///
232/// impl<const L: usize> MakeTypeWitness for Defaultable<'_, L, [u32; L]> {
233/// const MAKE: Self = Self::Array(TypeEq::NEW);
234/// }
235///
236/// ```
237///
238/// The `Defaultable` type definition and its impls can also be written using
239/// the [`simple_type_witness`] macro:
240#[cfg_attr(not(feature = "rust_1_61"), doc = "```ignore")]
241#[cfg_attr(feature = "rust_1_61", doc = "```rust")]
242/// typewit::simple_type_witness!{
243/// // Declares `enum Defaultable<'a, const L: usize, __Wit>`
244/// // The `__Wit` type parameter is implicit and always the last generic parameter.
245/// #[non_exhaustive]
246/// enum Defaultable<'a, const L: usize> {
247/// // `<'a, 0>` is necessary to have
248/// // `impl MakeTypeWitness for Defaultable<'_, 0, i32>` instead of
249/// // `impl<'a, const L: u32> MakeTypeWitness for Defaultable<'a, L, i32>`,
250/// // which allows the generic arguments to be inferred.
251/// I32<'a, 0> = i32,
252///
253/// Bool<'a, 0> = bool,
254///
255/// Str<'a, 0> = &'a str,
256///
257/// Array = [u32; L],
258/// }
259/// }
260/// ```
261/// note that [`simple_type_witness`] can't replace enums whose
262/// witnessed type parameter is not the last,
263/// or have variants with anything but one [`TypeEq`] field each.
264///
265///
266/// [`simple_type_witness`]: crate::simple_type_witness
267pub trait MakeTypeWitness: TypeWitnessTypeArg {
268 /// A constant with the type witness
269 const MAKE: Self;
270}