bee_ternary/
tryte.rs

1// Copyright 2020-2021 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4extern crate alloc;
5
6use alloc::vec::Vec;
7use core::{
8    fmt,
9    ops::{Deref, DerefMut},
10    str::FromStr,
11};
12
13use crate::{Btrit, Error, Trits, T3B1};
14
15/// A ternary tryte. Equivalent to 3 trits.
16#[derive(Copy, Clone, Eq, Hash, PartialEq)]
17#[repr(i8)]
18#[allow(missing_docs)]
19pub enum Tryte {
20    N = -13,
21    O = -12,
22    P = -11,
23    Q = -10,
24    R = -9,
25    S = -8,
26    T = -7,
27    U = -6,
28    V = -5,
29    W = -4,
30    X = -3,
31    Y = -2,
32    Z = -1,
33    Nine = 0,
34    A = 1,
35    B = 2,
36    C = 3,
37    D = 4,
38    E = 5,
39    F = 6,
40    G = 7,
41    H = 8,
42    I = 9,
43    J = 10,
44    K = 11,
45    L = 12,
46    M = 13,
47}
48
49impl Tryte {
50    /// The minimum value that this [`Tryte`] can hold.
51    pub const MIN_VALUE: Self = Tryte::N;
52
53    /// The maximum value that this [`Tryte`] can hold.
54    pub const MAX_VALUE: Self = Tryte::M;
55
56    /// Turn an array of three [`Btrit`]s into a [`Tryte`].
57    pub fn from_trits(trits: [Btrit; 3]) -> Self {
58        let x = i8::from(trits[0]) + i8::from(trits[1]) * 3 + i8::from(trits[2]) * 9;
59        Tryte::try_from(x).unwrap()
60    }
61
62    /// Interpret this tryte as a [`T3B1`] trit slice with exactly 3 elements.
63    pub fn as_trits(&self) -> &Trits<T3B1> {
64        unsafe { &*(T3B1::make(self as *const _ as *const _, 0, 3) as *const _) }
65    }
66
67    /// Interpret this tryte as a mutable [`T3B1`] trit slice with exactly 3 elements.
68    pub fn as_trits_mut(&mut self) -> &mut Trits<T3B1> {
69        unsafe { &mut *(T3B1::make(self as *const _ as *const _, 0, 3) as *mut _) }
70    }
71}
72
73impl From<Tryte> for char {
74    fn from(tryte: Tryte) -> char {
75        match tryte as i8 {
76            0 => '9',
77            -13..=-1 => (((tryte as i8 + 13) as u8) + b'N') as char,
78            1..=13 => (((tryte as i8 - 1) as u8) + b'A') as char,
79            x => unreachable!("Tried to decode Tryte with variant {}", x),
80        }
81    }
82}
83
84impl From<[Btrit; 3]> for Tryte {
85    fn from(trits: [Btrit; 3]) -> Self {
86        Self::from_trits(trits)
87    }
88}
89
90impl fmt::Debug for Tryte {
91    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
92        write!(f, "{:?}", char::from(*self))
93    }
94}
95
96impl fmt::Display for Tryte {
97    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
98        write!(f, "{}", char::from(*self))
99    }
100}
101
102impl TryFrom<char> for Tryte {
103    type Error = Error;
104
105    fn try_from(c: char) -> Result<Self, Self::Error> {
106        match c {
107            '9' => Ok(Tryte::Nine),
108            'N'..='Z' => Ok(unsafe { core::mem::transmute((c as u8 - b'N') as i8 - 13) }),
109            'A'..='M' => Ok(unsafe { core::mem::transmute((c as u8 - b'A') as i8 + 1) }),
110            _ => Err(Error::InvalidRepr),
111        }
112    }
113}
114
115impl TryFrom<i8> for Tryte {
116    type Error = Error;
117
118    fn try_from(x: i8) -> Result<Self, Self::Error> {
119        match x {
120            -13..=13 => Ok(unsafe { core::mem::transmute(x) }),
121            _ => Err(Error::InvalidRepr),
122        }
123    }
124}
125
126/// A buffer of [`Tryte`]s.
127/// Analogous to [`Vec`].
128#[derive(Default)]
129pub struct TryteBuf {
130    inner: Vec<Tryte>,
131}
132
133impl TryteBuf {
134    /// Create a new empty buffer.
135    pub fn new() -> Self {
136        Self::default()
137    }
138
139    /// Create a new empty buffer with room for `cap` trytes.
140    pub fn with_capacity(cap: usize) -> Self {
141        Self {
142            inner: Vec::with_capacity(cap),
143        }
144    }
145
146    /// Attempt to parse a string into a tryte buffer.
147    pub fn try_from_str(s: &str) -> Result<Self, Error> {
148        s.chars().map(Tryte::try_from).collect()
149    }
150
151    /// Returns `true` if the buffer is empty.
152    pub fn is_empty(&self) -> bool {
153        self.len() == 0
154    }
155
156    /// Returns the number of trytes in the buffer.
157    pub fn len(&self) -> usize {
158        self.inner.len()
159    }
160
161    /// Push a new tryte to the end of the buffer.
162    pub fn push(&mut self, tryte: Tryte) {
163        self.inner.push(tryte);
164    }
165
166    /// Attempt to pop a tryte from the end of the buffer.
167    pub fn pop(&mut self) -> Option<Tryte> {
168        self.inner.pop()
169    }
170
171    /// Safely interpret this tryte buffer as a [`T3B1`] trit slice.
172    pub fn as_trits(&self) -> &Trits<T3B1> {
173        unsafe { &*(T3B1::make(self.as_ptr() as *const _, 0, self.len() * 3) as *const _) }
174    }
175
176    /// Safely interpret this tryte buffer as a mutable [`T3B1`] trit slice.
177    pub fn as_trits_mut(&mut self) -> &mut Trits<T3B1> {
178        unsafe { &mut *(T3B1::make(self.as_ptr() as *const _, 0, self.len() * 3) as *mut _) }
179    }
180}
181
182impl Deref for TryteBuf {
183    type Target = [Tryte];
184    fn deref(&self) -> &Self::Target {
185        &self.inner
186    }
187}
188
189impl DerefMut for TryteBuf {
190    fn deref_mut(&mut self) -> &mut Self::Target {
191        &mut self.inner
192    }
193}
194
195impl FromIterator<Tryte> for TryteBuf {
196    fn from_iter<I: IntoIterator<Item = Tryte>>(iter: I) -> Self {
197        let iter = iter.into_iter();
198        let mut this = Self::with_capacity(iter.size_hint().0);
199        for tryte in iter {
200            this.push(tryte);
201        }
202        this
203    }
204}
205
206impl<'a> From<&'a [Tryte]> for TryteBuf {
207    fn from(trytes: &'a [Tryte]) -> Self {
208        Self { inner: trytes.to_vec() }
209    }
210}
211
212impl FromStr for TryteBuf {
213    type Err = Error;
214
215    fn from_str(s: &str) -> Result<Self, Self::Err> {
216        Self::try_from_str(s)
217    }
218}
219
220impl fmt::Debug for TryteBuf {
221    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
222        write!(f, "{:?}", self.inner)
223    }
224}
225
226impl fmt::Display for TryteBuf {
227    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
228        for tryte in self.iter() {
229            write!(f, "{}", tryte)?;
230        }
231        Ok(())
232    }
233}