use std::fmt::{Debug, Display, Formatter, self};
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct Bool;
impl Bool {
#[inline(always)]
pub fn get_string(&self) -> &'static str { "#bool" }
}
impl Debug for Bool {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
<Self as Display>::fmt(self, fmt)
}
}
impl Display for Bool {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", self.get_string())
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub enum LogicalOp {
Binary(Binary),
Unary(Unary)
}
impl Debug for LogicalOp {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
<Self as Display>::fmt(self, fmt)
}
}
impl Display for LogicalOp {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
match self {
Self::Binary(b) => <Binary as fmt::Display>::fmt(b, fmt),
Self::Unary(u) => <Unary as fmt::Display>::fmt(u, fmt)
}
}
}
impl From<Binary> for LogicalOp {
#[inline] fn from(b: Binary) -> LogicalOp { LogicalOp::Binary(b) }
}
impl PartialEq<Binary> for LogicalOp {
#[inline] fn eq(&self, b: &Binary) -> bool { self.eq(&LogicalOp::from(*b)) }
}
impl From<Unary> for LogicalOp {
#[inline] fn from(u: Unary) -> LogicalOp { LogicalOp::Unary(u) }
}
impl PartialEq<Unary> for LogicalOp {
#[inline] fn eq(&self, u: &Unary) -> bool { self.eq(&LogicalOp::from(*u)) }
}
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub enum Binary {
And,
Or,
Xor,
Nand,
Nor,
Eq,
Implies,
ImpliedBy
}
use Binary::*;
pub const BINARY_OPS: &[Binary] = &[And, Or, Xor, Nand, Nor, Eq, Implies, ImpliedBy];
impl Binary {
#[inline(always)]
pub fn get_string(&self) -> &'static str {
use Binary::*;
match self {
And => "#and",
Or => "#or",
Xor => "#xor",
Nand => "#nand",
Nor => "#nor",
Eq => "#eq",
Implies => "#implies",
ImpliedBy => "#impliedby"
}
}
#[inline(always)]
pub fn apply(&self, left: bool, right: bool) -> bool {
use Binary::*;
match self {
And => left & right,
Or => left | right,
Xor => left ^ right,
Nand => !(left & right),
Nor => !(left | right),
Eq => left == right,
Implies => !left | right,
ImpliedBy => left | !right
}
}
#[inline(always)]
pub fn partial_apply(&self, arg: bool) -> Unary {
use Unary::*;
use Binary::*;
match (self, arg) {
(And, true) => Id,
(And, false) => Constant(false),
(Or, true) => Constant(true),
(Or, false) => Id,
(Xor, true) => Not,
(Xor, false) => Id,
(Nand, true) => Not,
(Nand, false) => Constant(true),
(Nor, true) => Constant(false),
(Nor, false) => Not,
(Eq, true) => Id,
(Eq, false) => Not,
(Implies, true) => Id,
(Implies, false) => Constant(true),
(ImpliedBy, true) => Constant(true),
(ImpliedBy, false) => Not
}
}
}
impl Debug for Binary {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
<Self as Display>::fmt(self, fmt)
}
}
impl Display for Binary {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", self.get_string())
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub enum Unary {
Id,
Not,
Constant(bool)
}
use Unary::*;
pub const UNARY_OPS: &[Unary] = &[Id, Not, Constant(true), Constant(false)];
impl Unary {
#[inline(always)]
pub fn get_string(&self) -> &'static str {
match self {
Unary::Id => "#id", Unary::Not => "#not",
Unary::Constant(c) => if *c { "#constant_true" } else { "#constant_false" }
}
}
#[inline(always)]
pub fn apply(&self, arg: bool) -> bool {
match self {
Unary::Id => arg,
Unary::Not => !arg,
Unary::Constant(c) => *c
}
}
}
impl Debug for Unary {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
<Self as Display>::fmt(self, fmt)
}
}
impl Display for Unary {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", self.get_string())
}
}
#[cfg(test)]
pub mod tests {
#[test]
fn logical_operations_work() {
use super::Binary::*;
let f = false;
let t = true;
let ops = [
(And, f, f, f),
(And, t, f, f),
(And, f, t, f),
(And, t, t, t),
(Or, f, f, f),
(Or, t, f, t),
(Or, f, t, t),
(Or, t, t, t),
(Xor, f, f, f),
(Xor, t, f, t),
(Xor, f, t, t),
(Xor, t, t, f),
(Nand, f, f, t),
(Nand, t, f, t),
(Nand, f, t, t),
(Nand, t, t, f),
(Nor, f, f, t),
(Nor, t, f, f),
(Nor, f, t, f),
(Nor, t, t, f),
(Eq, f, f, t),
(Eq, t, f, f),
(Eq, f, t, f),
(Eq, t, t, t),
(Implies, f, f, t),
(Implies, t, f, f),
(Implies, f, t, t),
(Implies, t, t, t),
(ImpliedBy, f, f, t),
(ImpliedBy, t, f, t),
(ImpliedBy, f, t, f),
(ImpliedBy, t, t, t),
];
for op in ops.iter() {
assert_eq!(op.0.apply(op.1, op.2), op.3,
"Incorrect value for ({} {} {}) = {}", op.0, op.1, op.2, op.3);
assert_eq!(op.0.partial_apply(op.1).apply(op.2), op.3,
"Incorrect value for (({} {}) {}) = ({} {}) = {}",
op.0, op.1, op.2, op.0.partial_apply(op.1), op.2, op.3);
}
}
}