balanced_ternary/
tryte.rs1use crate::{
13 Digit,
14 Digit::{Neg, Pos, Zero},
15 Ternary,
16};
17use alloc::string::{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::new([Pos; 6]);
34 pub const MIN: Self = Self::new([Neg; 6]);
36 pub const ZERO: Self = Self::new([Zero; 6]);
38
39 pub const fn new(raw: [Digit; 6]) -> Self {
59 Self { raw }
60 }
61
62 pub fn to_ternary(&self) -> Ternary {
68 Ternary::new(self.raw.to_vec())
69 }
70
71 pub const fn to_digit_slice(&self) -> &[Digit] {
80 &self.raw
81 }
82
83 pub fn from_ternary(v: &Ternary) -> Self {
93 if v.log() > 6 {
94 panic!("Cannot convert a Ternary with more than 6 digits to a Tryte.");
95 }
96 let mut digits = [Zero; 6];
97 for (i, d) in v.digits.iter().rev().enumerate() {
98 digits[5 - i] = *d;
99 }
100 Self { raw: digits }
101 }
102
103 pub fn to_i16(&self) -> i16 {
109 self.to_ternary().to_dec() as i16
110 }
111
112 pub fn from_i8(v: i8) -> Self {
122 Self::from_ternary(&Ternary::from_dec(v as i64))
123 }
124
125 pub fn from_i16(v: i16) -> Self {
135 Self::from_ternary(&Ternary::from_dec(v as i64))
136 }
137
138 pub fn digit(&self, index: usize) -> Digit {
152 if index > 5 {
153 panic!(
154 "Cannot access a digit at index {}. Tryte has only 6 digits.",
155 index
156 );
157 }
158 *self.raw.iter().rev().nth(index).unwrap()
159 }
160}
161
162impl Display for Tryte {
163 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
168 write!(f, "{:06}", self.to_ternary().to_string())
169 }
170}
171
172impl StdNeg for Tryte {
173 type Output = Tryte;
174 fn neg(self) -> Self::Output {
175 Self::from_ternary(&-&self.to_ternary())
176 }
177}
178
179impl Add for Tryte {
180 type Output = Tryte;
181
182 fn add(self, rhs: Self) -> Self::Output {
183 Self::from_ternary(&(&self.to_ternary() + &rhs.to_ternary()))
184 }
185}
186
187impl Sub for Tryte {
188 type Output = Tryte;
189
190 fn sub(self, rhs: Self) -> Self::Output {
191 Self::from_ternary(&(&self.to_ternary() - &rhs.to_ternary()))
192 }
193}
194
195impl Mul for Tryte {
196 type Output = Tryte;
197
198 fn mul(self, rhs: Self) -> Self::Output {
199 Self::from_ternary(&(&self.to_ternary() * &rhs.to_ternary()))
200 }
201}
202
203impl Div for Tryte {
204 type Output = Tryte;
205
206 fn div(self, rhs: Self) -> Self::Output {
207 Self::from_ternary(&(&self.to_ternary() / &rhs.to_ternary()))
208 }
209}
210
211impl BitAnd for Tryte {
212 type Output = Tryte;
213 fn bitand(self, rhs: Self) -> Self::Output {
214 Self::from_ternary(&(&self.to_ternary() & &rhs.to_ternary()))
215 }
216}
217
218impl BitOr for Tryte {
219 type Output = Tryte;
220 fn bitor(self, rhs: Self) -> Self::Output {
221 Self::from_ternary(&(&self.to_ternary() | &rhs.to_ternary()))
222 }
223}
224
225impl BitXor for Tryte {
226 type Output = Tryte;
227 fn bitxor(self, rhs: Self) -> Self::Output {
228 Self::from_ternary(&(&self.to_ternary() ^ &rhs.to_ternary()))
229 }
230}
231
232impl Not for Tryte {
233 type Output = Tryte;
234 fn not(self) -> Self::Output {
235 -self
236 }
237}
238
239impl From<Ternary> for Tryte {
240 fn from(value: Ternary) -> Self {
241 Tryte::from_ternary(&value)
242 }
243}
244
245impl From<Tryte> for Ternary {
246 fn from(value: Tryte) -> Self {
247 value.to_ternary()
248 }
249}
250
251impl From<&str> for Tryte {
252 fn from(value: &str) -> Self {
253 Self::from_ternary(&Ternary::parse(value))
254 }
255}
256
257impl From<String> for Tryte {
258 fn from(value: String) -> Self {
259 Self::from(value.as_str())
260 }
261}
262
263impl From<Tryte> for String {
264 fn from(value: Tryte) -> Self {
265 value.to_string()
266 }
267}
268
269impl From<i16> for Tryte {
270 fn from(value: i16) -> Self {
271 Self::from_i16(value)
272 }
273}
274
275impl From<Tryte> for i16 {
276 fn from(value: Tryte) -> Self {
277 value.to_i16()
278 }
279}
280
281#[cfg(test)]
282#[test]
283pub fn test_tryte() {
284 let tryte = Tryte::from_i16(255);
285 assert_eq!(tryte.to_i16(), 255);
286 assert_eq!(tryte.to_string(), "+00++0");
287
288 let tryte = Tryte::from_i8(16);
289 assert_eq!(tryte.to_i16(), 16);
290 assert_eq!(tryte.to_string(), "00+--+");
291
292 assert_eq!(Tryte::MAX.to_string(), "++++++");
293 assert_eq!(Tryte::MAX.to_i16(), 364);
294 assert_eq!(Tryte::MIN.to_string(), "------");
295 assert_eq!(Tryte::MIN.to_i16(), -364);
296 assert_eq!(Tryte::ZERO.to_string(), "000000");
297 assert_eq!(Tryte::ZERO.to_i16(), 0);
298}