1use std::fmt::Write;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
6#[repr(i8)]
7pub enum Trit {
8 N = -1,
10 Z = 0,
12 P = 1,
14}
15
16const fn idx(t: Trit) -> usize {
18 (t as i8 + 1).cast_unsigned() as usize
19}
20
21static TMIN: [Trit; 9] = {
30 use Trit::{N, P, Z};
31 [N, N, N, N, Z, Z, N, Z, P]
32};
33
34static TMAX: [Trit; 9] = {
43 use Trit::{N, P, Z};
44 [N, Z, P, Z, Z, P, P, P, P]
45};
46
47static ADD_SUM: [Trit; 9] = {
56 use Trit::{N, P, Z};
57 [P, N, Z, N, Z, P, Z, P, N]
58};
59
60static ADD_CARRY: [Trit; 9] = {
71 use Trit::{N, P, Z};
72 [N, Z, Z, Z, Z, Z, Z, Z, P]
73};
74
75static CONSENSUS: [Trit; 9] = {
87 use Trit::{N, P, Z};
88 [N, Z, Z, Z, Z, Z, Z, Z, P]
89};
90
91impl Trit {
93 pub const fn new(val: i8) -> Self {
98 match val {
99 -1 => Self::N,
100 1 => Self::P,
101 _ => Self::Z,
102 }
103 }
104
105 pub const fn value(self) -> i8 {
107 self as i8
108 }
109
110 #[must_use]
112 pub const fn negate(self) -> Self {
113 match self {
114 Self::N => Self::P,
115 Self::Z => Self::Z,
116 Self::P => Self::N,
117 }
118 }
119
120 #[must_use]
122 pub const fn abs(self) -> Self {
123 match self {
124 Self::N => Self::P,
125 other => other,
126 }
127 }
128
129 #[must_use]
131 pub const fn inc(self) -> Self {
132 match self {
133 Self::N => Self::Z,
134 Self::Z => Self::P,
135 Self::P => Self::N,
136 }
137 }
138
139 #[must_use]
141 pub const fn dec(self) -> Self {
142 match self {
143 Self::N => Self::P,
144 Self::Z => Self::N,
145 Self::P => Self::Z,
146 }
147 }
148
149 #[must_use]
153 pub const fn sign(self) -> Self {
154 self
155 }
156
157 pub const fn is_zero(self) -> bool {
159 matches!(self, Self::Z)
160 }
161
162 pub const fn is_positive(self) -> bool {
164 matches!(self, Self::P)
165 }
166
167 pub const fn is_negative(self) -> bool {
169 matches!(self, Self::N)
170 }
171
172 #[must_use]
174 #[inline]
175 pub const fn tmin(self, other: Self) -> Self {
176 TMIN[idx(self) * 3 + idx(other)]
177 }
178
179 #[must_use]
181 #[inline]
182 pub const fn tmax(self, other: Self) -> Self {
183 TMAX[idx(self) * 3 + idx(other)]
184 }
185
186 #[must_use]
188 #[inline]
189 pub const fn tnot(self) -> Self {
190 match self {
191 Self::N => Self::P,
192 Self::Z => Self::Z,
193 Self::P => Self::N,
194 }
195 }
196
197 #[must_use]
199 #[inline]
200 pub const fn clip(self) -> Self {
201 self
202 }
203
204 #[must_use]
208 #[inline]
209 pub const fn add(self, other: Self) -> (Self, Self) {
210 let i = idx(self) * 3 + idx(other);
211 (ADD_SUM[i], ADD_CARRY[i])
212 }
213
214 #[must_use]
216 #[inline]
217 pub const fn consensus(self, other: Self) -> Self {
218 CONSENSUS[idx(self) * 3 + idx(other)]
219 }
220}
221
222impl From<Trit> for i8 {
223 #[inline]
224 fn from(t: Trit) -> Self {
225 t as Self
226 }
227}
228
229impl TryFrom<i8> for Trit {
230 type Error = &'static str;
231
232 fn try_from(val: i8) -> Result<Self, Self::Error> {
233 match val {
234 -1 => Ok(Self::N),
235 0 => Ok(Self::Z),
236 1 => Ok(Self::P),
237 _ => Err("Trit value must be -1, 0, or 1."),
238 }
239 }
240}
241
242impl std::fmt::Display for Trit {
243 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
244 f.write_char(match self {
245 Self::N => 'N',
246 Self::Z => 'Z',
247 Self::P => 'P',
248 })
249 }
250}
251
252#[cfg(test)]
254mod tests {
255 use super::*;
256
257 const _: Trit = Trit::N.negate();
259 const _: Trit = Trit::P.tmin(Trit::Z);
260 const _: Trit = Trit::N.tmax(Trit::P);
261 const _: (Trit, Trit) = Trit::P.add(Trit::P);
262 const _: () = assert!(Trit::N.negate() as i8 == 1);
263 const _: () = assert!(Trit::P.add(Trit::P).1 as i8 == 1);
264
265 const _: Trit = Trit::N.clip();
267 const _: () = assert!(Trit::P.clip() as i8 == 1);
268 const _: () = assert!(Trit::N.clip() as i8 == -1);
269 const _: () = assert!(Trit::Z.clip() as i8 == 0);
270}