iota_conversion/
trinary.rs1use crate::Result;
2use iota_constants::{TRINARY_RADIX, TRITS_PER_BYTE, TRITS_PER_TRYTE};
3
4lazy_static! {
5 pub static ref BYTE_TO_TRITS_MAPPINGS: [[i8; TRITS_PER_BYTE]; 243] = {
7 let mut trits: [i8; TRITS_PER_BYTE] = [0; TRITS_PER_BYTE];
8 let mut tmp = [[0; TRITS_PER_BYTE]; 243];
9 tmp.iter_mut().for_each(|tmp_entry| {
10 tmp_entry.copy_from_slice(&trits[0..TRITS_PER_BYTE]);
11 increment(&mut trits, TRITS_PER_BYTE);
12 });
13 tmp
14 };
15 pub static ref TRYTE_TO_TRITS_MAPPINGS: [[i8; TRITS_PER_TRYTE]; 27] = {
17 let mut trits: [i8; TRITS_PER_BYTE] = [0; TRITS_PER_BYTE];
18 let mut tmp = [[0; TRITS_PER_TRYTE]; 27];
19 tmp.iter_mut().for_each(|tmp_entry| {
20 tmp_entry.copy_from_slice(&trits[0..TRITS_PER_TRYTE]);
21 increment(&mut trits, TRITS_PER_TRYTE);
22 });
23 tmp
24 };
25}
26
27pub trait Trinary {
29 fn trits(&self) -> Vec<Trit>;
31 fn trits_with_length(&self, length: usize) -> Vec<Trit>;
33 fn trytes(&self) -> Result<Trytes>;
35}
36
37pub type Trit = i8;
39pub type Trytes = String;
41
42impl Trinary for i64 {
43 fn trits(&self) -> Vec<Trit> {
44 let mut trits = Vec::new();
45 let mut abs = self.abs();
46 while abs > 0 {
47 let mut remainder = (abs % i64::from(TRINARY_RADIX as i8)) as i8;
48 abs /= i64::from(TRINARY_RADIX as i8);
49 if remainder > iota_constants::MAX_TRIT_VALUE {
50 remainder = iota_constants::MIN_TRIT_VALUE;
51 abs += 1;
52 }
53 trits.push(remainder);
54 }
55 if *self < 0 {
56 trits.iter_mut().for_each(|trit| *trit = -*trit);
57 }
58 trits
59 }
60
61 fn trits_with_length(&self, length: usize) -> Vec<Trit> {
62 trits_with_length(&self.trits(), length)
63 }
64
65 fn trytes(&self) -> Result<Trytes> {
66 self.trits().trytes()
67 }
68}
69
70impl Trinary for Vec<Trit> {
71 fn trits(&self) -> Vec<Trit> {
72 self.to_vec()
73 }
74 fn trits_with_length(&self, length: usize) -> Vec<Trit> {
75 trits_with_length(&self.trits(), length)
76 }
77 fn trytes(&self) -> Result<Trytes> {
78 trytes(self)
79 }
80}
81
82impl Trinary for &[Trit] {
83 fn trits(&self) -> Vec<Trit> {
84 self.to_vec()
85 }
86 fn trits_with_length(&self, length: usize) -> Vec<Trit> {
87 trits_with_length(&self.trits(), length)
88 }
89 fn trytes(&self) -> Result<Trytes> {
90 trytes(self)
91 }
92}
93
94impl Trinary for [Trit; 243] {
95 fn trits(&self) -> Vec<Trit> {
96 self.to_vec()
97 }
98 fn trits_with_length(&self, length: usize) -> Vec<Trit> {
99 trits_with_length(&self.trits(), length)
100 }
101 fn trytes(&self) -> Result<Trytes> {
102 ensure!(self.len() % 3 == 0, "Invalid trit length.");
103
104 self.chunks(iota_constants::TRITS_PER_TRYTE)
105 .map(trits_to_char)
106 .collect()
107 }
108}
109
110impl Trinary for Trytes {
111 fn trits(&self) -> Vec<Trit> {
112 self.chars().flat_map(char_to_trits).cloned().collect()
113 }
114 fn trits_with_length(&self, length: usize) -> Vec<Trit> {
115 trits_with_length(&self.trits(), length)
116 }
117 fn trytes(&self) -> Result<Trytes> {
118 Ok(self.clone())
119 }
120}
121
122impl Trinary for &str {
123 fn trits(&self) -> Vec<Trit> {
124 self.chars().flat_map(char_to_trits).cloned().collect()
125 }
126 fn trits_with_length(&self, length: usize) -> Vec<Trit> {
127 trits_with_length(&self.trits(), length)
128 }
129 fn trytes(&self) -> Result<Trytes> {
130 Ok((*self).to_string())
131 }
132}
133
134fn increment(trit_array: &mut [Trit], size: usize) {
136 for trit in trit_array.iter_mut().take(size) {
137 *trit += 1;
138 if *trit > iota_constants::MAX_TRIT_VALUE {
139 *trit = iota_constants::MIN_TRIT_VALUE;
140 } else {
141 break;
142 }
143 }
144}
145
146fn char_to_trits(tryte: char) -> &'static [Trit] {
147 match iota_constants::TRYTE_ALPHABET
148 .iter()
149 .position(|&x| x == tryte)
150 {
151 Some(p) => &TRYTE_TO_TRITS_MAPPINGS[p],
152 None => &TRYTE_TO_TRITS_MAPPINGS[0],
153 }
154}
155
156fn trits_to_char(trits: &[Trit]) -> Result<char> {
157 ensure!(
158 trits.len() <= iota_constants::TRITS_PER_TRYTE,
159 "Provided trit slice is too long: {:?}",
160 trits
161 );
162 Ok(
163 match TRYTE_TO_TRITS_MAPPINGS.iter().position(|&x| x == trits) {
164 Some(p) => iota_constants::TRYTE_ALPHABET[p],
165 None => '-',
166 },
167 )
168}
169
170pub fn trytes(trits: &[Trit]) -> Result<Trytes> {
172 ensure!(trits.len() % 3 == 0, "Invalid trit length.");
173
174 trits
175 .chunks(iota_constants::TRITS_PER_TRYTE)
176 .map(trits_to_char)
177 .collect()
178}
179
180fn trits_with_length(trits: &[Trit], length: usize) -> Vec<Trit> {
181 if trits.len() < length {
182 let mut result = vec![0; length];
183 result[..trits.len()].copy_from_slice(&trits);
184 result
185 } else {
186 trits[..length].to_vec()
187 }
188}