balanced_ternary/
tryte.rs1use crate::{
2 Digit,
3 Digit::{Neg, Pos, Zero},
4 Ternary,
5};
6use alloc::string::{String, ToString};
7use core::fmt::{Display, Formatter};
8use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg as StdNeg, Not, Sub};
9
10#[derive(Clone, PartialEq, Eq, Hash, Debug, Copy)]
35pub struct Tryte<const SIZE: usize = 6> {
36 raw: [Digit; SIZE],
38}
39
40impl<const SIZE: usize> Tryte<SIZE> {
41 pub const MAX: Self = Self::new([Pos; SIZE]);
43 pub const MIN: Self = Self::new([Neg; SIZE]);
45 pub const ZERO: Self = Self::new([Zero; SIZE]);
47
48 pub const fn new(digits: [Digit; SIZE]) -> Self {
72 if SIZE > 40 {
73 panic!("Cannot construct a Tryte with more than 40 digits (~63.5 bits).")
74 }
75 Self { raw: digits }
76 }
77
78 pub fn to_ternary(&self) -> Ternary {
84 Ternary::new(self.raw.to_vec())
85 }
86
87 pub const fn to_digit_slice(&self) -> &[Digit] {
96 &self.raw
97 }
98
99 pub fn from_ternary(v: &Ternary) -> Self {
109 if v.log() > SIZE {
110 panic!(
111 "Cannot convert a Ternary with more than {} digits to a Tryte<{}>.",
112 SIZE, SIZE
113 );
114 }
115 let mut digits = [Zero; SIZE];
116 for (i, d) in v.digits.iter().rev().enumerate() {
117 digits[SIZE - 1 - i] = *d;
118 }
119 Self::new(digits)
120 }
121
122 pub fn to_i64(&self) -> i64 {
128 self.to_ternary().to_dec()
129 }
130
131 pub fn from_i64(v: i64) -> Self {
141 Self::from_ternary(&Ternary::from_dec(v))
142 }
143
144 pub fn digit(&self, index: usize) -> Digit {
158 if index > SIZE - 1 {
159 panic!(
160 "Cannot access a digit at index {}. Tryte<{}> has only {} digits.",
161 index, SIZE, SIZE
162 );
163 }
164 *self.raw.iter().rev().nth(index).unwrap()
165 }
166
167 pub fn each(&self, f: impl Fn(Digit) -> Digit) -> Self {
169 Self::from_ternary(&self.to_ternary().each(f))
170 }
171
172 pub fn each_with(&self, f: impl Fn(Digit, Digit) -> Digit, with: Digit) -> Self {
174 Self::from_ternary(&self.to_ternary().each_with(f, with))
175 }
176
177 pub fn each_zip(&self, f: impl Fn(Digit, Digit) -> Digit, other: Self) -> Self {
179 Self::from_ternary(&self.to_ternary().each_zip(f, other.to_ternary()))
180 }
181
182 pub fn each_zip_carry(
184 &self,
185 f: impl Fn(Digit, Digit, Digit) -> (Digit, Digit),
186 other: Self,
187 ) -> Self {
188 Self::from_ternary(&self.to_ternary().each_zip_carry(f, other.to_ternary()))
189 }
190}
191
192impl<const SIZE: usize> Display for Tryte<SIZE> {
193 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
198 write!(f, "{:01$}", self.to_ternary().to_string(), SIZE)
199 }
200}
201
202impl<const SIZE: usize> StdNeg for Tryte<SIZE> {
203 type Output = Tryte<SIZE>;
204 fn neg(self) -> Self::Output {
205 Self::from_ternary(&-&self.to_ternary())
206 }
207}
208
209impl<const SIZE: usize> Add for Tryte<SIZE> {
210 type Output = Tryte<SIZE>;
211
212 fn add(self, rhs: Self) -> Self::Output {
213 Self::from_ternary(&(&self.to_ternary() + &rhs.to_ternary()))
214 }
215}
216
217impl<const SIZE: usize> Sub for Tryte<SIZE> {
218 type Output = Tryte<SIZE>;
219
220 fn sub(self, rhs: Self) -> Self::Output {
221 Self::from_ternary(&(&self.to_ternary() - &rhs.to_ternary()))
222 }
223}
224
225impl<const SIZE: usize> Mul for Tryte<SIZE> {
226 type Output = Tryte<SIZE>;
227
228 fn mul(self, rhs: Self) -> Self::Output {
229 Self::from_ternary(&(&self.to_ternary() * &rhs.to_ternary()))
230 }
231}
232
233impl<const SIZE: usize> Div for Tryte<SIZE> {
234 type Output = Tryte<SIZE>;
235
236 fn div(self, rhs: Self) -> Self::Output {
237 Self::from_ternary(&(&self.to_ternary() / &rhs.to_ternary()))
238 }
239}
240
241impl<const SIZE: usize> BitAnd for Tryte<SIZE> {
242 type Output = Tryte<SIZE>;
243 fn bitand(self, rhs: Self) -> Self::Output {
244 Self::from_ternary(&(&self.to_ternary() & &rhs.to_ternary()))
245 }
246}
247
248impl<const SIZE: usize> BitOr for Tryte<SIZE> {
249 type Output = Tryte<SIZE>;
250 fn bitor(self, rhs: Self) -> Self::Output {
251 Self::from_ternary(&(&self.to_ternary() | &rhs.to_ternary()))
252 }
253}
254
255impl<const SIZE: usize> BitXor for Tryte<SIZE> {
256 type Output = Tryte<SIZE>;
257 fn bitxor(self, rhs: Self) -> Self::Output {
258 Self::from_ternary(&(&self.to_ternary() ^ &rhs.to_ternary()))
259 }
260}
261
262impl<const SIZE: usize> Not for Tryte<SIZE> {
263 type Output = Tryte<SIZE>;
264 fn not(self) -> Self::Output {
265 -self
266 }
267}
268
269impl<const SIZE: usize> From<Ternary> for Tryte<SIZE> {
270 fn from(value: Ternary) -> Self {
271 Tryte::from_ternary(&value)
272 }
273}
274
275impl<const SIZE: usize> From<Tryte<SIZE>> for Ternary {
276 fn from(value: Tryte<SIZE>) -> Self {
277 value.to_ternary()
278 }
279}
280
281impl<const SIZE: usize> From<&str> for Tryte<SIZE> {
282 fn from(value: &str) -> Self {
283 Self::from_ternary(&Ternary::parse(value))
284 }
285}
286
287impl<const SIZE: usize> From<String> for Tryte<SIZE> {
288 fn from(value: String) -> Self {
289 Self::from(value.as_str())
290 }
291}
292
293impl<const SIZE: usize> From<Tryte<SIZE>> for String {
294 fn from(value: Tryte<SIZE>) -> Self {
295 value.to_string()
296 }
297}
298
299impl<const SIZE: usize> From<i64> for Tryte<SIZE> {
300 fn from(value: i64) -> Self {
301 Self::from_i64(value)
302 }
303}
304
305impl<const SIZE: usize> From<Tryte<SIZE>> for i64 {
306 fn from(value: Tryte<SIZE>) -> Self {
307 value.to_i64()
308 }
309}
310
311#[cfg(test)]
312#[test]
313pub fn test_tryte() {
314 let tryte = Tryte::<6>::from_i64(255);
315 assert_eq!(tryte.to_i64(), 255);
316 assert_eq!(tryte.to_string(), "+00++0");
317
318 let tryte = Tryte::<6>::from_i64(16);
319 assert_eq!(tryte.to_i64(), 16);
320 assert_eq!(tryte.to_string(), "00+--+");
321
322 assert_eq!(Tryte::<6>::MAX.to_string(), "++++++");
323 assert_eq!(Tryte::<6>::MAX.to_i64(), 364);
324 assert_eq!(Tryte::<6>::MIN.to_string(), "------");
325 assert_eq!(Tryte::<6>::MIN.to_i64(), -364);
326 assert_eq!(Tryte::<6>::ZERO.to_string(), "000000");
327 assert_eq!(Tryte::<6>::ZERO.to_i64(), 0);
328}