Trait konst_kernel::type_eq::MakeTypeWitness
source · pub trait MakeTypeWitness: TypeWitnessTypeArg {
const MAKE: Self;
}
Expand description
Constructs this type witness.
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 can be automatically implemented for simple type witnesses
by declaring the type witness with the simple_type_witness
macro.
Example
(this example requires Rust 1.61.0)
use typewit::{TypeWitnessTypeArg, MakeTypeWitness, TypeEq};
const fn default<'a, T, const L: usize>() -> T
where
Defaultable<'a, L, T>: MakeTypeWitness
{
match MakeTypeWitness::MAKE {
// `te` is a `TypeEq<T, i32>`, which allows coercing between `T` and `i32`.
// `te.to_left(...)` goes from `i32` to `T`.
Defaultable::I32(te) => te.to_left(3),
// `te` is a `TypeEq<T, bool>`
Defaultable::Bool(te) => te.to_left(true),
// `te` is a `TypeEq<T, &'a str>`
Defaultable::Str(te) => te.to_left("empty"),
// `te` is a `TypeEq<T, [u32; L]>`
Defaultable::Array(te) => te.to_left([5; L]),
}
}
let number: i32 = default();
assert_eq!(number, 3);
let boolean: bool = default();
assert_eq!(boolean, true);
let string: &str = default();
assert_eq!(string, "empty");
let array: [u32; 3] = default();
assert_eq!(array, [5, 5, 5]);
// This enum is a type witness (documented in the root module)
#[non_exhaustive]
enum Defaultable<'a, const L: usize, T> {
// This variant requires `T == i32`
I32(TypeEq<T, i32>),
// This variant requires `T == bool`
Bool(TypeEq<T, bool>),
// This variant requires `T == &'a str`
Str(TypeEq<T, &'a str>),
// This variant requires `T == [u32; L]`
Array(TypeEq<T, [u32; L]>),
}
impl<T, const L: usize> TypeWitnessTypeArg for Defaultable<'_, L, T> {
// this aids type inference for what type parameter is witnessed
type Arg = T;
}
// Specifying dummy values for the generics that the `I32` variant doesn't use,
// so that they don't have to be specified when this impl is used.
impl MakeTypeWitness for Defaultable<'_, 0, i32> {
// The `TypeEq<T, i32>` field can be constructed because `T == i32` here.
const MAKE: Self = Self::I32(TypeEq::NEW);
}
impl MakeTypeWitness for Defaultable<'_, 0, bool> {
const MAKE: Self = Self::Bool(TypeEq::NEW);
}
impl<'a> MakeTypeWitness for Defaultable<'a, 0, &'a str> {
const MAKE: Self = Self::Str(TypeEq::NEW);
}
impl<const L: usize> MakeTypeWitness for Defaultable<'_, L, [u32; L]> {
const MAKE: Self = Self::Array(TypeEq::NEW);
}
The Defaultable
type definition and its impls can also be written using
the simple_type_witness
macro:
typewit::simple_type_witness!{
// Declares `enum Defaultable<'a, const L: usize, __Wit>`
// The `__Wit` type parameter is implicit and always the last generic parameter.
#[non_exhaustive]
enum Defaultable['a, const L: usize] {
// `['a, 0]` is necessary to have
// `impl MakeTypeWitness for Defaultable<'_, 0, i32>` instead of
// `impl<'a, const L: u32> MakeTypeWitness for Defaultable<'a, L, i32>`
I32['a, 0] = i32,
Bool['a, 0] = bool,
Str['a, 0] = &'a str,
Array = [u32; L],
}
}
note that simple_type_witness
can’t replace enums whose
witnessed type parameter is not the last,
or have variants with anything but one TypeEq
field each.