Crate const_guards
source · [−]Expand description
const_guards
is a simple attribute macro that makes it easy to express certain
compile time constraints on const_generics
using generic_const_exprs
.
Example
#![feature(generic_const_exprs)]
use const_guards::guard;
#[guard(N > 0)]
fn f<const N: usize>() { todo!() }
f::<0>()
f::<1>()
Guards
Guards can have either a expression or a polymorphic block as argument.
Expression Guard
The expression guard can only use const generics and normal generics introduced
by the item and is limited to one rust expression allowed in const fn
.
#[guard(PREFIX == '_' || PREFIX == '#')]
struct Label<const PREFIX: char> (&'static str);
let label = Label::<'!'>("important");
let label = Label::<'_'>("unused");
Polymorphic Block Guard
The polymorphic block is denoted <const A: Type, const B: Type, .., T, V, ..> { .. }
and can introduce const generics and normal generics from the outer scope
to the block in curly brackets. The generics are optional and an polymorphic block
without the need of outer generics can be denoted as { .. }
Inside the block the same kind of logic that can be used inside const fn
is allowed.
trait ArrayHead<T, const N: usize> {
#[guard(<const N: usize> { N > 0 })]
fn head(&self) -> &T;
}
impl<T, const N: usize> ArrayHead<T, N> for [T; N] {
fn head(&self) -> &T {
&self[0]
}
}
let array = &[(); 0];
let head: &() = array.head();
let array = &[(); 1];
let head: &() = array.head();
Items
Guards are allowed to be an attribute of the following rust items:
fn
enum
struct
impl
Advanced
Custom Error Messages
Raise an custom error by panic!
-ing inside the guard.
This will be rendered as compile error with help of rust’s const_panic
.
With that in mind we could modify the trait definition from
Polymorphic Block Guard.
trait ArrayHead<T, const N: usize> {
#[guard(<const N: usize> {
if N == 0 {
panic!("expected at least one item in array")
} else {
true
}
})]
fn head(&self) -> &T;
}
Const Functions
It’s possible to outsource logic by calling other const fn
.
With that in mind we could modify the trait definition from
Polymorphic Block Guard.
const fn is_not_empty<const N: usize>() -> bool {
N > 0
}
trait ArrayHead<T, const N: usize> {
#[guard(<const N: usize> { is_not_empty::<N>() })]
fn head(&self) -> &T;
}
Marco Expansion
For an example for the expansion that takes places see [here
]
[here
]: https://docs.rs/const_guards/latest/const_guards/attr.guard.html
Structs
Traits
Attribute Macros
Macro Expansion