pub trait HasTypeWitness<W: TypeWitnessTypeArg<Arg = Self>> {
const WITNESS: W;
}
Expand description
Gets a type witness for Self
.
A type witness is an enum whose variants only have TypeEq
fields.
Each variant requires the enum’s type parameter to be a specific type.
This trait is a helper to write W: MakeTypeWitness<Arg = T>
with the T
and W
type parameters flipped,
most useful in supertrait bounds.
This trait can’t be implemented outside of typewit
.
§Example
This example shows how one can make a const fn
that converts both
&str
and &[u8]
to &str
(this example requires Rust 1.64.0)
ⓘ
use typewit::{HasTypeWitness, TypeWitnessTypeArg, MakeTypeWitness, TypeEq};
fn main() {
assert_eq!(str_try_from("hello"), Ok("hello"));
assert_eq!(str_try_from(&[b'w', b'o', b'r', b'l', b'd']), Ok("world"));
assert_eq!(str_try_from(b"foo bar" as &[_]), Ok("foo bar"));
}
pub const fn str_try_from<'a, T, const L: usize>(
input: T
) -> Result<&'a str, std::str::Utf8Error>
where
T: StrTryFrom<'a, L>
{
// `T::WITNESS` expands to
// `<T as HasTypeWitness<StrTryFromWitness<'a, L, T>>::WITNESS`
match T::WITNESS {
StrTryFromWitness::Str(te) => {
// `te` (a `TypeEq<T, &'a str>`) allows coercing between `T` and `&'a str`.
let string: &str = te.to_right(input);
Ok(string)
}
StrTryFromWitness::Bytes(te) => {
let bytes: &[u8] = te.to_right(input);
std::str::from_utf8(bytes)
}
StrTryFromWitness::Array(te) => {
let slice: &[u8] = te.to_right(input);
str_try_from(slice)
}
}
}
// trait alias pattern
pub trait StrTryFrom<'a, const L: usize>:
Copy + HasTypeWitness<StrTryFromWitness<'a, L, Self>>
{}
impl<'a, T, const L: usize> StrTryFrom<'a, L> for T
where
T: Copy + HasTypeWitness<StrTryFromWitness<'a, L, T>>
{}
// This macro declares a type witness enum
typewit::simple_type_witness! {
// Declares `enum StrTryFromWitness<'a, const L: usize, __Wit>`
// (the `__Wit` type parameter is implicitly added after all generics)
// `#[non_exhausitve]` allows adding more supported types.
#[non_exhaustive]
pub enum StrTryFromWitness<'a, const L: usize> {
// This variant requires `__Wit == &'a str`
//
// The `<'a, 0>` here changes this macro from generating
// `impl<'a, const L: usize> MakeTypeWitness for StrTryFromWitness<'a, L, &'a [u8]>`
// to
// `impl<'a> MakeTypeWitness for StrTryFromWitness<'a, 0, &'a [u8]>`
// which allows the compiler to infer generic arguments when
// using the latter `MakeTypeWitness` impl`
Str<'a, 0> = &'a str,
// This variant requires `__Wit == &'a [u8]`
Bytes<'a, 0> = &'a [u8],
// This variant requires `__Wit == &'a [u8; L]`
Array = &'a [u8; L],
}
}
Required Associated Constants§
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.