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