use core::{ mem, ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not}, }; /// Not-yet evaluated boolean value. #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub enum LazyBool { /// Like `false`. /// /// This is this type’s default. #[default] False, /// Like `true`. True, /// Not-yet decided. Lazy(T), } impl From for LazyBool { fn from(value: bool) -> Self { match value { false => Self::False, true => Self::True, } } } /// Helper to implement various binary operations on [`LazyBool`]. macro_rules! impl_op { ( < $trait:ident::$method:ident, $assign_trait:ident::$assign_method:ident >($matching:pat_param) { $($pattern:pat => $body:expr),+ $(,)? } $(where $($bound:tt)+)? ) => { impl $trait> for LazyBool where L: $trait, LazyBool: Into>, LazyBool: Into>, $($($bound)+)? { type Output = LazyBool; fn $method(self, rhs: LazyBool) -> Self::Output { match (self, rhs) { (LazyBool::Lazy(lhs), LazyBool::Lazy(rhs)) => LazyBool::Lazy(lhs.$method(rhs)), ($matching, rhs) => rhs.into(), (lhs, $matching) => lhs.into(), $($pattern => $body),+ } } } impl<'a, L, R, T> $trait<&'a LazyBool> for LazyBool where L: $trait<&'a R, Output = T>, LazyBool: Into>, LazyBool: Into> + Clone, $($($bound)+)? { type Output = LazyBool; fn $method(self, rhs: &'a LazyBool) -> Self::Output { match (self, rhs) { (LazyBool::Lazy(lhs), LazyBool::Lazy(rhs)) => LazyBool::Lazy(lhs.$method(rhs)), ($matching, rhs) => rhs.clone().into(), (lhs, $matching) => lhs.into(), $($pattern => $body),+ } } } impl<'a, L, R, T> $trait> for &'a LazyBool where LazyBool: $trait<&'a LazyBool, Output = LazyBool>, { type Output = LazyBool; fn $method(self, rhs: LazyBool) -> Self::Output { rhs.$method(self) } } impl $assign_trait> for LazyBool where LazyBool: $trait, Output = LazyBool>, { fn $assign_method(&mut self, rhs: LazyBool) { let lhs = mem::take(self); *self = lhs.$method(rhs); } } }; } impl_op! { (LazyBool::True){ _ => LazyBool::False } } impl_op! { (LazyBool::False) { _ => LazyBool::True } } impl_op! { (LazyBool::False) { (LazyBool::True, rhs) => (!rhs).into(), (lhs, LazyBool::True) => (!lhs).into(), } where LazyBool: Not>, LazyBool: Not>, } impl Not for LazyBool where T: Not, { type Output = Self; fn not(self) -> Self::Output { match self { Self::False => Self::True, Self::True => Self::False, Self::Lazy(this) => Self::Lazy(!this), } } } impl Not for &LazyBool where LazyBool: Not> + Clone, { type Output = LazyBool; fn not(self) -> Self::Output { !self.clone() } }