devela/num/logic/bool.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
// devela::code::bool::bool
//
//! Type-level booleans.
//
// TOC
// - trait ConstBool
// - macro const_bool!
// - types True, False
use crate::sf;
/// Allows to convert compile-time constants into type-level booleans.
///
/// See also the [`const_bool`] macro, and the [`True`] and [`False`] types.
#[rustfmt::skip]
#[diagnostic::on_unimplemented(
message = "Only expressions that evaluate to a constant 0 or 1 are valid for `ConstBool`.",
label = "This expression does not evaluate to a constant 0 or 1 (as usize)."
)]
pub trait ConstBool {
/// The resulting type-level boolean (`True` or `False`).
type Value: Sized;
/// The constant value of the type-level boolean.
const VALUE: Self::Value;
}
sf! {
impl ConstBool for [(); 0] { type Value = False; const VALUE: False = False; }
impl ConstBool for [(); 1] { type Value = True; const VALUE: True = True; }
impl ConstBool for False { type Value = False; const VALUE: False = False; }
impl ConstBool for True { type Value = True; const VALUE: True = True; }
}
/// Converts a *const* `bool` expression to a type-level boolean.
///
/// Internally, it leverages the [`ConstBool`] trait and a trick related to array sizes:
/// - Arrays of size `[(); 0]` are mapped to [`False`].
/// - Arrays of size `[(); 1]` are mapped to [`True`].
///
/// # Examples
/// ```
/// # use devela::{const_bool, True};
/// const _: True = const_bool![4 == 4];
/// ```
/// ```compile_fail
/// # use devela::{const_bool, True};
/// const _: True = const_bool![3 == 4];
/// ```
#[macro_export]
#[cfg_attr(cargo_primary_package, doc(hidden))]
macro_rules! const_bool {
($bool:expr) => {{
<[(); { $bool as usize }] as $crate::ConstBool>::VALUE
}};
}
#[doc(inline)]
pub use const_bool;
/// A type-level logical true.
///
/// See also the [`ConstBool`] trait, the [`const_bool`] macro, and the [`False`] type.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct True;
/// A type-level logical false.
///
/// See also the [`ConstBool`] trait, the [`const_bool`] macro, and the [`True`] type.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct False;
#[rustfmt::skip]
impl True {
/// Applies the `not` operation, (returns `False`).
pub const fn not(self) -> False { False }
/// Applies the `not` operation, (returns `False`).
pub const fn not_ref(&self) -> &'static False { &False }
/// Applies the `and` operation to `other`, (returns `other`).
pub const fn and<T>(self, other: T) -> T { other }
/// Applies the `and` operation to `other`, (returns `other`).
pub const fn and_ref<'a, T>(&self, other: &'a T) -> &'a T { other }
/// Applies the `or` operation to `_other`, (returns `True`).
pub fn or<T>(self, _other: T) -> True { True }
/// Applies the `or` operation to `_other`, (returns `True`).
pub const fn or_ref<T>(&self, _other: &T) -> &'static True { &True }
/// Returns the value as `bool` (returns `true`).
pub const fn value(self) -> bool { true }
/// Returns the value as `bool` (returns `true`).
pub const fn value_ref(&self) -> bool { true }
}
#[rustfmt::skip]
impl False {
/// Applies the `not` operation, (returns `True`).
pub const fn not(self) -> True { True }
/// Applies the `not` operation, (returns `True`).
pub const fn not_ref(&self) -> &'static True { &True }
/// Applies the `and` operation to `_other`, (returns `False`).
pub fn and<T>(self, _other: T) -> False { False }
/// Applies the `and` operation to `_other`, (returns `False`).
pub const fn and_ref<T>(&self, _other: &T) -> &'static False { &False }
/// Applies the `or` operation to `other`, (returns `other`).
pub fn or<T>(self, other: T) -> T { other }
/// Applies the `or` operation to `other`, (returns `other`).
pub const fn or_ref<'a, T>(&self, other: &'a T) -> &'a T { other }
/// Returns the value as `bool` (returns `false`).
pub const fn value(self) -> bool { false }
/// Returns the value as `bool` (returns `false`).
pub const fn value_ref(&self) -> bool { false }
}