cli dollcode encoder and decoder
1pub trait Dollcode {
2 /// Decodes a `&str` containing a dollcode into a `Self`.
3 /// Returns `None` if `dollcode` contains invalid characters
4 /// (everything except `'▖'`, `'▘'`, and `'▌'`).
5 fn from_dollcode(dollcode: &str) -> Option<Self>
6 where
7 Self: Sized;
8
9 /// Takes a `Self` and encodes it to a `String` containing a dollcode made up
10 /// of `'▖'`, `'▘'`, and `'▌'`.
11 fn to_dollcode(self) -> String;
12}
13
14macro_rules! impl_std_Dollcode {
15 ($($t:ty),+ $(,)?) => {
16 $(impl Dollcode for $t {
17 fn from_dollcode(input: &str) -> Option<Self> {
18 let mut acc = 0;
19
20 for char in input.chars() {
21 acc = acc * 3
22 + match char {
23 '▖' => 1,
24 '▘' => 2,
25 '▌' => 3,
26 _ => return None,
27 }
28 }
29
30 Some(acc)
31 }
32
33 fn to_dollcode(mut self) -> String {
34 let mut res = String::new();
35
36 while self > 0 {
37 self -= 1;
38 res.push(['▖', '▘', '▌'][(self % 3) as usize]);
39 self /= 3;
40 }
41
42 res.chars().rev().collect::<String>()
43 }
44 })*
45 }
46}
47
48impl_std_Dollcode!(u8, u16, u32, u64, u128, usize);
49
50#[cfg(feature = "num")]
51use num::{BigUint, ToPrimitive};
52
53#[cfg(feature = "num")]
54impl Dollcode for BigUint {
55 fn from_dollcode(input: &str) -> Option<Self> {
56 let mut acc = BigUint::ZERO;
57
58 for char in input.chars() {
59 acc = acc * 3_u32
60 + match char {
61 '▖' => 1_u32,
62 '▘' => 2_u32,
63 '▌' => 3_u32,
64 _ => return None,
65 }
66 }
67
68 Some(acc)
69 }
70
71 fn to_dollcode(mut self) -> String {
72 let mut res = String::new();
73
74 while self > BigUint::ZERO {
75 self -= 1_u32;
76 res.push(
77 ['▖', '▘', '▌'][(self.clone() % 3_u32)
78 .to_usize()
79 .expect("failed to convert value to usize")],
80 );
81 self /= 3_u32;
82 }
83
84 res.chars().rev().collect::<String>()
85 }
86}
87
88#[cfg(test)]
89mod trait_tests {
90 use crate::Dollcode;
91
92 #[test]
93 fn std_encode() {
94 assert_eq!(0_u32.to_dollcode(), "");
95 assert_eq!(1_u32.to_dollcode(), "▖");
96 assert_eq!(2_u32.to_dollcode(), "▘");
97 assert_eq!(3_u32.to_dollcode(), "▌");
98 assert_eq!(4_u32.to_dollcode(), "▖▖");
99 assert_eq!(13_u32.to_dollcode(), "▖▖▖");
100 assert_eq!(440729_u32.to_dollcode(), "▖▌▌▌▌▖▖▖▘▌▘▘");
101 assert_eq!(893271_u32.to_dollcode(), "▖▖▘▘▌▘▌▌▘▘▘▌▌");
102 assert_eq!(
103 u64::MAX.to_dollcode(),
104 "▖▖▖▖▘▘▖▘▌▘▘▖▘▘▖▖▘▌▌▖▖▌▌▌▖▌▖▖▌▖▌▌▖▌▌▘▖▖▘▖▌"
105 );
106 }
107
108 #[test]
109 fn std_decode() {
110 assert_eq!(u32::from_dollcode("invalid"), None);
111 assert_eq!(u32::from_dollcode("▖▌▌▌▌▖▖▖▘invalid"), None);
112 assert_eq!(u32::from_dollcode(""), Some(0));
113 assert_eq!(u32::from_dollcode("▖"), Some(1));
114 assert_eq!(u32::from_dollcode("▘"), Some(2));
115 assert_eq!(u32::from_dollcode("▌"), Some(3));
116 assert_eq!(u32::from_dollcode("▖▖"), Some(4));
117 assert_eq!(u32::from_dollcode("▖▖▖"), Some(13));
118 assert_eq!(u32::from_dollcode("▖▌▌▌▌▖▖▖▘▌▘▘"), Some(440729));
119 assert_eq!(u32::from_dollcode("▖▖▘▘▌▘▌▌▘▘▘▌▌"), Some(893271));
120 assert_eq!(
121 u64::from_dollcode("▖▖▖▖▘▘▖▘▌▘▘▖▘▘▖▖▘▌▌▖▖▌▌▌▖▌▖▖▌▖▌▌▖▌▌▘▖▖▘▖▌"),
122 Some(u64::MAX)
123 );
124 }
125
126 #[test]
127 #[cfg(feature = "num")]
128 fn big_int_encode() {
129 use num::BigUint;
130
131 assert_eq!(BigUint::ZERO.to_dollcode(), "");
132 assert_eq!(
133 BigUint::from_slice(&[893271]).to_dollcode(),
134 "▖▖▘▘▌▘▌▌▘▘▘▌▌"
135 );
136 assert_eq!(
137 BigUint::from_slice(&[u32::MAX, u32::MAX, u32::MAX]).to_dollcode(),
138 "▖▘▖▖▌▌▘▌▌▌▘▌▘▖▌▘▌▘▌▌▖▌▖▘▘▖▘▖▘▖▘▌▌▖▌▖▖▌▖▖▖▘▖▌▖▖▘▌▌▘▌▘▘▘▘▖▘▌▌▘▌"
139 );
140 }
141
142 #[test]
143 #[cfg(feature = "num")]
144 fn big_int_decode() {
145 use num::BigUint;
146
147 assert_eq!(BigUint::from_dollcode("invalid"), None);
148 assert_eq!(BigUint::from_dollcode(""), Some(BigUint::ZERO));
149 assert_eq!(
150 BigUint::from_dollcode("▖▖▘▘▌▘▌▌▘▘▘▌▌"),
151 Some(BigUint::from_slice(&[893271]))
152 );
153 assert_eq!(
154 BigUint::from_dollcode("▖▘▖▖▌▌▘▌▌▌▘▌▘▖▌▘▌▘▌▌▖▌▖▘▘▖▘▖▘▖▘▌▌▖▌▖▖▌▖▖▖▘▖▌▖▖▘▌▌▘▌▘▘▘▘▖▘▌▌▘▌"),
155 Some(BigUint::from_slice(&[u32::MAX, u32::MAX, u32::MAX]))
156 );
157 }
158}
159
160/// Decodes a `&str` containing a dollcode into a `u64`.
161/// Returns `None` if `input` contains invalid characters
162/// (everything except `'▖'`, `'▘'`, and `'▌'`).
163///
164/// # Example
165///
166/// ```
167/// use lib_porcelain::dollcode_decode;
168///
169/// assert_eq!(dollcode_decode(""), Some(0));
170///
171/// assert_eq!(dollcode_decode("▖▖▘▘▌▘▌▌▘▘▘▌▌"), Some(893271));
172///
173/// assert_eq!(dollcode_decode("invalid"), None);
174/// ```
175#[deprecated(since = "0.2.0", note = "please use the `Dollcode` trait instead")]
176pub fn dollcode_decode(input: &str) -> Option<u64> {
177 let mut acc = 0;
178
179 for char in input.chars() {
180 acc = acc * 3
181 + match char {
182 '▖' => 1,
183 '▘' => 2,
184 '▌' => 3,
185 _ => return None,
186 }
187 }
188
189 Some(acc)
190}
191
192/// Takes a `u64` and encodes in to a `String` containing a dollcode made up of
193/// `'▖'`, `'▘'`, and `'▌'`.
194///
195/// # Example
196///
197/// ```
198/// use lib_porcelain::dollcode_encode;
199///
200/// assert_eq!(dollcode_encode(0), "");
201///
202/// assert_eq!(dollcode_encode(893271), "▖▖▘▘▌▘▌▌▘▘▘▌▌");
203/// ```
204#[deprecated(since = "0.2.0", note = "please use the `Dollcode` trait instead")]
205pub fn dollcode_encode(mut input: u64) -> String {
206 let mut res = String::new();
207
208 while input > 0 {
209 input -= 1;
210 res.push(['▖', '▘', '▌'][(input % 3) as usize]);
211 input /= 3;
212 }
213
214 res.chars().rev().collect::<String>()
215}
216
217#[cfg(test)]
218mod fn_tests {
219 use crate::{dollcode_decode, dollcode_encode};
220
221 #[test]
222 fn test_encode() {
223 assert_eq!(dollcode_encode(0), "");
224 assert_eq!(dollcode_encode(1), "▖");
225 assert_eq!(dollcode_encode(2), "▘");
226 assert_eq!(dollcode_encode(3), "▌");
227 assert_eq!(dollcode_encode(4), "▖▖");
228 assert_eq!(dollcode_encode(13), "▖▖▖");
229 assert_eq!(dollcode_encode(440729), "▖▌▌▌▌▖▖▖▘▌▘▘");
230 assert_eq!(dollcode_encode(893271), "▖▖▘▘▌▘▌▌▘▘▘▌▌");
231 assert_eq!(
232 dollcode_encode(u64::MAX),
233 "▖▖▖▖▘▘▖▘▌▘▘▖▘▘▖▖▘▌▌▖▖▌▌▌▖▌▖▖▌▖▌▌▖▌▌▘▖▖▘▖▌"
234 );
235 }
236
237 #[test]
238 fn test_decode() {
239 assert_eq!(dollcode_decode("invalid"), None);
240 assert_eq!(dollcode_decode("▖▌▌▌▌▖▖▖▘invalid"), None);
241 assert_eq!(dollcode_decode(""), Some(0));
242 assert_eq!(dollcode_decode("▖"), Some(1));
243 assert_eq!(dollcode_decode("▘"), Some(2));
244 assert_eq!(dollcode_decode("▌"), Some(3));
245 assert_eq!(dollcode_decode("▖▖"), Some(4));
246 assert_eq!(dollcode_decode("▖▖▖"), Some(13));
247 assert_eq!(dollcode_decode("▖▌▌▌▌▖▖▖▘▌▘▘"), Some(440729));
248 assert_eq!(dollcode_decode("▖▖▘▘▌▘▌▌▘▘▘▌▌"), Some(893271));
249 assert_eq!(
250 dollcode_decode("▖▖▖▖▘▘▖▘▌▘▘▖▘▘▖▖▘▌▌▖▖▌▌▌▖▌▖▖▌▖▌▌▖▌▌▘▖▖▘▖▌"),
251 Some(u64::MAX)
252 );
253 }
254}