This crate provides abstractions for creating type witnesses.
The inciting motivation for this crate is emulating trait polymorphism in const fn
(as of 2023-10-01, it's not possible to call trait methods in const contexts on stable).
What are type witnesses
Type witnesses are enums that allow coercing between a type parameter and a range of possible types (one per variant).
The simplest type witness is TypeEq<L, R>
,
which only allows coercing between L
and R
.
Most type witnesses are enums with TypeEq
fields,
which can coerce between a type parameter and as many types as there are variants.
Examples
Polymorphic function
This demonstrates how one can write a return-type-polymorphic const fn
(as of 2023-10-01, trait methods can't be called in const fns on stable)
use ;
assert_eq!;
assert_eq!;
const
// This macro declares a type witness enum
simple_type_witness!
Indexing polymorphism
This function demonstrates const fn polymorphism
and projecting TypeEq
by implementing TypeFn
.
(this example requires Rust 1.71.0, because it uses <[T]>::split_at
in a const context.
use Range;
use ;
const
// This macro declares a type witness enum
simple_type_witness!
/// Trait for all types that can be used as slice indices
///
/// The `HasTypeWitness` supertrait allows getting a `IndexWitness<Self>`
/// with its `WITNESS` associated constant.
type SliceIndexRet<I, T> = Returns;
// Declares `struct FnSliceIndexRet<T>`
// a type-level function (TypeFn implementor) from `I` to `SliceIndexRet<I, T>`
type_fn!
When the wrong type is passed for the index, the compile-time error is the same as with normal generic functions:
error[E0277]: the trait bound `RangeFull: SliceIndex<{integer}>` is not satisfied
--> src/main.rs:43:30
|
13 | assert_eq!(index(&array, ..), [13, 21]);
| ----- ^^ the trait `SliceIndex<{integer}>` is not implemented for `RangeFull`
| |
| required by a bound introduced by this call
|
= help: the following other types implement trait `SliceIndex<T>`:
std::ops::Range<usize>
usize
Downcasting const generic type
This example demonstrates "downcasting" from a type with a const parameter to a concrete instance of that type.
use ;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!; // this is different!
assert_eq!;
;
// Declares `struct GArr`
// a type-level function (TypeFn implementor) from `Usize<N>` to `Arr<N>`
type_fn!
Builder
Using a type witness to help encode a type-level enum, and to match on that type-level enum inside of a function.
The type-level enum is used to track the initialization of fields in a builder.
This example requires Rust 1.65.0, because it uses Generic Associated Types.
use HasTypeWitness;
// Emulates a type-level `enum InitState { Init, Uninit }`
// If `I` is `Uninit`, then this evaluates to `()`
// If `I` is `Init`, then this evaluates to `T`
type BuilderField<I, T> = ;
/// Gets `T` out of `maybe_init` if it's actually initialized,
/// otherwise returns `else_()`.
Cargo features
These are the features of this crate.
Default-features
These features are enabled by default:
"proc_macros"
: uses proc macros to improve compile-errors involving macro-generated impls.
Rust-versions and standard crates
These features enable items that have a minimum Rust version:
-
"rust_stable"
: enables all the"rust_1_*"
features. -
"rust_1_65"
: enables thetype_constructors
module, themethods
module, and the"rust_1_61"
feature. -
"rust_1_61"
: enablesMetaBaseTypeWit
,BaseTypeWitness
, and the{TypeCmp, TypeNe}::{zip*, in_array}
methods.
These features enable items that require a non-core
standard crate:
"alloc"
: enable items that use anything from the standardalloc
crate.
Nightly features
These features require the nightly Rust compiler:
-
"adt_const_marker"
: enables the"rust_stable"
crate feature, and marker types in theconst_marker
module that have non-primitiveconst
parameters. -
"nightly_mut_refs"
: Enables the"rust_stable"
and"mut_refs"
crate features, and turns functions that use mutable references intoconst fn
s.
Future-Rust features
These features currently require future compiler versions:
"mut_refs"
: turns functions that take mutable references intoconst fn
s. note: as of October 2023, this crate feature requires a stable compiler from the future.
No-std support
typewit
is #![no_std]
, it can be used anywhere Rust can be used.
You need to enable the "alloc"
feature to enable items that use anything
from the standard alloc
crate.
Minimum Supported Rust Version
typewit
supports Rust 1.57.0.
Features that require newer versions of Rust, or the nightly compiler, need to be explicitly enabled with crate features.