1use std::fmt;
2use std::ops::{Add, Mul, Neg};
3use serde::{Serialize, Deserialize};
4
5use std::sync::LazyLock;
6
7static ADD_TABLE: LazyLock<[[u8; 243]; 243]> = LazyLock::new(|| {
8 let mut table = [[0u8; 243]; 243];
9 for i in 0..243 {
10 for j in 0..243 {
11 let t1 = unpack_5_trits(i as u8);
12 let t2 = unpack_5_trits(j as u8);
13 let mut res = [Trit::Tend; 5];
14 for k in 0..5 {
15 let (sum, _) = t1[k] + t2[k];
16 res[k] = sum;
17 }
18 table[i][j] = pack_5_trits(res);
19 }
20 }
21 table
22});
23
24static CONSENSUS_TABLE: LazyLock<[[u8; 243]; 243]> = LazyLock::new(|| {
25 let mut table = [[0u8; 243]; 243];
26 for i in 0..243 {
27 for j in 0..243 {
28 let t1 = unpack_5_trits(i as u8);
29 let t2 = unpack_5_trits(j as u8);
30 let mut res = [Trit::Tend; 5];
31 for k in 0..5 {
32 res[k] = match (t1[k], t2[k]) {
33 (Trit::Affirm, Trit::Affirm) => Trit::Affirm,
34 (Trit::Reject, Trit::Reject) => Trit::Reject,
35 (Trit::Tend, x) => x,
36 (x, Trit::Tend) => x,
37 _ => Trit::Tend,
38 };
39 }
40 table[i][j] = pack_5_trits(res);
41 }
42 }
43 table
44});
45
46static NEG_TABLE: LazyLock<[u8; 243]> = LazyLock::new(|| {
47 let mut table = [0u8; 243];
48 for i in 0..243 {
49 let t = unpack_5_trits(i as u8);
50 let mut res = [Trit::Tend; 5];
51 for k in 0..5 {
52 res[k] = -t[k];
53 }
54 table[i] = pack_5_trits(res);
55 }
56 table
57});
58
59pub fn packed_neg(a: u8) -> u8 {
60 NEG_TABLE[a as usize]
61}
62
63pub fn packed_add(a: u8, b: u8) -> u8 {
64 ADD_TABLE[a as usize][b as usize]
65}
66
67pub fn packed_consensus(a: u8, b: u8) -> u8 {
68 CONSENSUS_TABLE[a as usize][b as usize]
69}
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
72pub enum Trit {
73 Reject = -1, Tend = 0, Affirm = 1, }
77
78impl From<i8> for Trit {
79 fn from(val: i8) -> Self {
80 if val > 0 { Trit::Affirm }
85 else if val < 0 { Trit::Reject }
86 else { Trit::Tend }
87 }
88}
89
90impl fmt::Display for Trit {
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 match self {
93 Trit::Reject => write!(f, "reject"),
94 Trit::Tend => write!(f, "tend"),
95 Trit::Affirm => write!(f, "affirm"),
96 }
97 }
98}
99
100impl Neg for Trit {
101 type Output = Self;
102
103 fn neg(self) -> Self::Output {
104 match self {
105 Trit::Reject => Trit::Affirm,
106 Trit::Tend => Trit::Tend,
107 Trit::Affirm => Trit::Reject,
108 }
109 }
110}
111
112impl Add for Trit {
113 type Output = (Self, Self); fn add(self, rhs: Self) -> Self::Output {
116 match (self, rhs) {
117 (Trit::Reject, Trit::Reject) => (Trit::Affirm, Trit::Reject),
118 (Trit::Reject, Trit::Tend) => (Trit::Reject, Trit::Tend),
119 (Trit::Reject, Trit::Affirm) => (Trit::Tend, Trit::Tend),
120 (Trit::Tend, Trit::Reject) => (Trit::Reject, Trit::Tend),
121 (Trit::Tend, Trit::Tend) => (Trit::Tend, Trit::Tend),
122 (Trit::Tend, Trit::Affirm) => (Trit::Affirm, Trit::Tend),
123 (Trit::Affirm, Trit::Reject) => (Trit::Tend, Trit::Tend),
124 (Trit::Affirm, Trit::Tend) => (Trit::Affirm, Trit::Tend),
125 (Trit::Affirm, Trit::Affirm) => (Trit::Reject, Trit::Affirm),
126 }
127 }
128}
129
130impl Mul for Trit {
131 type Output = Self;
132
133 fn mul(self, rhs: Self) -> Self::Output {
134 match (self, rhs) {
135 (Trit::Tend, _) | (_, Trit::Tend) => Trit::Tend,
136 (Trit::Affirm, Trit::Affirm) | (Trit::Reject, Trit::Reject) => Trit::Affirm,
137 (Trit::Affirm, Trit::Reject) | (Trit::Reject, Trit::Affirm) => Trit::Reject,
138 }
139 }
140}
141
142pub fn pack_5_trits(trits: [Trit; 5]) -> u8 {
145 let mut val: u8 = 0;
146 let mut multiplier: u8 = 1;
147 for &t in &trits {
148 let t_val = match t {
149 Trit::Reject => 0,
150 Trit::Tend => 1,
151 Trit::Affirm => 2,
152 };
153 val += t_val * multiplier;
154 multiplier *= 3;
155 }
156 val
157}
158
159pub fn unpack_5_trits(mut val: u8) -> [Trit; 5] {
161 let mut trits = [Trit::Tend; 5];
162 for i in 0..5 {
163 let t_val = val % 3;
164 trits[i] = match t_val {
165 0 => Trit::Reject,
166 1 => Trit::Tend,
167 2 => Trit::Affirm,
168 _ => unreachable!(),
169 };
170 val /= 3;
171 }
172 trits
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178
179 #[test]
180 fn test_packing() {
181 let test_cases = [
182 [Trit::Reject; 5],
183 [Trit::Tend; 5],
184 [Trit::Affirm; 5],
185 [Trit::Reject, Trit::Tend, Trit::Affirm, Trit::Reject, Trit::Tend],
186 [Trit::Affirm, Trit::Reject, Trit::Tend, Trit::Affirm, Trit::Reject],
187 ];
188
189 for &original in &test_cases {
190 let packed = pack_5_trits(original);
191 let unpacked = unpack_5_trits(packed);
192 assert_eq!(original, unpacked);
193 }
194 }
195
196 #[test]
197 fn test_negation() {
198 assert_eq!(-Trit::Reject, Trit::Affirm);
199 assert_eq!(-Trit::Tend, Trit::Tend);
200 assert_eq!(-Trit::Affirm, Trit::Reject);
201 }
202
203 #[test]
204 fn test_addition() {
205 assert_eq!(Trit::Reject + Trit::Reject, (Trit::Affirm, Trit::Reject));
206 assert_eq!(Trit::Reject + Trit::Tend, (Trit::Reject, Trit::Tend));
207 assert_eq!(Trit::Reject + Trit::Affirm, (Trit::Tend, Trit::Tend));
208 assert_eq!(Trit::Tend + Trit::Reject, (Trit::Reject, Trit::Tend));
209 assert_eq!(Trit::Tend + Trit::Tend, (Trit::Tend, Trit::Tend));
210 assert_eq!(Trit::Tend + Trit::Affirm, (Trit::Affirm, Trit::Tend));
211 assert_eq!(Trit::Affirm + Trit::Reject, (Trit::Tend, Trit::Tend));
212 assert_eq!(Trit::Affirm + Trit::Tend, (Trit::Affirm, Trit::Tend));
213 assert_eq!(Trit::Affirm + Trit::Affirm, (Trit::Reject, Trit::Affirm));
214 }
215
216 #[test]
217 fn test_multiplication() {
218 assert_eq!(Trit::Reject * Trit::Reject, Trit::Affirm);
219 assert_eq!(Trit::Reject * Trit::Tend, Trit::Tend);
220 assert_eq!(Trit::Reject * Trit::Affirm, Trit::Reject);
221 assert_eq!(Trit::Tend * Trit::Reject, Trit::Tend);
222 assert_eq!(Trit::Tend * Trit::Tend, Trit::Tend);
223 assert_eq!(Trit::Tend * Trit::Affirm, Trit::Tend);
224 assert_eq!(Trit::Affirm * Trit::Reject, Trit::Reject);
225 assert_eq!(Trit::Affirm * Trit::Tend, Trit::Tend);
226 assert_eq!(Trit::Affirm * Trit::Affirm, Trit::Affirm);
227 }
228}