use std::ops::{Add, Not, Sub};
#[derive(Default, Debug, PartialEq)]
pub enum Effect {
#[default]
None,
Apply,
Clear,
}
impl Effect {
pub fn is_set(&self) -> bool {
!matches!(self, Effect::None)
}
pub fn is_unset(&self) -> bool {
!self.is_set()
}
}
impl Add for Effect {
type Output = Effect;
fn add(self, rhs: Self) -> Self::Output {
match (self, rhs) {
(Effect::None, Effect::None) => Effect::None,
(Effect::None, Effect::Apply) => Effect::Apply,
(Effect::None, Effect::Clear) => Effect::None,
(Effect::Apply, Effect::None) => Effect::Apply,
(Effect::Apply, Effect::Apply) => Effect::Apply,
(Effect::Apply, Effect::Clear) => Effect::Clear,
(Effect::Clear, Effect::None) => Effect::Clear,
(Effect::Clear, Effect::Apply) => Effect::Apply,
(Effect::Clear, Effect::Clear) => Effect::Clear,
}
}
}
impl Sub for Effect {
type Output = Effect;
fn sub(self, rhs: Self) -> Self::Output {
match (self, rhs) {
(Effect::None, _) => Effect::None,
(Effect::Apply, Effect::Apply) => Effect::None,
(Effect::Clear, Effect::Clear) => Effect::None,
(Effect::Apply, _) => Effect::Apply,
(Effect::Clear, Effect::None) => Effect::None,
(Effect::Clear, _) => Effect::Clear,
}
}
}
impl Not for Effect {
type Output = Effect;
fn not(self) -> Self::Output {
match self {
Effect::None => Effect::None,
Effect::Apply => Effect::Clear,
Effect::Clear => Effect::None,
}
}
}
impl From<(bool, bool)> for Effect {
fn from(value: (bool, bool)) -> Self {
match value {
(false, false) => Effect::None,
(true, false) => Effect::Apply,
(false, true) => Effect::Clear,
_ => unreachable!("Invalid Effect"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub enum DuoEffect {
#[default]
None,
A,
B,
AB,
BA,
AE,
BE,
E,
}
impl DuoEffect {
pub fn is_set(&self) -> bool {
!matches!(self, DuoEffect::None)
}
pub fn is_unset(&self) -> bool {
!self.is_set()
}
}
impl Add for DuoEffect {
type Output = DuoEffect;
fn add(self, rhs: Self) -> Self::Output {
match (self, rhs) {
(DuoEffect::None, DuoEffect::E | DuoEffect::AE | DuoEffect::BE) => DuoEffect::None,
(DuoEffect::None, rhs) => rhs,
(lhs, DuoEffect::None) => lhs,
(DuoEffect::E, rhs) => rhs,
(DuoEffect::A | DuoEffect::BA | DuoEffect::AE, DuoEffect::E) => DuoEffect::AE,
(DuoEffect::B | DuoEffect::AB | DuoEffect::BE, DuoEffect::E) => DuoEffect::BE,
(DuoEffect::A | DuoEffect::BA, DuoEffect::A) => DuoEffect::A,
(DuoEffect::B | DuoEffect::AB, DuoEffect::B) => DuoEffect::B,
(DuoEffect::A | DuoEffect::BA, DuoEffect::B) => DuoEffect::AB,
(DuoEffect::B | DuoEffect::AB, DuoEffect::A) => DuoEffect::BA,
(DuoEffect::A | DuoEffect::BA, DuoEffect::AE) => DuoEffect::AE,
(DuoEffect::B | DuoEffect::AB, DuoEffect::BE) => DuoEffect::BE,
(DuoEffect::AE, DuoEffect::B) => DuoEffect::AB,
(DuoEffect::BE, DuoEffect::A) => DuoEffect::BA,
(lhs, DuoEffect::AE) => lhs,
(lhs, DuoEffect::BE) => lhs,
(_, rhs) => rhs,
}
}
}
impl Sub for DuoEffect {
type Output = DuoEffect;
fn sub(self, rhs: Self) -> Self::Output {
match (self, rhs) {
(DuoEffect::E, DuoEffect::None) => DuoEffect::None,
(DuoEffect::None | DuoEffect::E, _) => self,
(lhs, DuoEffect::None | DuoEffect::E) => lhs,
(DuoEffect::A, DuoEffect::A | DuoEffect::BA) => DuoEffect::None,
(DuoEffect::B, DuoEffect::A | DuoEffect::BA) => DuoEffect::AB,
(DuoEffect::A, DuoEffect::B | DuoEffect::AB) => DuoEffect::BA,
(DuoEffect::B, DuoEffect::B | DuoEffect::AB) => DuoEffect::None,
(DuoEffect::AE, DuoEffect::A | DuoEffect::BA) => DuoEffect::AE,
(DuoEffect::BE, DuoEffect::B | DuoEffect::AB) => DuoEffect::BE,
(DuoEffect::AE, _) => DuoEffect::None,
(DuoEffect::BE, _) => DuoEffect::None,
(lhs, _) => lhs,
}
}
}
impl Not for DuoEffect {
type Output = DuoEffect;
fn not(self) -> Self::Output {
match self {
DuoEffect::None => DuoEffect::None,
DuoEffect::A | DuoEffect::BA => DuoEffect::AE,
DuoEffect::B | DuoEffect::AB => DuoEffect::BE,
DuoEffect::E | DuoEffect::AE | DuoEffect::BE => DuoEffect::None,
}
}
}
impl From<(bool, bool, bool)> for DuoEffect {
fn from(value: (bool, bool, bool)) -> Self {
match value {
(false, false, false) => DuoEffect::None,
(true, false, false) => DuoEffect::A,
(false, true, false) => DuoEffect::B,
(true, true, false) => DuoEffect::AB,
(false, false, true) => DuoEffect::BA,
(false, true, true) => DuoEffect::AE,
(true, false, true) => DuoEffect::BE,
(true, true, true) => DuoEffect::E,
}
}
}