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 }
}