balanced_ternary/
tryte.rs1use crate::{
13 Digit,
14 Digit::{Neg, Pos, Zero},
15 Ternary,
16};
17use alloc::string::ToString;
18use core::fmt::{Display, Formatter};
19use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg as StdNeg, Not, Sub};
20
21#[derive(Clone, PartialEq, Eq, Hash, Debug, Copy)]
26pub struct Tryte {
27 raw: [Digit; 6],
29}
30
31impl Tryte {
32 pub const MAX: Self = Self { raw: [Pos; 6] };
34 pub const MIN: Self = Self { raw: [Neg; 6] };
36 pub const ZERO: Self = Self { raw: [Zero; 6] };
38
39 pub fn to_ternary(&self) -> Ternary {
45 Ternary::new(self.raw.to_vec())
46 }
47
48 pub fn to_digit_slice(&self) -> &[Digit] {
57 &self.raw
58 }
59
60 pub fn from_ternary(v: &Ternary) -> Self {
70 if v.log() > 6 {
71 panic!("Cannot convert a Ternary with more than 6 digits to a Tryte.");
72 }
73 let mut digits = [Zero; 6];
74 for (i, d) in v.digits.iter().rev().enumerate() {
75 digits[5 - i] = *d;
76 }
77 Self { raw: digits }
78 }
79
80 pub fn to_i16(&self) -> i16 {
86 self.to_ternary().to_dec() as i16
87 }
88
89 pub fn from_i8(v: i8) -> Self {
99 Self::from_ternary(&Ternary::from_dec(v as i64))
100 }
101
102 pub fn from_i16(v: i16) -> Self {
112 Self::from_ternary(&Ternary::from_dec(v as i64))
113 }
114
115 pub fn digit(&self, index: usize) -> Digit {
129 if index > 5 {
130 panic!(
131 "Cannot access a digit at index {}. Tryte has only 6 digits.",
132 index
133 );
134 }
135 *self.raw.iter().rev().nth(index).unwrap()
136 }
137}
138
139impl Display for Tryte {
140 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
145 write!(f, "{:06}", self.to_ternary().to_string())
146 }
147}
148
149impl StdNeg for Tryte {
150 type Output = Tryte;
151 fn neg(self) -> Self::Output {
152 Self::from_ternary(&-&self.to_ternary())
153 }
154}
155
156impl Add for Tryte {
157 type Output = Tryte;
158
159 fn add(self, rhs: Self) -> Self::Output {
160 Self::from_ternary(&(&self.to_ternary() + &rhs.to_ternary()))
161 }
162}
163
164impl Sub for Tryte {
165 type Output = Tryte;
166
167 fn sub(self, rhs: Self) -> Self::Output {
168 Self::from_ternary(&(&self.to_ternary() - &rhs.to_ternary()))
169 }
170}
171
172impl Mul for Tryte {
173 type Output = Tryte;
174
175 fn mul(self, rhs: Self) -> Self::Output {
176 Self::from_ternary(&(&self.to_ternary() * &rhs.to_ternary()))
177 }
178}
179
180impl Div for Tryte {
181 type Output = Tryte;
182
183 fn div(self, rhs: Self) -> Self::Output {
184 Self::from_ternary(&(&self.to_ternary() / &rhs.to_ternary()))
185 }
186}
187
188impl BitAnd for Tryte {
189 type Output = Tryte;
190 fn bitand(self, rhs: Self) -> Self::Output {
191 Self::from_ternary(&(&self.to_ternary() & &rhs.to_ternary()))
192 }
193}
194
195impl BitOr for Tryte {
196 type Output = Tryte;
197 fn bitor(self, rhs: Self) -> Self::Output {
198 Self::from_ternary(&(&self.to_ternary() | &rhs.to_ternary()))
199 }
200}
201
202impl BitXor for Tryte {
203 type Output = Tryte;
204 fn bitxor(self, rhs: Self) -> Self::Output {
205 Self::from_ternary(&(&self.to_ternary() ^ &rhs.to_ternary()))
206 }
207}
208
209impl Not for Tryte {
210 type Output = Tryte;
211 fn not(self) -> Self::Output {
212 -self
213 }
214}
215
216impl From<Ternary> for Tryte {
217 fn from(value: Ternary) -> Self {
218 Tryte::from_ternary(&value)
219 }
220}
221
222impl From<Tryte> for Ternary {
223 fn from(value: Tryte) -> Self {
224 value.to_ternary()
225 }
226}
227
228#[cfg(test)]
229#[test]
230pub fn test_tryte() {
231 let tryte = Tryte::from_i16(255);
232 assert_eq!(tryte.to_i16(), 255);
233 assert_eq!(tryte.to_string(), "+00++0");
234
235 let tryte = Tryte::from_i8(16);
236 assert_eq!(tryte.to_i16(), 16);
237 assert_eq!(tryte.to_string(), "00+--+");
238
239 assert_eq!(Tryte::MAX.to_string(), "++++++");
240 assert_eq!(Tryte::MAX.to_i16(), 364);
241 assert_eq!(Tryte::MIN.to_string(), "------");
242 assert_eq!(Tryte::MIN.to_i16(), -364);
243 assert_eq!(Tryte::ZERO.to_string(), "000000");
244 assert_eq!(Tryte::ZERO.to_i16(), 0);
245}