cli dollcode encoder and decoder

dollcode trait thing

0xda157 f9e68928 3717d902

+184 -84
+2 -2
Cargo.lock
··· 93 94 [[package]] 95 name = "lib-porcelain" 96 - version = "0.1.0" 97 98 [[package]] 99 name = "once_cell_polyfill" ··· 103 104 [[package]] 105 name = "porcelain" 106 - version = "0.2.1" 107 dependencies = [ 108 "clap", 109 "lib-porcelain",
··· 93 94 [[package]] 95 name = "lib-porcelain" 96 + version = "0.2.0" 97 98 [[package]] 99 name = "once_cell_polyfill" ··· 103 104 [[package]] 105 name = "porcelain" 106 + version = "0.2.2" 107 dependencies = [ 108 "clap", 109 "lib-porcelain",
+2 -2
Cargo.toml
··· 4 5 [package] 6 name = "porcelain" 7 - version = "0.2.1" 8 license = "MIT" 9 authors = ["0xda157 <da157@voidq.com>"] 10 description = "cli dollcode encoder and decoder" ··· 15 edition = "2024" 16 17 [dependencies] 18 - lib-porcelain = { path = "./lib-porcelain", version = "0.1.0" } 19 clap = { version = "4.5.51", features = ["cargo"] }
··· 4 5 [package] 6 name = "porcelain" 7 + version = "0.2.2" 8 license = "MIT" 9 authors = ["0xda157 <da157@voidq.com>"] 10 description = "cli dollcode encoder and decoder" ··· 15 edition = "2024" 16 17 [dependencies] 18 + lib-porcelain = { path = "./lib-porcelain", version = "0.2.0" } 19 clap = { version = "4.5.51", features = ["cargo"] }
+1 -3
lib-porcelain/Cargo.toml
··· 1 [package] 2 name = "lib-porcelain" 3 - version = "0.1.0" 4 license = "MIT" 5 authors = ["0xda157 <da157@voidq.com>"] 6 description = "dollcode encoder and decoder" 7 homepage = "https://codeberg.org/da157/porcelain" 8 repository = "https://codeberg.org/da157/porcelain" 9 edition = "2024" 10 - 11 - [dependencies]
··· 1 [package] 2 name = "lib-porcelain" 3 + version = "0.2.0" 4 license = "MIT" 5 authors = ["0xda157 <da157@voidq.com>"] 6 description = "dollcode encoder and decoder" 7 homepage = "https://codeberg.org/da157/porcelain" 8 repository = "https://codeberg.org/da157/porcelain" 9 edition = "2024"
+95
lib-porcelain/src/deprecated.rs
···
··· 1 + /// Decodes a `&str` containing a dollcode into a `u64`. 2 + /// Returns `None` if `input` contains invalid characters 3 + /// (everything except `'▖'`, `'▘'`, and `'▌'`). 4 + /// 5 + /// # Example 6 + /// 7 + /// ``` 8 + /// use lib_porcelain::dollcode_decode; 9 + /// 10 + /// assert_eq!(dollcode_decode(""), Some(0)); 11 + /// 12 + /// assert_eq!(dollcode_decode("▖▖▘▘▌▘▌▌▘▘▘▌▌"), Some(893271)); 13 + /// 14 + /// assert_eq!(dollcode_decode("invalid"), None); 15 + /// ``` 16 + #[deprecated(since = "0.2.0", note = "please use the `Dollcode` trait instead")] 17 + pub fn dollcode_decode(input: &str) -> Option<u64> { 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 + /// Takes a `u64` and encodes in to a `String` containing a dollcode made up of 34 + /// `'▖'`, `'▘'`, and `'▌'`. 35 + /// 36 + /// # Example 37 + /// 38 + /// ``` 39 + /// use lib_porcelain::dollcode_encode; 40 + /// 41 + /// assert_eq!(dollcode_encode(0), ""); 42 + /// 43 + /// assert_eq!(dollcode_encode(893271), "▖▖▘▘▌▘▌▌▘▘▘▌▌"); 44 + /// ``` 45 + #[deprecated(since = "0.2.0", note = "please use the `Dollcode` trait instead")] 46 + pub fn dollcode_encode(mut input: u64) -> String { 47 + let mut res = String::new(); 48 + 49 + while input > 0 { 50 + input -= 1; 51 + res.push(['▖', '▘', '▌'][(input % 3) as usize]); 52 + input /= 3; 53 + } 54 + 55 + res.chars().rev().collect::<String>() 56 + } 57 + 58 + #[cfg(test)] 59 + mod tests { 60 + use crate::{dollcode_decode, dollcode_encode}; 61 + 62 + #[test] 63 + fn test_encode() { 64 + assert_eq!(dollcode_encode(0), ""); 65 + assert_eq!(dollcode_encode(1), "▖"); 66 + assert_eq!(dollcode_encode(2), "▘"); 67 + assert_eq!(dollcode_encode(3), "▌"); 68 + assert_eq!(dollcode_encode(4), "▖▖"); 69 + assert_eq!(dollcode_encode(13), "▖▖▖"); 70 + assert_eq!(dollcode_encode(440729), "▖▌▌▌▌▖▖▖▘▌▘▘"); 71 + assert_eq!(dollcode_encode(893271), "▖▖▘▘▌▘▌▌▘▘▘▌▌"); 72 + assert_eq!( 73 + dollcode_encode(u64::MAX), 74 + "▖▖▖▖▘▘▖▘▌▘▘▖▘▘▖▖▘▌▌▖▖▌▌▌▖▌▖▖▌▖▌▌▖▌▌▘▖▖▘▖▌" 75 + ); 76 + } 77 + 78 + #[test] 79 + fn test_decode() { 80 + assert_eq!(dollcode_decode("invalid"), None); 81 + assert_eq!(dollcode_decode("▖▌▌▌▌▖▖▖▘invalid"), None); 82 + assert_eq!(dollcode_decode(""), Some(0)); 83 + assert_eq!(dollcode_decode("▖"), Some(1)); 84 + assert_eq!(dollcode_decode("▘"), Some(2)); 85 + assert_eq!(dollcode_decode("▌"), Some(3)); 86 + assert_eq!(dollcode_decode("▖▖"), Some(4)); 87 + assert_eq!(dollcode_decode("▖▖▖"), Some(13)); 88 + assert_eq!(dollcode_decode("▖▌▌▌▌▖▖▖▘▌▘▘"), Some(440729)); 89 + assert_eq!(dollcode_decode("▖▖▘▘▌▘▌▌▘▘▘▌▌"), Some(893271)); 90 + assert_eq!( 91 + dollcode_decode("▖▖▖▖▘▘▖▘▌▘▘▖▘▘▖▖▘▌▌▖▖▌▌▌▖▌▖▖▌▖▌▌▖▌▌▘▖▖▘▖▌"), 92 + Some(u64::MAX) 93 + ); 94 + } 95 + }
+71 -68
lib-porcelain/src/lib.rs
··· 1 - /// Decodes a `&str` containing a dollcode into a `u64`. 2 - /// Returns `None` if `input` contains invalid characters 3 - /// (everything except `'▖'`, `'▘'`, and `'▌'`). 4 - /// 5 - /// # Example 6 - /// 7 - /// ``` 8 - /// use lib_porcelain::dollcode_decode; 9 - /// 10 - /// assert_eq!(dollcode_decode(""), Some(0)); 11 - /// 12 - /// assert_eq!(dollcode_decode("▖▖▘▘▌▘▌▌▘▘▘▌▌"), Some(893271)); 13 - /// 14 - /// assert_eq!(dollcode_decode("invalid"), None); 15 - /// ``` 16 - pub fn dollcode_decode(input: &str) -> Option<u64> { 17 - let mut acc = 0; 18 19 - for char in input.chars() { 20 - acc = acc * 3 21 - + match char { 22 - '▖' => 1, 23 - '▘' => 2, 24 - '▌' => 3, 25 - _ => return None, 26 - } 27 - } 28 29 - Some(acc) 30 } 31 32 - /// Takes a `u64` and encodes in to a `String` containing a dollcode made up of 33 - /// `'▖'`, `'▘'`, and `'▌'`. 34 - /// 35 - /// # Example 36 - /// 37 - /// ``` 38 - /// use lib_porcelain::dollcode_encode; 39 - /// 40 - /// assert_eq!(dollcode_encode(0), ""); 41 - /// 42 - /// assert_eq!(dollcode_encode(893271), "▖▖▘▘▌▘▌▌▘▘▘▌▌"); 43 - /// ``` 44 - pub fn dollcode_encode(mut input: u64) -> String { 45 - let mut res = String::new(); 46 47 - while input > 0 { 48 - input -= 1; 49 - res.push(['▖', '▘', '▌'][(input % 3) as usize]); 50 - input /= 3; 51 } 52 53 - res.chars().rev().collect::<String>() 54 - } 55 56 #[cfg(test)] 57 mod tests { 58 - use crate::{dollcode_decode, dollcode_encode}; 59 60 #[test] 61 fn test_encode() { 62 - assert_eq!(dollcode_encode(0), ""); 63 - assert_eq!(dollcode_encode(1), "▖"); 64 - assert_eq!(dollcode_encode(2), "▘"); 65 - assert_eq!(dollcode_encode(3), "▌"); 66 - assert_eq!(dollcode_encode(4), "▖▖"); 67 - assert_eq!(dollcode_encode(13), "▖▖▖"); 68 - assert_eq!(dollcode_encode(440729), "▖▌▌▌▌▖▖▖▘▌▘▘"); 69 - assert_eq!(dollcode_encode(893271), "▖▖▘▘▌▘▌▌▘▘▘▌▌"); 70 assert_eq!( 71 - dollcode_encode(u64::MAX), 72 "▖▖▖▖▘▘▖▘▌▘▘▖▘▘▖▖▘▌▌▖▖▌▌▌▖▌▖▖▌▖▌▌▖▌▌▘▖▖▘▖▌" 73 ); 74 } 75 76 #[test] 77 fn test_decode() { 78 - assert_eq!(dollcode_decode("invalid"), None); 79 - assert_eq!(dollcode_decode("▖▌▌▌▌▖▖▖▘invalid"), None); 80 - assert_eq!(dollcode_decode(""), Some(0)); 81 - assert_eq!(dollcode_decode("▖"), Some(1)); 82 - assert_eq!(dollcode_decode("▘"), Some(2)); 83 - assert_eq!(dollcode_decode("▌"), Some(3)); 84 - assert_eq!(dollcode_decode("▖▖"), Some(4)); 85 - assert_eq!(dollcode_decode("▖▖▖"), Some(13)); 86 - assert_eq!(dollcode_decode("▖▌▌▌▌▖▖▖▘▌▘▘"), Some(440729)); 87 - assert_eq!(dollcode_decode("▖▖▘▘▌▘▌▌▘▘▘▌▌"), Some(893271)); 88 assert_eq!( 89 - dollcode_decode("▖▖▖▖▘▘▖▘▌▘▘▖▘▘▖▖▘▌▌▖▖▌▌▌▖▌▖▖▌▖▌▌▖▌▌▘▖▖▘▖▌"), 90 Some(u64::MAX) 91 ); 92 }
··· 1 + mod deprecated; 2 3 + pub use deprecated::{dollcode_decode, dollcode_encode}; 4 5 + pub trait Dollcode { 6 + /// Decodes a `&str` containing a dollcode into a `Self`. 7 + /// Returns `None` if `dollcode` contains invalid characters 8 + /// (everything except `'▖'`, `'▘'`, and `'▌'`). 9 + fn from_dollcode(dollcode: &str) -> Option<Self> 10 + where 11 + Self: Sized; 12 + 13 + /// Takes a `u64` and encodes in to a `String` containing a dollcode made up 14 + /// of `'▖'`, `'▘'`, and `'▌'`. 15 + fn to_dollcode(self) -> String; 16 } 17 18 + macro_rules! impl_std_Dollcode { 19 + (for $($t:ty),+) => { 20 + $(impl Dollcode for $t { 21 + fn from_dollcode(input: &str) -> Option<Self> { 22 + let mut acc = 0; 23 + 24 + for char in input.chars() { 25 + acc = acc * 3 26 + + match char { 27 + '▖' => 1, 28 + '▘' => 2, 29 + '▌' => 3, 30 + _ => return None, 31 + } 32 + } 33 + 34 + Some(acc) 35 + } 36 + 37 + fn to_dollcode(mut self) -> String { 38 + let mut res = String::new(); 39 + 40 + while self > 0 { 41 + self -= 1; 42 + res.push(['▖', '▘', '▌'][(self % 3) as usize]); 43 + self /= 3; 44 + } 45 46 + res.chars().rev().collect::<String>() 47 + } 48 + })* 49 } 50 + } 51 52 + impl_std_Dollcode!(for u8); 53 + impl_std_Dollcode!(for u16); 54 + impl_std_Dollcode!(for u32); 55 + impl_std_Dollcode!(for u64); 56 + impl_std_Dollcode!(for u128); 57 + impl_std_Dollcode!(for usize); 58 59 #[cfg(test)] 60 mod tests { 61 + use crate::Dollcode; 62 63 #[test] 64 fn test_encode() { 65 + assert_eq!(0_u32.to_dollcode(), ""); 66 + assert_eq!(1_u32.to_dollcode(), "▖"); 67 + assert_eq!(2_u32.to_dollcode(), "▘"); 68 + assert_eq!(3_u32.to_dollcode(), "▌"); 69 + assert_eq!(4_u32.to_dollcode(), "▖▖"); 70 + assert_eq!(13_u32.to_dollcode(), "▖▖▖"); 71 + assert_eq!(440729_u32.to_dollcode(), "▖▌▌▌▌▖▖▖▘▌▘▘"); 72 + assert_eq!(893271_u32.to_dollcode(), "▖▖▘▘▌▘▌▌▘▘▘▌▌"); 73 assert_eq!( 74 + u64::MAX.to_dollcode(), 75 "▖▖▖▖▘▘▖▘▌▘▘▖▘▘▖▖▘▌▌▖▖▌▌▌▖▌▖▖▌▖▌▌▖▌▌▘▖▖▘▖▌" 76 ); 77 } 78 79 #[test] 80 fn test_decode() { 81 + assert_eq!(u32::from_dollcode("invalid"), None); 82 + assert_eq!(u32::from_dollcode("▖▌▌▌▌▖▖▖▘invalid"), None); 83 + assert_eq!(u32::from_dollcode(""), Some(0)); 84 + assert_eq!(u32::from_dollcode("▖"), Some(1)); 85 + assert_eq!(u32::from_dollcode("▘"), Some(2)); 86 + assert_eq!(u32::from_dollcode("▌"), Some(3)); 87 + assert_eq!(u32::from_dollcode("▖▖"), Some(4)); 88 + assert_eq!(u32::from_dollcode("▖▖▖"), Some(13)); 89 + assert_eq!(u32::from_dollcode("▖▌▌▌▌▖▖▖▘▌▘▘"), Some(440729)); 90 + assert_eq!(u32::from_dollcode("▖▖▘▘▌▘▌▌▘▘▘▌▌"), Some(893271)); 91 assert_eq!( 92 + u64::from_dollcode("▖▖▖▖▘▘▖▘▌▘▘▖▘▘▖▖▘▌▌▖▖▌▌▌▖▌▖▖▌▖▌▌▖▌▌▘▖▖▘▖▌"), 93 Some(u64::MAX) 94 ); 95 }
+13 -9
src/main.rs
··· 1 use clap::{ArgGroup, Command, Id, arg, command, crate_authors}; 2 - use lib_porcelain::{dollcode_decode, dollcode_encode}; 3 4 fn main() { 5 let matches = command!() ··· 25 if let Some(s) = input.strip_prefix("0x") { 26 println!( 27 "{}", 28 - dollcode_encode(u64::from_str_radix(s, 16).expect("invalid hex")) 29 ); 30 return; 31 } ··· 33 if ematches.get_flag("hex") { 34 println!( 35 "{}", 36 - dollcode_encode(u64::from_str_radix(input, 16).expect("invalid hex")) 37 ); 38 return; 39 } 40 41 println!( 42 "{}", 43 - dollcode_encode( 44 - input 45 - .parse::<u64>() 46 - .expect("input must be declared as hex or be a decimial number") 47 - ) 48 ); 49 } 50 51 if let Some(dmatches) = matches.subcommand_matches("decode") { 52 let dollcode = dmatches.get_one::<String>("dollcode").unwrap(); 53 54 - let res = dollcode_decode(dollcode).expect("dollcodes may only contain '▖', '▘', or '▌'"); 55 56 match dmatches.get_one("format").map(Id::as_ref) { 57 Some("decimial") => println!("{}", res),
··· 1 use clap::{ArgGroup, Command, Id, arg, command, crate_authors}; 2 + use lib_porcelain::Dollcode; 3 4 fn main() { 5 let matches = command!() ··· 25 if let Some(s) = input.strip_prefix("0x") { 26 println!( 27 "{}", 28 + u64::from_str_radix(s, 16) 29 + .expect("invalid hex") 30 + .to_dollcode() 31 ); 32 return; 33 } ··· 35 if ematches.get_flag("hex") { 36 println!( 37 "{}", 38 + u64::from_str_radix(input, 16) 39 + .expect("invalid hex") 40 + .to_dollcode() 41 ); 42 return; 43 } 44 45 println!( 46 "{}", 47 + input 48 + .parse::<u64>() 49 + .expect("input must be declared as hex or be a decimial number") 50 + .to_dollcode() 51 ); 52 } 53 54 if let Some(dmatches) = matches.subcommand_matches("decode") { 55 let dollcode = dmatches.get_one::<String>("dollcode").unwrap(); 56 57 + let res = 58 + u64::from_dollcode(dollcode).expect("dollcodes may only contain '▖', '▘', or '▌'"); 59 60 match dmatches.get_one("format").map(Id::as_ref) { 61 Some("decimial") => println!("{}", res),