cli dollcode encoder and decoder
at main 141 lines 4.9 kB view raw
1use clap::{ArgGroup, Command, Id, arg, command, crate_authors}; 2use lib_porcelain::Dollcode; 3#[cfg(feature = "bigint")] 4use num::{BigUint, Num, traits::ToBytes}; 5use std::str::FromStr; 6 7fn main() { 8 let matches = command!() 9 .author(crate_authors!("\n")) 10 .arg(arg!(-v --verbose ... "provide more info")) 11 .subcommand_required(true) 12 .subcommand( 13 Command::new("encode") 14 .arg(arg!([input] "Input to encode to a dollcode").required(true)) 15 .arg(arg!(hex: -x --hex "Encode from hex")) 16 .arg(arg!(string: -s --string "Encode from a utf8 string")), 17 ) 18 .subcommand( 19 Command::new("decode") 20 .arg(arg!([dollcode] "Dollcode to decode").required(true)) 21 .arg(arg!(decimial: -d --decimial "Decode to decimial")) 22 .arg(arg!(hex: -x --hex "Decode to hexadecimal")) 23 .arg(arg!(string: -s --string "Decode to utf8 string")) 24 .group(ArgGroup::new("format").args(["decimial", "hex", "string"])), 25 ) 26 .get_matches(); 27 28 if let Some(ematches) = matches.subcommand_matches("encode") { 29 let input = ematches.get_one::<String>("input").unwrap(); 30 31 if ematches.get_flag("string") { 32 #[cfg(feature = "bigint")] 33 println!( 34 "{}", 35 BigUint::from_bytes_be(input.clone().as_bytes()).to_dollcode() 36 ); 37 #[cfg(not(feature = "bigint"))] 38 println!("{}", { 39 let mut buf = [0u8; 8]; 40 let len = 8.min(input.len()); 41 buf[..len].copy_from_slice(&input.as_bytes()[..len]); 42 u64::from_be_bytes(buf).to_dollcode() 43 }); 44 45 return; 46 } 47 48 if let Some(s) = input.strip_prefix("0x") { 49 #[cfg(feature = "bigint")] 50 println!( 51 "{}", 52 BigUint::from_str_radix(s, 16) 53 .expect("invalid hex") 54 .to_dollcode() 55 ); 56 #[cfg(not(feature = "bigint"))] 57 println!( 58 "{}", 59 u64::from_str_radix(s, 16) 60 .expect("invalid hex") 61 .to_dollcode() 62 ); 63 return; 64 } 65 66 if ematches.get_flag("hex") { 67 #[cfg(feature = "bigint")] 68 println!( 69 "{}", 70 BigUint::from_str_radix(input, 16) 71 .expect("invalid hex") 72 .to_dollcode() 73 ); 74 #[cfg(not(feature = "bigint"))] 75 println!( 76 "{}", 77 u64::from_str_radix(input, 16) 78 .expect("invalid hex") 79 .to_dollcode(), 80 ); 81 return; 82 } 83 84 #[cfg(feature = "bigint")] 85 println!( 86 "{}", 87 BigUint::from_str(input) 88 .expect("input must be declared as hex or be a decimial number") 89 .to_dollcode() 90 ); 91 #[cfg(not(feature = "bigint"))] 92 println!( 93 "{}", 94 input 95 .parse::<u64>() 96 .expect("input must be declared as hex or be a decimial number") 97 .to_dollcode() 98 ); 99 } 100 101 if let Some(dmatches) = matches.subcommand_matches("decode") { 102 let dollcode = dmatches.get_one::<String>("dollcode").unwrap(); 103 104 let err = "dollcodes may only contain '▖', '▘', or '▌'"; 105 106 #[cfg(feature = "bigint")] 107 let res = BigUint::from_dollcode(dollcode).expect(err); 108 #[cfg(not(feature = "bigint"))] 109 let res = u64::from_dollcode(dollcode).expect(err); 110 111 let res_bytes = res.clone().to_be_bytes(); 112 113 match dmatches.get_one("format").map(Id::as_ref) { 114 Some("decimial") => println!("{}", res), 115 Some("hex") => println!("{:X}", res), 116 Some("string") => println!( 117 "{}", 118 str::from_utf8(&res_bytes).expect("failed to encode res as utf8") 119 ), 120 None => println!( 121 "decimial: {}, hexadecimal: {:X}, string: {}", 122 res, 123 res, 124 match str::from_utf8(&res_bytes) { 125 Ok(v) => v.to_string(), 126 Err(e) => 127 if *matches 128 .get_one::<u8>("verbose") 129 .expect("error getting verbose level") 130 > 0 131 { 132 format!("invalid utf8: {:?}", e) 133 } else { 134 "invalid utf8".to_string() 135 }, 136 } 137 ), 138 Some(_) => unreachable!(), 139 } 140 } 141}