Skip to main content

vildrose_core/word/
conversion.rs

1use super::{Tribble, Tryte, Word27, Word54, WordError};
2use crate::trit::Trit;
3
4impl Tribble {
5    /// The minimum representable value for a tribble.
6    pub const MIN_INT: i8 = -(3_i8.pow(3) - 1) / 2;
7
8    /// The maximum representable value for a tribble.
9    pub const MAX_INT: i8 = (3_i8.pow(3) - 1) / 2;
10
11    /// Converts this tribble to its native integer representation.
12    #[must_use]
13    pub fn to_int(self) -> i8 {
14        let mut value = 0_i8;
15        let mut place = 1_i8;
16
17        for trit in self.0 {
18            value += trit.value() * place;
19            place *= 3;
20        }
21
22        value
23    }
24
25    /// Constructs a tribble from a native integer.
26    ///
27    /// # Errors
28    ///
29    /// Returns [`WordError::OutOfRange`] if `value` is outside
30    /// [`Tribble::MIN_INT`] through [`Tribble::MAX_INT`].
31    pub fn from_int(mut value: i8) -> Result<Self, WordError> {
32        if !(Self::MIN_INT..=Self::MAX_INT).contains(&value) {
33            return Err(WordError::OutOfRange);
34        }
35
36        let mut trits = [Trit::Z; Self::TRIT_COUNT];
37
38        for trit in &mut trits {
39            let remainder = value.rem_euclid(3);
40
41            *trit = match remainder {
42                0 => Trit::Z,
43                1 => Trit::P,
44                2 => {
45                    value += 1;
46                    Trit::N
47                }
48                _ => unreachable!("remainder modulo three is always 0, 1, or 2"),
49            };
50
51            value = value.div_euclid(3);
52        }
53
54        Ok(Self(trits))
55    }
56}
57
58impl From<Tribble> for i8 {
59    fn from(word: Tribble) -> Self {
60        word.to_int()
61    }
62}
63
64impl TryFrom<i8> for Tribble {
65    type Error = WordError;
66
67    fn try_from(value: i8) -> Result<Self, Self::Error> {
68        Self::from_int(value)
69    }
70}
71
72impl Tryte {
73    /// The minimum representable value for a tryte.
74    pub const MIN_INT: i16 = -(3_i16.pow(9) - 1) / 2;
75
76    /// The maximum representable value for a tryte.
77    pub const MAX_INT: i16 = (3_i16.pow(9) - 1) / 2;
78
79    /// Converts this tryte to its native integer representation.
80    #[must_use]
81    pub fn to_int(self) -> i16 {
82        let mut value = 0_i16;
83        let mut place = 1_i16;
84
85        for trit in self.0 {
86            value += i16::from(trit.value()) * place;
87            place *= 3;
88        }
89
90        value
91    }
92
93    /// Constructs a tryte from a native integer.
94    ///
95    /// # Errors
96    ///
97    /// Returns [`WordError::OutOfRange`] if `value` is outside
98    /// [`Tryte::MIN_INT`] through [`Tryte::MAX_INT`].
99    pub fn from_int(mut value: i16) -> Result<Self, WordError> {
100        if !(Self::MIN_INT..=Self::MAX_INT).contains(&value) {
101            return Err(WordError::OutOfRange);
102        }
103
104        let mut trits = [Trit::Z; Self::TRIT_COUNT];
105
106        for trit in &mut trits {
107            let remainder = value.rem_euclid(3);
108
109            *trit = match remainder {
110                0 => Trit::Z,
111                1 => Trit::P,
112                2 => {
113                    value += 1;
114                    Trit::N
115                }
116                _ => unreachable!("remainder modulo three is always 0, 1, or 2"),
117            };
118
119            value = value.div_euclid(3);
120        }
121
122        Ok(Self(trits))
123    }
124}
125
126impl From<Tryte> for i16 {
127    fn from(word: Tryte) -> Self {
128        word.to_int()
129    }
130}
131
132impl TryFrom<i16> for Tryte {
133    type Error = WordError;
134
135    fn try_from(value: i16) -> Result<Self, Self::Error> {
136        Self::from_int(value)
137    }
138}
139
140impl Word27 {
141    /// The minimum representable value for a 27-trit word.
142    pub const MIN_INT: i64 = -(3_i64.pow(27) - 1) / 2;
143
144    /// The maximum representable value for a 27-trit word.
145    pub const MAX_INT: i64 = (3_i64.pow(27) - 1) / 2;
146
147    /// Converts this 27-trit word to its native integer representation.
148    #[must_use]
149    pub fn to_int(self) -> i64 {
150        let mut value = 0_i64;
151        let mut place = 1_i64;
152
153        for trit in self.0 {
154            value += i64::from(trit.value()) * place;
155            place *= 3;
156        }
157
158        value
159    }
160
161    /// Constructs a 27-trit word from a native integer.
162    ///
163    /// # Errors
164    ///
165    /// Returns [`WordError::OutOfRange`] if `value` is outside
166    /// [`Word27::MIN_INT`] through [`Word27::MAX_INT`].
167    pub fn from_int(mut value: i64) -> Result<Self, WordError> {
168        if !(Self::MIN_INT..=Self::MAX_INT).contains(&value) {
169            return Err(WordError::OutOfRange);
170        }
171
172        let mut trits = [Trit::Z; Self::TRIT_COUNT];
173
174        for trit in &mut trits {
175            let remainder = value.rem_euclid(3);
176
177            *trit = match remainder {
178                0 => Trit::Z,
179                1 => Trit::P,
180                2 => {
181                    value += 1;
182                    Trit::N
183                }
184                _ => unreachable!("remainder modulo three is always 0, 1, or 2"),
185            };
186
187            value = value.div_euclid(3);
188        }
189
190        Ok(Self(trits))
191    }
192}
193
194impl From<Word27> for i64 {
195    fn from(word: Word27) -> Self {
196        word.to_int()
197    }
198}
199
200impl TryFrom<i64> for Word27 {
201    type Error = WordError;
202
203    fn try_from(value: i64) -> Result<Self, Self::Error> {
204        Self::from_int(value)
205    }
206}
207
208impl Word54 {
209    /// The minimum representable value for a 54-trit word.
210    pub const MIN_INT: i128 = -(3_i128.pow(54) - 1) / 2;
211
212    /// The maximum representable value for a 54-trit word.
213    pub const MAX_INT: i128 = (3_i128.pow(54) - 1) / 2;
214
215    /// Converts this 54-trit word to its native integer representation.
216    #[must_use]
217    pub fn to_int(self) -> i128 {
218        let mut value = 0_i128;
219        let mut place = 1_i128;
220
221        for trit in self.0 {
222            value += i128::from(trit.value()) * place;
223            place *= 3;
224        }
225
226        value
227    }
228
229    /// Constructs a 54-trit word from a native integer.
230    ///
231    /// # Errors
232    ///
233    /// Returns [`WordError::OutOfRange`] if `value` is outside
234    /// [`Word54::MIN_INT`] through [`Word54::MAX_INT`].
235    pub fn from_int(mut value: i128) -> Result<Self, WordError> {
236        if !(Self::MIN_INT..=Self::MAX_INT).contains(&value) {
237            return Err(WordError::OutOfRange);
238        }
239
240        let mut trits = [Trit::Z; Self::TRIT_COUNT];
241
242        for trit in &mut trits {
243            let remainder = value.rem_euclid(3);
244
245            *trit = match remainder {
246                0 => Trit::Z,
247                1 => Trit::P,
248                2 => {
249                    value += 1;
250                    Trit::N
251                }
252                _ => unreachable!("remainder modulo three is always 0, 1, or 2"),
253            };
254
255            value = value.div_euclid(3);
256        }
257
258        Ok(Self(trits))
259    }
260}
261
262impl From<Word54> for i128 {
263    fn from(word: Word54) -> Self {
264        word.to_int()
265    }
266}
267
268impl TryFrom<i128> for Word54 {
269    type Error = WordError;
270
271    fn try_from(value: i128) -> Result<Self, Self::Error> {
272        Self::from_int(value)
273    }
274}