1use std::fmt::{Debug, Display, Formatter, self};
6
7#[derive(Copy, Clone, Eq, PartialEq, Hash)]
9pub struct Bool;
10
11impl Bool {
12 #[inline(always)]
14 pub fn get_string(&self) -> &'static str { "#bool" }
15}
16
17impl Debug for Bool {
18 fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
19 <Self as Display>::fmt(self, fmt)
20 }
21}
22
23impl Display for Bool {
24 fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
25 write!(fmt, "{}", self.get_string())
26 }
27}
28
29#[derive(Copy, Clone, Eq, PartialEq, Hash)]
31pub enum LogicalOp {
32 Binary(Binary),
34 Unary(Unary)
36}
37
38impl Debug for LogicalOp {
39 fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
40 <Self as Display>::fmt(self, fmt)
41 }
42}
43
44impl Display for LogicalOp {
45 fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
46 match self {
47 Self::Binary(b) => <Binary as fmt::Display>::fmt(b, fmt),
48 Self::Unary(u) => <Unary as fmt::Display>::fmt(u, fmt)
49 }
50 }
51}
52
53impl From<Binary> for LogicalOp {
54 #[inline] fn from(b: Binary) -> LogicalOp { LogicalOp::Binary(b) }
55}
56
57impl PartialEq<Binary> for LogicalOp {
58 #[inline] fn eq(&self, b: &Binary) -> bool { self.eq(&LogicalOp::from(*b)) }
59}
60
61impl From<Unary> for LogicalOp {
62 #[inline] fn from(u: Unary) -> LogicalOp { LogicalOp::Unary(u) }
63}
64
65impl PartialEq<Unary> for LogicalOp {
66 #[inline] fn eq(&self, u: &Unary) -> bool { self.eq(&LogicalOp::from(*u)) }
67}
68
69#[derive(Copy, Clone, Eq, PartialEq, Hash)]
71pub enum Binary {
72 And,
74 Or,
76 Xor,
78 Nand,
80 Nor,
82 Eq,
84 Implies,
86 ImpliedBy
88}
89
90use Binary::*;
91pub const BINARY_OPS: &[Binary] = &[And, Or, Xor, Nand, Nor, Eq, Implies, ImpliedBy];
93
94impl Binary {
95 #[inline(always)]
97 pub fn get_string(&self) -> &'static str {
98 use Binary::*;
99 match self {
100 And => "#and",
101 Or => "#or",
102 Xor => "#xor",
103 Nand => "#nand",
104 Nor => "#nor",
105 Eq => "#eq",
106 Implies => "#implies",
107 ImpliedBy => "#impliedby"
108 }
109 }
110 #[inline(always)]
112 pub fn apply(&self, left: bool, right: bool) -> bool {
113 use Binary::*;
114 match self {
115 And => left & right,
116 Or => left | right,
117 Xor => left ^ right,
118 Nand => !(left & right),
119 Nor => !(left | right),
120 Eq => left == right,
121 Implies => !left | right,
122 ImpliedBy => left | !right
123 }
124 }
125 #[inline(always)]
127 pub fn partial_apply(&self, arg: bool) -> Unary {
128 use Unary::*;
129 use Binary::*;
130 match (self, arg) {
131 (And, true) => Id,
132 (And, false) => Constant(false),
133 (Or, true) => Constant(true),
134 (Or, false) => Id,
135 (Xor, true) => Not,
136 (Xor, false) => Id,
137 (Nand, true) => Not,
138 (Nand, false) => Constant(true),
139 (Nor, true) => Constant(false),
140 (Nor, false) => Not,
141 (Eq, true) => Id,
142 (Eq, false) => Not,
143 (Implies, true) => Id,
144 (Implies, false) => Constant(true),
145 (ImpliedBy, true) => Constant(true),
146 (ImpliedBy, false) => Not
147 }
148 }
149}
150
151impl Debug for Binary {
152 fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
153 <Self as Display>::fmt(self, fmt)
154 }
155}
156
157impl Display for Binary {
158 fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
159 write!(fmt, "{}", self.get_string())
160 }
161}
162
163#[derive(Copy, Clone, Eq, PartialEq, Hash)]
165pub enum Unary {
166 Id,
168 Not,
170 Constant(bool)
172}
173
174use Unary::*;
175pub const UNARY_OPS: &[Unary] = &[Id, Not, Constant(true), Constant(false)];
177
178impl Unary {
179 #[inline(always)]
181 pub fn get_string(&self) -> &'static str {
182 match self {
183 Unary::Id => "#id", Unary::Not => "#not",
185 Unary::Constant(c) => if *c { "#constant_true" } else { "#constant_false" }
187 }
188 }
189 #[inline(always)]
191 pub fn apply(&self, arg: bool) -> bool {
192 match self {
193 Unary::Id => arg,
194 Unary::Not => !arg,
195 Unary::Constant(c) => *c
196 }
197 }
198}
199
200impl Debug for Unary {
201 fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
202 <Self as Display>::fmt(self, fmt)
203 }
204}
205
206impl Display for Unary {
207 fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
208 write!(fmt, "{}", self.get_string())
209 }
210}
211
212#[cfg(test)]
213pub mod tests {
214 #[test]
215 fn logical_operations_work() {
216 use super::Binary::*;
217 let f = false;
218 let t = true;
219 let ops = [
220 (And, f, f, f),
221 (And, t, f, f),
222 (And, f, t, f),
223 (And, t, t, t),
224 (Or, f, f, f),
225 (Or, t, f, t),
226 (Or, f, t, t),
227 (Or, t, t, t),
228 (Xor, f, f, f),
229 (Xor, t, f, t),
230 (Xor, f, t, t),
231 (Xor, t, t, f),
232 (Nand, f, f, t),
233 (Nand, t, f, t),
234 (Nand, f, t, t),
235 (Nand, t, t, f),
236 (Nor, f, f, t),
237 (Nor, t, f, f),
238 (Nor, f, t, f),
239 (Nor, t, t, f),
240 (Eq, f, f, t),
241 (Eq, t, f, f),
242 (Eq, f, t, f),
243 (Eq, t, t, t),
244 (Implies, f, f, t),
245 (Implies, t, f, f),
246 (Implies, f, t, t),
247 (Implies, t, t, t),
248 (ImpliedBy, f, f, t),
249 (ImpliedBy, t, f, t),
250 (ImpliedBy, f, t, f),
251 (ImpliedBy, t, t, t),
252 ];
253 for op in ops.iter() {
254 assert_eq!(op.0.apply(op.1, op.2), op.3,
255 "Incorrect value for ({} {} {}) = {}", op.0, op.1, op.2, op.3);
256 assert_eq!(op.0.partial_apply(op.1).apply(op.2), op.3,
257 "Incorrect value for (({} {}) {}) = ({} {}) = {}",
258 op.0, op.1, op.2, op.0.partial_apply(op.1), op.2, op.3);
259 }
260 }
261}