balanced_ternary/
tryte.rs1use crate::{Digit, Ternary};
13use alloc::string::ToString;
14use core::fmt::{Display, Formatter};
15use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Sub};
16
17#[derive(Clone, PartialEq, Eq, Hash, Debug, Copy)]
22pub struct Tryte {
23 raw: [Digit; 6],
25}
26
27impl Tryte {
28 pub const MAX: Self = Self {
30 raw: [Digit::Pos; 6],
31 };
32 pub const MIN: Self = Self {
34 raw: [Digit::Neg; 6],
35 };
36 pub const ZERO: Self = Self {
38 raw: [Digit::Zero; 6],
39 };
40
41 pub fn to_ternary(&self) -> Ternary {
47 Ternary::new(self.raw.to_vec())
48 }
49
50 pub fn from_ternary(v: &Ternary) -> Self {
60 if v.log() > 6 {
61 panic!("Cannot convert a Ternary with more than 6 digits to a Tryte.");
62 }
63 let mut digits = [Digit::Zero; 6];
64 for (i, d) in v.digits.iter().rev().enumerate() {
65 digits[5 - i] = *d;
66 }
67 Self { raw: digits }
68 }
69
70 pub fn to_i16(&self) -> i16 {
76 self.to_ternary().to_dec() as i16
77 }
78
79 pub fn from_i8(v: i8) -> Self {
89 Self::from_ternary(&Ternary::from_dec(v as i64))
90 }
91
92 pub fn from_i16(v: i16) -> Self {
102 Self::from_ternary(&Ternary::from_dec(v as i64))
103 }
104
105 pub fn digit(&self, index: usize) -> Digit {
119 if index > 5 {
120 panic!(
121 "Cannot access a digit at index {}. Tryte has only 6 digits.",
122 index
123 );
124 }
125 self.raw[index]
126 }
127}
128
129impl Display for Tryte {
130 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
135 write!(f, "{:06}", self.to_ternary().to_string())
136 }
137}
138
139impl Add for Tryte {
140 type Output = Tryte;
141
142 fn add(self, rhs: Self) -> Self::Output {
143 Self::from_ternary(&(&self.to_ternary() + &rhs.to_ternary()))
144 }
145}
146
147impl Sub for Tryte {
148 type Output = Tryte;
149
150 fn sub(self, rhs: Self) -> Self::Output {
151 Self::from_ternary(&(&self.to_ternary() - &rhs.to_ternary()))
152 }
153}
154
155impl Mul for Tryte {
156 type Output = Tryte;
157
158 fn mul(self, rhs: Self) -> Self::Output {
159 Self::from_ternary(&(&self.to_ternary() * &rhs.to_ternary()))
160 }
161}
162
163impl Div for Tryte {
164 type Output = Tryte;
165
166 fn div(self, rhs: Self) -> Self::Output {
167 Self::from_ternary(&(&self.to_ternary() / &rhs.to_ternary()))
168 }
169}
170
171impl BitAnd for Tryte {
172 type Output = Tryte;
173 fn bitand(self, rhs: Self) -> Self::Output {
174 Self::from_ternary(&(&self.to_ternary() & &rhs.to_ternary()))
175 }
176}
177
178impl BitOr for Tryte {
179 type Output = Tryte;
180 fn bitor(self, rhs: Self) -> Self::Output {
181 Self::from_ternary(&(&self.to_ternary() | &rhs.to_ternary()))
182 }
183}
184
185impl BitXor for Tryte {
186 type Output = Tryte;
187 fn bitxor(self, rhs: Self) -> Self::Output {
188 Self::from_ternary(&(&self.to_ternary() ^ &rhs.to_ternary()))
189 }
190}
191
192impl From<Ternary> for Tryte {
193 fn from(value: Ternary) -> Self {
194 Tryte::from_ternary(&value)
195 }
196}
197
198impl From<Tryte> for Ternary {
199 fn from(value: Tryte) -> Self {
200 value.to_ternary()
201 }
202}
203
204#[cfg(test)]
205#[test]
206pub fn test_tryte() {
211 let tryte = Tryte::from_i16(255);
212 assert_eq!(tryte.to_i16(), 255);
213 assert_eq!(tryte.to_string(), "+00++0");
214
215 let tryte = Tryte::from_i8(16);
216 assert_eq!(tryte.to_i16(), 16);
217 assert_eq!(tryte.to_string(), "00+--+");
218
219 assert_eq!(Tryte::MAX.to_string(), "++++++");
220 assert_eq!(Tryte::MAX.to_i16(), 364);
221 assert_eq!(Tryte::MIN.to_string(), "------");
222 assert_eq!(Tryte::MIN.to_i16(), -364);
223 assert_eq!(Tryte::ZERO.to_string(), "000000");
224 assert_eq!(Tryte::ZERO.to_i16(), 0);
225}