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}