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, Neg, Not, 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 to_digit_slice(&self) -> &[Digit] {
59 &self.raw
60 }
61
62 pub fn from_ternary(v: &Ternary) -> Self {
72 if v.log() > 6 {
73 panic!("Cannot convert a Ternary with more than 6 digits to a Tryte.");
74 }
75 let mut digits = [Digit::Zero; 6];
76 for (i, d) in v.digits.iter().rev().enumerate() {
77 digits[5 - i] = *d;
78 }
79 Self { raw: digits }
80 }
81
82 pub fn to_i16(&self) -> i16 {
88 self.to_ternary().to_dec() as i16
89 }
90
91 pub fn from_i8(v: i8) -> Self {
101 Self::from_ternary(&Ternary::from_dec(v as i64))
102 }
103
104 pub fn from_i16(v: i16) -> Self {
114 Self::from_ternary(&Ternary::from_dec(v as i64))
115 }
116
117 pub fn digit(&self, index: usize) -> Digit {
131 if index > 5 {
132 panic!(
133 "Cannot access a digit at index {}. Tryte has only 6 digits.",
134 index
135 );
136 }
137 *self.raw.iter().rev().nth(index).unwrap()
138 }
139}
140
141impl Display for Tryte {
142 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
147 write!(f, "{:06}", self.to_ternary().to_string())
148 }
149}
150
151impl Neg for Tryte {
152 type Output = Tryte;
153 fn neg(self) -> Self::Output {
154 Self::from_ternary(&-&self.to_ternary())
155 }
156}
157
158impl Add for Tryte {
159 type Output = Tryte;
160
161 fn add(self, rhs: Self) -> Self::Output {
162 Self::from_ternary(&(&self.to_ternary() + &rhs.to_ternary()))
163 }
164}
165
166impl Sub for Tryte {
167 type Output = Tryte;
168
169 fn sub(self, rhs: Self) -> Self::Output {
170 Self::from_ternary(&(&self.to_ternary() - &rhs.to_ternary()))
171 }
172}
173
174impl Mul for Tryte {
175 type Output = Tryte;
176
177 fn mul(self, rhs: Self) -> Self::Output {
178 Self::from_ternary(&(&self.to_ternary() * &rhs.to_ternary()))
179 }
180}
181
182impl Div for Tryte {
183 type Output = Tryte;
184
185 fn div(self, rhs: Self) -> Self::Output {
186 Self::from_ternary(&(&self.to_ternary() / &rhs.to_ternary()))
187 }
188}
189
190impl BitAnd for Tryte {
191 type Output = Tryte;
192 fn bitand(self, rhs: Self) -> Self::Output {
193 Self::from_ternary(&(&self.to_ternary() & &rhs.to_ternary()))
194 }
195}
196
197impl BitOr for Tryte {
198 type Output = Tryte;
199 fn bitor(self, rhs: Self) -> Self::Output {
200 Self::from_ternary(&(&self.to_ternary() | &rhs.to_ternary()))
201 }
202}
203
204impl BitXor for Tryte {
205 type Output = Tryte;
206 fn bitxor(self, rhs: Self) -> Self::Output {
207 Self::from_ternary(&(&self.to_ternary() ^ &rhs.to_ternary()))
208 }
209}
210
211impl Not for Tryte {
212 type Output = Tryte;
213 fn not(self) -> Self::Output {
214 -self
215 }
216}
217
218impl From<Ternary> for Tryte {
219 fn from(value: Ternary) -> Self {
220 Tryte::from_ternary(&value)
221 }
222}
223
224impl From<Tryte> for Ternary {
225 fn from(value: Tryte) -> Self {
226 value.to_ternary()
227 }
228}
229
230#[cfg(test)]
231#[test]
232pub fn test_tryte() {
233 let tryte = Tryte::from_i16(255);
234 assert_eq!(tryte.to_i16(), 255);
235 assert_eq!(tryte.to_string(), "+00++0");
236
237 let tryte = Tryte::from_i8(16);
238 assert_eq!(tryte.to_i16(), 16);
239 assert_eq!(tryte.to_string(), "00+--+");
240
241 assert_eq!(Tryte::MAX.to_string(), "++++++");
242 assert_eq!(Tryte::MAX.to_i16(), 364);
243 assert_eq!(Tryte::MIN.to_string(), "------");
244 assert_eq!(Tryte::MIN.to_i16(), -364);
245 assert_eq!(Tryte::ZERO.to_string(), "000000");
246 assert_eq!(Tryte::ZERO.to_i16(), 0);
247}