type_const/lib.rs
1//! This crate provides simple utils for passing `const` values around through generics,
2//! in the form of types.
3//!
4//! The concept of a type const is expressed through the [`Const`](crate::Const) trait, which holds the type and
5//! the value of the constant.
6//!
7//! Passing values that are known at compile time through generics is different from passing
8//! them through arguments, for example:
9//! ```
10//! const fn array_of_const<C: type_const::Const, const N: usize>() -> [C::Type; N] {
11//! [C::VALUE; N] // no `Copy` needed!
12//! }
13//! assert_eq!(array_of_const::<type_const::DefaultOf<i32>, 3>(), [0; 3]);
14//! ```
15//!
16//! This may also be used to write `const` "functions" in traits without the nightly
17//! `const_trait` feature. Note that unlike `const fn`, these can only be evaluated at compile
18//! time.
19//! ```
20//! trait AddConst<Rhs=Self> {
21//! type Output;
22//! type Add<
23//! LhsC: type_const::Const<Type = Self>,
24//! RhsC: type_const::Const<Type = Rhs>,
25//! >: Const<Type = Self::Output>;
26//! }
27//! ```
28
29/// Describes a type const.
30pub trait Const {
31 /// The value type of the const
32 type Type;
33 /// The implementation of the value. Prefer [`value_of`] for accessing this during const
34 /// evaluation.
35 const VALUE: Self::Type;
36}
37
38/// Alias for [`Const::Type`].
39pub type TypeOf<C> = <C as Const>::Type;
40
41/// Alias for [`Const::VALUE`]. Prefer this function over accessing the const directly.
42///
43/// Using the associated constant through this function rather than directly often causes it to only be
44/// evaluated when the branch that it is used in is actually executed.
45/// This means that it may improve compile times, avoid errors for recursive consts and avoid evaluating
46/// panics.
47///
48/// For example:
49/// ```compile_fail
50/// # use type_const::*;
51/// struct Fallible;
52/// impl Const for Fallible {
53/// type Type = ();
54/// const VALUE: Self::Type = panic!();
55/// }
56/// const _: () = if false { Fallible::VALUE }; // this gives a compile error
57/// ```
58/// ```
59/// # use type_const::*;
60/// # struct Fallible;
61/// # impl Const for Fallible {
62/// # type Type = ();
63/// # const VALUE: Self::Type = panic!();
64/// # }
65/// const _: () = if false { value_of::<Fallible>() }; // this compiles
66/// ```
67pub const fn value_of<C: Const + ?Sized>() -> C::Type {
68 C::VALUE
69}
70
71/// A const version of [`Default`].
72pub trait DefaultConst: Sized {
73 /// The default value for this type. Prefer accessing this by calling [`value_of`] on [`DefaultOf<Self>`].
74 const DEFAULT: Self;
75}
76/// A [`Const`] that evaluates to [`DefaultConst::DEFAULT`].
77pub struct DefaultOf<T>(#[allow(dead_code)] fn() -> T);
78impl<T: DefaultConst> Const for DefaultOf<T> {
79 type Type = T;
80 const VALUE: Self::Type = T::DEFAULT;
81}
82
83mod impls;