use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Sub};
#[cfg(feature = "ternary-string")]
use crate::Ternary;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum Digit {
Neg,
Zero,
Pos,
}
impl Digit {
pub const fn to_char_theta(&self) -> char {
match self {
Digit::Neg => 'Θ',
Digit::Zero => '0',
Digit::Pos => '1',
}
}
pub const fn to_char_z(&self) -> char {
match self {
Digit::Neg => 'Z',
Digit::Zero => '0',
Digit::Pos => '1',
}
}
pub const fn to_char_t(&self) -> char {
match self {
Digit::Neg => 'T',
Digit::Zero => '0',
Digit::Pos => '1',
}
}
pub const fn from_char_theta(c: char) -> Digit {
match c {
'Θ' => Digit::Neg,
'0' => Digit::Zero,
'1' => Digit::Pos,
_ => panic!("Invalid value. Expected 'Θ', '0', or '1'."),
}
}
pub const fn from_char_z(c: char) -> Digit {
match c {
'Z' => Digit::Neg,
'0' => Digit::Zero,
'1' => Digit::Pos,
_ => panic!("Invalid value. Expected 'Z', '0', or '1'."),
}
}
pub const fn from_char_t(c: char) -> Digit {
match c {
'T' => Digit::Neg,
'0' => Digit::Zero,
'1' => Digit::Pos,
_ => panic!("Invalid value. Expected 'T', '0', or '1'."),
}
}
pub const fn to_char(&self) -> char {
match self {
Digit::Neg => '-',
Digit::Zero => '0',
Digit::Pos => '+',
}
}
pub const fn from_char(c: char) -> Digit {
match c {
'-' => Digit::Neg,
'0' => Digit::Zero,
'+' => Digit::Pos,
_ => panic!("Invalid value. A Ternary must be either -, 0 or +."),
}
}
pub const fn to_i8(&self) -> i8 {
match self {
Digit::Neg => -1,
Digit::Zero => 0,
Digit::Pos => 1,
}
}
pub const fn from_i8(i: i8) -> Digit {
match i {
-1 => Digit::Neg,
0 => Digit::Zero,
1 => Digit::Pos,
_ => panic!("Invalid value. A Ternary must be either -1, 0 or +1."),
}
}
pub const fn possibly(self) -> Self {
match self {
Digit::Neg => Digit::Neg,
Digit::Zero => Digit::Pos,
Digit::Pos => Digit::Pos,
}
}
pub const fn necessary(self) -> Self {
match self {
Digit::Neg => Digit::Neg,
Digit::Zero => Digit::Neg,
Digit::Pos => Digit::Pos,
}
}
pub const fn contingently(self) -> Self {
match self {
Digit::Neg => Digit::Neg,
Digit::Zero => Digit::Pos,
Digit::Pos => Digit::Neg,
}
}
pub const fn absolute_positive(self) -> Self {
match self {
Digit::Neg => Digit::Pos,
Digit::Zero => Digit::Zero,
Digit::Pos => Digit::Pos,
}
}
pub const fn positive(self) -> Self {
match self {
Digit::Neg => Digit::Zero,
Digit::Zero => Digit::Zero,
Digit::Pos => Digit::Pos,
}
}
pub const fn not_negative(self) -> Self {
match self {
Digit::Neg => Digit::Zero,
Digit::Zero => Digit::Pos,
Digit::Pos => Digit::Pos,
}
}
pub const fn not_positive(self) -> Self {
match self {
Digit::Neg => Digit::Neg,
Digit::Zero => Digit::Neg,
Digit::Pos => Digit::Zero,
}
}
pub const fn negative(self) -> Self {
match self {
Digit::Neg => Digit::Neg,
Digit::Zero => Digit::Zero,
Digit::Pos => Digit::Zero,
}
}
pub const fn absolute_negative(self) -> Self {
match self {
Digit::Neg => Digit::Neg,
Digit::Zero => Digit::Zero,
Digit::Pos => Digit::Neg,
}
}
pub const fn k3_imply(self, other: Self) -> Self {
match self {
Digit::Neg => Digit::Pos,
Digit::Zero => other.positive(),
Digit::Pos => other,
}
}
pub const fn k3_equiv(self, other: Self) -> Self {
match self {
Digit::Neg => match other {
Digit::Neg => Digit::Pos,
Digit::Zero => Digit::Zero,
Digit::Pos => Digit::Neg,
},
Digit::Zero => Digit::Zero,
Digit::Pos => other,
}
}
pub const fn bi3_and(self, other: Self) -> Self {
match self {
Digit::Neg => other.absolute_negative(),
Digit::Zero => Digit::Zero,
Digit::Pos => other,
}
}
pub const fn bi3_or(self, other: Self) -> Self {
match self {
Digit::Neg => other,
Digit::Zero => Digit::Zero,
Digit::Pos => other.absolute_positive(),
}
}
pub const fn bi3_imply(self, other: Self) -> Self {
match self {
Digit::Neg => other.absolute_positive(),
Digit::Zero => Digit::Zero,
Digit::Pos => other,
}
}
pub const fn l3_imply(self, other: Self) -> Self {
match self {
Digit::Neg => Digit::Pos,
Digit::Zero => other.not_negative(),
Digit::Pos => other,
}
}
pub const fn rm3_imply(self, other: Self) -> Self {
match self {
Digit::Neg => Digit::Pos,
Digit::Zero => other,
Digit::Pos => other.necessary(),
}
}
pub const fn para_imply(self, other: Self) -> Self {
match self {
Digit::Neg => Digit::Pos,
_ => other,
}
}
pub const fn ht_imply(self, other: Self) -> Self {
match self {
Digit::Neg => Digit::Pos,
Digit::Zero => other.possibly(),
Digit::Pos => other,
}
}
pub const fn ht_not(self) -> Self {
match self {
Digit::Neg => Digit::Pos,
Digit::Zero => Digit::Neg,
Digit::Pos => Digit::Neg,
}
}
pub const fn ht_bool(self) -> bool {
match self {
Digit::Neg => false,
Digit::Zero => panic!(
"Cannot convert a Digit::Zero to a bool. \
Use Digit::possibly()->to_bool() or Digit::necessary()->to_bool() instead."
),
Digit::Pos => true,
}
}
pub const fn post(self) -> Self {
match self {
Digit::Neg => Digit::Zero,
Digit::Zero => Digit::Pos,
Digit::Pos => Digit::Neg,
}
}
pub const fn pre(self) -> Self {
match self {
Digit::Neg => Digit::Pos,
Digit::Zero => Digit::Neg,
Digit::Pos => Digit::Zero,
}
}
pub const fn to_unbalanced(self) -> u8 {
match self {
Digit::Neg => 0,
Digit::Zero => 1,
Digit::Pos => 2,
}
}
pub const fn from_unbalanced(u: u8) -> Digit {
match u {
0 => Digit::Neg,
1 => Digit::Zero,
2 => Digit::Pos,
_ => panic!("Invalid value. A unbalanced ternary value must be either 0, 1 or 2."),
}
}
#[cfg(feature = "ternary-string")]
pub fn inc(self) -> Ternary {
match self {
Digit::Neg => Ternary::parse("0"),
Digit::Zero => Ternary::parse("+"),
Digit::Pos => Ternary::parse("+-"),
}
}
#[cfg(feature = "ternary-string")]
pub fn dec(self) -> Ternary {
match self {
Digit::Neg => Ternary::parse("-+"),
Digit::Zero => Ternary::parse("-"),
Digit::Pos => Ternary::parse("0"),
}
}
}
impl Neg for Digit {
type Output = Self;
fn neg(self) -> Self::Output {
match self {
Digit::Neg => Digit::Pos,
Digit::Zero => Digit::Zero,
Digit::Pos => Digit::Neg,
}
}
}
impl Not for Digit {
type Output = Self;
fn not(self) -> Self::Output {
-self
}
}
impl Add<Digit> for Digit {
type Output = Digit;
fn add(self, other: Digit) -> Self::Output {
match self {
Digit::Neg => other.pre(),
Digit::Zero => other,
Digit::Pos => other.post(),
}
}
}
impl Sub<Digit> for Digit {
type Output = Digit;
fn sub(self, other: Digit) -> Self::Output {
match self {
Digit::Neg => other.post(),
Digit::Zero => -other,
Digit::Pos => other.pre(),
}
}
}
impl Mul<Digit> for Digit {
type Output = Digit;
fn mul(self, other: Digit) -> Self::Output {
match self {
Digit::Neg => -other,
Digit::Zero => Digit::Zero,
Digit::Pos => other,
}
}
}
impl Div<Digit> for Digit {
type Output = Digit;
fn div(self, other: Digit) -> Self::Output {
if other == Digit::Zero {
panic!("Cannot divide by zero.");
}
self * other
}
}
impl BitAnd for Digit {
type Output = Self;
fn bitand(self, other: Self) -> Self::Output {
match self {
Digit::Neg => Digit::Neg,
Digit::Zero => other.negative(),
Digit::Pos => other,
}
}
}
impl BitOr for Digit {
type Output = Self;
fn bitor(self, other: Self) -> Self::Output {
match self {
Digit::Neg => other,
Digit::Zero => other.positive(),
Digit::Pos => Digit::Pos,
}
}
}
impl BitXor for Digit {
type Output = Self;
fn bitxor(self, rhs: Self) -> Self::Output {
match self {
Digit::Neg => rhs,
Digit::Zero => Digit::Zero,
Digit::Pos => -rhs,
}
}
}