cli dollcode encoder and decoder
at main 254 lines 8.6 kB view raw
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}