Expand description
§Optional const
Optional constness on stable Rust.
This crate should be superseded by keyword genericity in the future.
§Usage
use optionally_const::{const_type_instance, OptionallyConst};
fn print_flag<T: OptionallyConst<bool>>(flag: T) {
if let Some(flag) = T::MAYBE_CONST {
println!("flag is const: {flag}");
} else {
let flag: bool = flag.into_value();
println!("flag is not const: {flag}");
};
}
fn main() {
print_flag(true);
print_flag(false);
print_flag(const_type_instance!(true));
print_flag(const_type_instance!(false));
}§Limitations
- Rust currently doesn’t allow defining a type like
struct ConstType<T, const VAL: T>;because the type of const parameters must not depend on other generic parameters [E770]. Consequently, one can’t provide a canonical “const type” for any const value. - The
const_type_instance!macro currently supports onlybooltype. However, it can be extended to support other types in the future. - Due to lack of support for negative trait bounds and [E770], it’s impossible to implement
OptionallyConst<T>for all types that implementConst<T>. The current implementation only supportsbooltype. However, you can implement bothOptionallyConst<T>andConst<T>for your own types.
§Optional constness for user-defined types
§Enums
use optionally_const::Const;
enum MyEnum {
A,
B,
C,
}
impl std::fmt::Display for MyEnum {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MyEnum::A => write!(f, "A"),
MyEnum::B => write!(f, "B"),
MyEnum::C => write!(f, "C"),
}
}
}
struct MyEnumAConstType;
struct MyEnumBConstType;
struct MyEnumCConstType;
// Ideally, OptionallyConst<T> should be implemented for
// all types that implement Const<T>.
//
// However, impl of OptionallyConst<T> for all `T` conflicts with the
// impl of OptionallyConst<T> for all `U: Const<T>` in the absence of
// negative trait bounds.
impl Const<MyEnum> for MyEnumAConstType {
const VALUE: MyEnum = MyEnum::A;
}
impl OptionallyConst<MyEnum> for MyEnumAConstType {
const MAYBE_CONST: Option<MyEnum> = Some(MyEnum::A);
fn into_value(self) -> MyEnum {
MyEnum::A
}
}
impl Const<MyEnum> for MyEnumBConstType {
const VALUE: MyEnum = MyEnum::B;
}
impl OptionallyConst<MyEnum> for MyEnumBConstType {
const MAYBE_CONST: Option<MyEnum> = Some(MyEnum::B);
fn into_value(self) -> MyEnum {
MyEnum::B
}
}
impl Const<MyEnum> for MyEnumCConstType {
const VALUE: MyEnum = MyEnum::C;
}
impl OptionallyConst<MyEnum> for MyEnumCConstType {
const MAYBE_CONST: Option<MyEnum> = Some(MyEnum::C);
fn into_value(self) -> MyEnum {
MyEnum::C
}
}
fn print_my_enum<T: OptionallyConst<MyEnum>>(value: T) {
if let Some(value) = T::MAYBE_CONST {
println!("value is const: {value}");
} else {
let value: MyEnum = value.into_value();
println!("value is not const: {value}");
};
}
fn main() {
print_my_enum(MyEnum::A);
print_my_enum(MyEnum::B);
print_my_enum(MyEnum::C);
print_my_enum(MyEnumAConstType);
print_my_enum(MyEnumBConstType);
print_my_enum(MyEnumCConstType);
}Note: this can be done even easier with the FieldlessEnumConstType derive macro, which is exposed when the derive feature is enabled.
§Use cases
- More generic const parameters: at the moment of writing, only a handful of types can be used as generic const parameters. However, with this crate, you can accept
T: Const<U>whereUis an enum type.
§Read more about keyword genericity
Macros§
- const_
type_ instance - Returns an instance of the type that represents the constant.
Traits§
- Const
- A trait whose types-implementors represent a constant value of type
T. - Optionally
Const - A trait that can be used to represent a type that is either
type
Tor a type that represents a constant value of typeT.
Type Aliases§
- Const
Type Bool - A convenience type alias that represents a constant boolean value.
Derive Macros§
- Fieldless
Enum Const Type derive - Derives the const type for a fieldless enum as well as the implementations
of the
ConstandOptionallyConsttraits for the parameterizations of the const type that represent the enum variants.