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)]
43pub struct Tryte<const SIZE: usize = 6> {
44 raw: [Digit; SIZE],
46}
47
48impl<const SIZE: usize> Tryte<SIZE> {
49 pub const MAX: Self = Self::new([Pos; SIZE]);
51 pub const MIN: Self = Self::new([Neg; SIZE]);
53 pub const ZERO: Self = Self::new([Zero; SIZE]);
55
56 pub const fn new(digits: [Digit; SIZE]) -> Self {
80 if SIZE > 40 {
81 panic!("Cannot construct a Tryte with more than 40 digits (~63.5 bits).")
82 }
83 Self { raw: digits }
84 }
85
86 pub fn to_ternary(&self) -> Ternary {
92 Ternary::new(self.raw.to_vec())
93 }
94
95 pub const fn to_digit_slice(&self) -> &[Digit] {
104 &self.raw
105 }
106
107 pub fn from_ternary(v: &Ternary) -> Self {
117 if v.log() > SIZE {
118 panic!(
119 "Cannot convert a Ternary with more than {} digits to a Tryte<{}>.",
120 SIZE, SIZE
121 );
122 }
123 let mut digits = [Zero; SIZE];
124 for (i, d) in v.digits.iter().rev().enumerate() {
125 digits[SIZE - 1 - i] = *d;
126 }
127 Self::new(digits)
128 }
129
130 pub fn to_i64(&self) -> i64 {
136 self.to_ternary().to_dec()
137 }
138
139 pub fn from_i64(v: i64) -> Self {
149 Self::from_ternary(&Ternary::from_dec(v))
150 }
151
152 pub fn digit(&self, index: usize) -> Digit {
166 if index > SIZE - 1 {
167 panic!(
168 "Cannot access a digit at index {}. Tryte<{}> has only {} digits.",
169 index, SIZE, SIZE
170 );
171 }
172 *self.raw.iter().rev().nth(index).unwrap()
173 }
174
175 pub fn each(&self, f: impl Fn(Digit) -> Digit) -> Self {
177 Self::from_ternary(&self.to_ternary().each(f))
178 }
179
180 pub fn each_with(&self, f: impl Fn(Digit, Digit) -> Digit, with: Digit) -> Self {
182 Self::from_ternary(&self.to_ternary().each_with(f, with))
183 }
184
185 pub fn each_zip(&self, f: impl Fn(Digit, Digit) -> Digit, other: Self) -> Self {
187 Self::from_ternary(&self.to_ternary().each_zip(f, other.to_ternary()))
188 }
189
190 pub fn each_zip_carry(
192 &self,
193 f: impl Fn(Digit, Digit, Digit) -> (Digit, Digit),
194 other: Self,
195 ) -> Self {
196 Self::from_ternary(&self.to_ternary().each_zip_carry(f, other.to_ternary()))
197 }
198}
199
200impl<const SIZE: usize> Display for Tryte<SIZE> {
201 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
206 write!(f, "{:01$}", self.to_ternary().to_string(), SIZE)
207 }
208}
209
210impl<const SIZE: usize> StdNeg for Tryte<SIZE> {
211 type Output = Tryte<SIZE>;
212 fn neg(self) -> Self::Output {
213 Self::from_ternary(&-&self.to_ternary())
214 }
215}
216
217impl<const SIZE: usize> Add for Tryte<SIZE> {
218 type Output = Tryte<SIZE>;
219
220 fn add(self, rhs: Self) -> Self::Output {
221 Self::from_ternary(&(&self.to_ternary() + &rhs.to_ternary()))
222 }
223}
224
225impl<const SIZE: usize> Sub for Tryte<SIZE> {
226 type Output = Tryte<SIZE>;
227
228 fn sub(self, rhs: Self) -> Self::Output {
229 Self::from_ternary(&(&self.to_ternary() - &rhs.to_ternary()))
230 }
231}
232
233impl<const SIZE: usize> Mul for Tryte<SIZE> {
234 type Output = Tryte<SIZE>;
235
236 fn mul(self, rhs: Self) -> Self::Output {
237 Self::from_ternary(&(&self.to_ternary() * &rhs.to_ternary()))
238 }
239}
240
241impl<const SIZE: usize> Div for Tryte<SIZE> {
242 type Output = Tryte<SIZE>;
243
244 fn div(self, rhs: Self) -> Self::Output {
245 Self::from_ternary(&(&self.to_ternary() / &rhs.to_ternary()))
246 }
247}
248
249impl<const SIZE: usize> BitAnd for Tryte<SIZE> {
250 type Output = Tryte<SIZE>;
251 fn bitand(self, rhs: Self) -> Self::Output {
252 Self::from_ternary(&(&self.to_ternary() & &rhs.to_ternary()))
253 }
254}
255
256impl<const SIZE: usize> BitOr for Tryte<SIZE> {
257 type Output = Tryte<SIZE>;
258 fn bitor(self, rhs: Self) -> Self::Output {
259 Self::from_ternary(&(&self.to_ternary() | &rhs.to_ternary()))
260 }
261}
262
263impl<const SIZE: usize> BitXor for Tryte<SIZE> {
264 type Output = Tryte<SIZE>;
265 fn bitxor(self, rhs: Self) -> Self::Output {
266 Self::from_ternary(&(&self.to_ternary() ^ &rhs.to_ternary()))
267 }
268}
269
270impl<const SIZE: usize> Not for Tryte<SIZE> {
271 type Output = Tryte<SIZE>;
272 fn not(self) -> Self::Output {
273 -self
274 }
275}
276
277impl<const SIZE: usize> From<Ternary> for Tryte<SIZE> {
278 fn from(value: Ternary) -> Self {
279 Tryte::from_ternary(&value)
280 }
281}
282
283impl<const SIZE: usize> From<Tryte<SIZE>> for Ternary {
284 fn from(value: Tryte<SIZE>) -> Self {
285 value.to_ternary()
286 }
287}
288
289impl<const SIZE: usize> From<&str> for Tryte<SIZE> {
290 fn from(value: &str) -> Self {
291 Self::from_ternary(&Ternary::parse(value))
292 }
293}
294
295impl<const SIZE: usize> From<String> for Tryte<SIZE> {
296 fn from(value: String) -> Self {
297 Self::from(value.as_str())
298 }
299}
300
301impl<const SIZE: usize> From<Tryte<SIZE>> for String {
302 fn from(value: Tryte<SIZE>) -> Self {
303 value.to_string()
304 }
305}
306
307impl<const SIZE: usize> From<i64> for Tryte<SIZE> {
308 fn from(value: i64) -> Self {
309 Self::from_i64(value)
310 }
311}
312
313impl<const SIZE: usize> From<Tryte<SIZE>> for i64 {
314 fn from(value: Tryte<SIZE>) -> Self {
315 value.to_i64()
316 }
317}
318
319#[cfg(test)]
320#[test]
321pub fn test_tryte() {
322 let tryte = Tryte::<6>::from_i64(255);
323 assert_eq!(tryte.to_i64(), 255);
324 assert_eq!(tryte.to_string(), "+00++0");
325
326 let tryte = Tryte::<6>::from_i64(16);
327 assert_eq!(tryte.to_i64(), 16);
328 assert_eq!(tryte.to_string(), "00+--+");
329
330 assert_eq!(Tryte::<6>::MAX.to_string(), "++++++");
331 assert_eq!(Tryte::<6>::MAX.to_i64(), 364);
332 assert_eq!(Tryte::<6>::MIN.to_string(), "------");
333 assert_eq!(Tryte::<6>::MIN.to_i64(), -364);
334 assert_eq!(Tryte::<6>::ZERO.to_string(), "000000");
335 assert_eq!(Tryte::<6>::ZERO.to_i64(), 0);
336}