generated from PlexSheep/rs-base
Compare commits
15 commits
32ecd3cd97
...
acdec5836e
Author | SHA1 | Date | |
---|---|---|---|
|
acdec5836e | ||
9700ae5b35 | |||
290b959b7e | |||
a88a03eab7 | |||
1f91710bda | |||
b681a6b04d | |||
fe01412467 | |||
|
cd7f7cc376 | ||
9bfc8504a4 | |||
47ae8e135b | |||
8b419048ef | |||
6251546a31 | |||
4f269fb509 | |||
cae701815e | |||
82c1bf8d8a |
3 changed files with 367 additions and 78 deletions
164
src/format.rs
164
src/format.rs
|
@ -1,8 +1,12 @@
|
|||
#![allow(dead_code)] // this is exported to lib.rs
|
||||
use clap::{ArgGroup, Parser};
|
||||
use clap_num::maybe_hex;
|
||||
use libpt::bintols::split;
|
||||
|
||||
pub type Num = u128;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
/// formats supported by numf
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub enum Format {
|
||||
Dec,
|
||||
Hex,
|
||||
|
@ -12,6 +16,150 @@ pub enum Format {
|
|||
Base32,
|
||||
}
|
||||
|
||||
/// Describes what the formatter should do
|
||||
///
|
||||
/// Use [Self::default] to get a basic variant or create a object yourself.
|
||||
///
|
||||
/// This struct can be parsed with [clap] derive.
|
||||
#[derive(Parser, Debug, Clone, PartialEq, Eq, Hash)]
|
||||
#[clap(author, version, about, long_about = None)]
|
||||
#[command(
|
||||
author,
|
||||
version,
|
||||
about,
|
||||
long_about,
|
||||
help_template = r#"{about-section}
|
||||
{usage-heading} {usage}
|
||||
{all-args}{tab}
|
||||
|
||||
{name}: {version}
|
||||
Author: {author-with-newline}
|
||||
"#
|
||||
)]
|
||||
#[clap(group(
|
||||
ArgGroup::new("format")
|
||||
.args(&["hex", "bin", "oct", "dec", "base64", "base32"]),
|
||||
))]
|
||||
pub struct FormatOptions {
|
||||
#[arg(short, long)]
|
||||
/// add a prefix (like "0x" for hex)
|
||||
prefix: bool,
|
||||
#[arg(short = 'P', long)]
|
||||
/// add a padding to make the number at least one byte long
|
||||
///
|
||||
/// For example, `0b1100` will be `0b00001100` with this.
|
||||
/// This does not apply to all formats, only hexadecimal and binary.
|
||||
padding: bool,
|
||||
#[arg(short = 'x', long, default_value_t = true)]
|
||||
/// format to hexadecimal
|
||||
hex: bool,
|
||||
#[arg(short, long)]
|
||||
/// format to binary
|
||||
bin: bool,
|
||||
#[arg(short, long)]
|
||||
/// format to decimal
|
||||
dec: bool,
|
||||
#[arg(short, long)]
|
||||
/// format to octal
|
||||
oct: bool,
|
||||
#[arg(short = 's', long)]
|
||||
/// format to base64
|
||||
base64: bool,
|
||||
#[arg(short = 'z', long)]
|
||||
/// format to base32
|
||||
base32: bool,
|
||||
#[clap(value_parser=maybe_hex::<Num>, required=true)]
|
||||
/// at least one number that should be formatted
|
||||
///
|
||||
/// supports either base 10 or base 16 inputs (with 0xaaaa)
|
||||
numbers: Vec<Num>,
|
||||
}
|
||||
|
||||
impl FormatOptions {
|
||||
/// get the format that the user has configured
|
||||
pub fn format(&self) -> Format {
|
||||
if self.oct {
|
||||
Format::Octal
|
||||
} else if self.bin {
|
||||
Format::Bin
|
||||
} else if self.dec {
|
||||
Format::Dec
|
||||
} else if self.base64 {
|
||||
Format::Base64
|
||||
} else if self.base32 {
|
||||
Format::Base32
|
||||
} else if self.hex {
|
||||
Format::Hex
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
/// set the format manually
|
||||
pub fn set_format(&mut self, format: Format) {
|
||||
self.bin = false;
|
||||
self.oct = false;
|
||||
self.dec = false;
|
||||
self.hex = false;
|
||||
self.base64 = false;
|
||||
self.base32 = false;
|
||||
match format {
|
||||
Format::Bin => self.bin = true,
|
||||
Format::Hex => self.hex = true,
|
||||
Format::Octal => self.oct = true,
|
||||
Format::Base64 => self.base64 = true,
|
||||
Format::Base32 => self.base32 = true,
|
||||
Format::Dec => self.dec = true,
|
||||
}
|
||||
}
|
||||
|
||||
/// get numbers
|
||||
pub fn numbers(&self) -> &[u128] {
|
||||
self.numbers.as_ref()
|
||||
}
|
||||
|
||||
/// set numbers manually
|
||||
pub fn set_numbers(&mut self, numbers: Vec<Num>) {
|
||||
self.numbers = numbers;
|
||||
}
|
||||
|
||||
/// set padding manually
|
||||
pub fn set_padding(&mut self, value: bool) {
|
||||
self.padding = value
|
||||
}
|
||||
|
||||
/// get padding
|
||||
pub fn padding(&self) -> bool {
|
||||
self.padding
|
||||
}
|
||||
|
||||
/// get prefix
|
||||
pub fn prefix(&self) -> bool {
|
||||
self.prefix
|
||||
}
|
||||
|
||||
/// set prefix manually
|
||||
pub fn set_prefix(&mut self, value: bool) {
|
||||
self.prefix = value;
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FormatOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
padding: false,
|
||||
prefix: false,
|
||||
oct: false,
|
||||
hex: true,
|
||||
bin: false,
|
||||
base32: false,
|
||||
base64: false,
|
||||
dec: false,
|
||||
numbers: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Format {
|
||||
pub fn prefix(&self) -> String {
|
||||
match self {
|
||||
|
@ -31,18 +179,28 @@ impl Format {
|
|||
}
|
||||
.to_string()
|
||||
}
|
||||
pub fn format(&self, num: Num, prefix: bool) -> String {
|
||||
pub fn format(&self, num: Num, options: &FormatOptions) -> String {
|
||||
let mut buf = String::new();
|
||||
if prefix {
|
||||
if options.prefix {
|
||||
buf += &self.prefix();
|
||||
}
|
||||
match self {
|
||||
Format::Hex => {
|
||||
if options.padding {
|
||||
let tmp = &format!("{num:X}");
|
||||
buf += &("0".repeat((2 - tmp.len() % 2) % 2) + tmp);
|
||||
} else {
|
||||
buf += &format!("{num:X}");
|
||||
}
|
||||
}
|
||||
Format::Bin => {
|
||||
if options.padding {
|
||||
let tmp = &format!("{num:b}");
|
||||
buf += &("0".repeat((8 - tmp.len() % 8) % 8) + tmp);
|
||||
} else {
|
||||
buf += &format!("{num:b}");
|
||||
}
|
||||
}
|
||||
Format::Octal => {
|
||||
buf += &format!("{num:o}");
|
||||
}
|
||||
|
|
77
src/main.rs
77
src/main.rs
|
@ -3,87 +3,18 @@
|
|||
//! This binary should just take any amount of numbers and print them out formatted to some other
|
||||
//! system.
|
||||
|
||||
use clap::{ArgGroup, Parser};
|
||||
use clap_num::maybe_hex;
|
||||
use clap::Parser;
|
||||
|
||||
mod format;
|
||||
use format::*;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(author, version, about, long_about = None)]
|
||||
#[command(
|
||||
author,
|
||||
version,
|
||||
about,
|
||||
long_about,
|
||||
help_template = r#"{about-section}
|
||||
{usage-heading} {usage}
|
||||
{all-args}{tab}
|
||||
|
||||
{name}: {version}
|
||||
Author: {author-with-newline}
|
||||
"#
|
||||
)]
|
||||
#[clap(group(
|
||||
ArgGroup::new("format")
|
||||
.args(&["hex", "bin", "oct", "dec", "base64", "base32"]),
|
||||
))]
|
||||
struct Cli {
|
||||
#[arg(short, long)]
|
||||
/// add a prefix (like "0x" for hex)
|
||||
prefix: bool,
|
||||
#[arg(short = 'x', long, default_value_t = true)]
|
||||
/// format to hexadecimal
|
||||
hex: bool,
|
||||
#[arg(short, long)]
|
||||
/// format to binary
|
||||
bin: bool,
|
||||
#[arg(short, long)]
|
||||
/// format to decimal
|
||||
dec: bool,
|
||||
#[arg(short, long)]
|
||||
/// format to octal
|
||||
oct: bool,
|
||||
#[arg(short = 's', long)]
|
||||
/// format to base64
|
||||
base64: bool,
|
||||
#[arg(short = 'z', long)]
|
||||
/// format to base32
|
||||
base32: bool,
|
||||
#[clap(value_parser=maybe_hex::<Num>, required=true)]
|
||||
/// at least one number that should be formatted
|
||||
///
|
||||
/// supports either base 10 or base 16 inputs (with 0xaaaa)
|
||||
numbers: Vec<Num>,
|
||||
}
|
||||
|
||||
impl Cli {
|
||||
fn format(&self) -> Format {
|
||||
if self.oct {
|
||||
Format::Octal
|
||||
} else if self.bin {
|
||||
Format::Bin
|
||||
} else if self.dec {
|
||||
Format::Dec
|
||||
} else if self.base64 {
|
||||
Format::Base64
|
||||
} else if self.base32 {
|
||||
Format::Base32
|
||||
} else if self.hex {
|
||||
Format::Hex
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let cli = Cli::parse();
|
||||
let options = FormatOptions::parse();
|
||||
|
||||
let mut out: Vec<String> = Vec::new();
|
||||
|
||||
for num in &cli.numbers {
|
||||
out.push(cli.format().format(*num, cli.prefix));
|
||||
for num in options.numbers() {
|
||||
out.push(options.format().format(*num, &options));
|
||||
}
|
||||
for o in out {
|
||||
println!("{o}")
|
||||
|
|
200
tests/format.rs
Normal file
200
tests/format.rs
Normal file
|
@ -0,0 +1,200 @@
|
|||
use numf::format::*;
|
||||
|
||||
#[test]
|
||||
fn format() {
|
||||
let options = FormatOptions::default();
|
||||
assert_eq!(Format::Dec.format(1337, &options), "1337");
|
||||
assert_eq!(
|
||||
Format::Dec.format(u128::MAX, &options),
|
||||
format!("{}", u128::MAX)
|
||||
);
|
||||
|
||||
assert_eq!(Format::Hex.format(0x1337, &options), "1337");
|
||||
assert_eq!(
|
||||
Format::Hex.format(u128::MAX, &options),
|
||||
format!("{:X}", u128::MAX)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Format::Bin.format(0b1010001001010010010100111, &options),
|
||||
"1010001001010010010100111"
|
||||
);
|
||||
assert_eq!(
|
||||
Format::Bin.format(u128::MAX, &options),
|
||||
format!("{:b}", u128::MAX)
|
||||
);
|
||||
|
||||
assert_eq!(Format::Octal.format(0o13377331, &options), "13377331");
|
||||
assert_eq!(
|
||||
Format::Octal.format(u128::MAX, &options),
|
||||
format!("{:o}", u128::MAX)
|
||||
);
|
||||
|
||||
assert_eq!(Format::Base32.format(0x41414242, &options), "IFAUEQQ=");
|
||||
assert_eq!(
|
||||
Format::Base32.format(0x4141414141414141, &options),
|
||||
"IFAUCQKBIFAUC==="
|
||||
);
|
||||
|
||||
assert_eq!(Format::Base64.format(0x41414242, &options), "QUFCQg==");
|
||||
assert_eq!(
|
||||
Format::Base64.format(0x4141414141414141, &options),
|
||||
"QUFBQUFBQUE="
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_padding() {
|
||||
let mut options = FormatOptions::default();
|
||||
options.set_padding(true);
|
||||
|
||||
assert_eq!(Format::Dec.format(1337, &options), "1337");
|
||||
assert_eq!(
|
||||
Format::Dec.format(u128::MAX, &options),
|
||||
format!("{}", u128::MAX)
|
||||
);
|
||||
|
||||
assert_eq!(Format::Hex.format(0xFFF, &options), "0FFF");
|
||||
assert_eq!(Format::Hex.format(0xFFFF, &options), "FFFF");
|
||||
assert_eq!(
|
||||
Format::Hex.format(u128::MAX, &options),
|
||||
format!("{:X}", u128::MAX)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Format::Bin.format(0b11110000_00001111, &options),
|
||||
"1111000000001111"
|
||||
);
|
||||
assert_eq!(
|
||||
Format::Bin.format(0b110000_00001111, &options),
|
||||
"0011000000001111"
|
||||
);
|
||||
assert_eq!(
|
||||
Format::Bin.format(u128::MAX, &options),
|
||||
format!("{:b}", u128::MAX)
|
||||
);
|
||||
|
||||
assert_eq!(Format::Octal.format(0o13377331, &options), "13377331");
|
||||
assert_eq!(
|
||||
Format::Octal.format(u128::MAX, &options),
|
||||
format!("{:o}", u128::MAX)
|
||||
);
|
||||
|
||||
assert_eq!(Format::Base32.format(0x41414242, &options), "IFAUEQQ=");
|
||||
assert_eq!(
|
||||
Format::Base32.format(0x4141414141414141, &options),
|
||||
"IFAUCQKBIFAUC==="
|
||||
);
|
||||
|
||||
assert_eq!(Format::Base64.format(0x41414242, &options), "QUFCQg==");
|
||||
assert_eq!(
|
||||
Format::Base64.format(0x4141414141414141, &options),
|
||||
"QUFBQUFBQUE="
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_prefix() {
|
||||
let mut options = FormatOptions::default();
|
||||
options.set_prefix(true);
|
||||
|
||||
assert_eq!(Format::Dec.format(1337, &options), "0d1337");
|
||||
assert_eq!(
|
||||
Format::Dec.format(u128::MAX, &options),
|
||||
format!("0d{}", u128::MAX)
|
||||
);
|
||||
|
||||
assert_eq!(Format::Hex.format(0x1337, &options), "0x1337");
|
||||
assert_eq!(
|
||||
Format::Hex.format(u128::MAX, &options),
|
||||
format!("0x{:X}", u128::MAX)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Format::Bin.format(0b1010001001010010010100111, &options),
|
||||
"0b1010001001010010010100111"
|
||||
);
|
||||
assert_eq!(
|
||||
Format::Bin.format(u128::MAX, &options),
|
||||
format!("0b{:b}", u128::MAX)
|
||||
);
|
||||
|
||||
assert_eq!(Format::Octal.format(0o13377331, &options), "0o13377331");
|
||||
assert_eq!(
|
||||
Format::Octal.format(u128::MAX, &options),
|
||||
format!("0o{:o}", u128::MAX)
|
||||
);
|
||||
|
||||
assert_eq!(Format::Base32.format(0x41414242, &options), "032sIFAUEQQ=");
|
||||
assert_eq!(
|
||||
Format::Base32.format(0x4141414141414141, &options),
|
||||
"032sIFAUCQKBIFAUC==="
|
||||
);
|
||||
|
||||
assert_eq!(Format::Base64.format(0x41414242, &options), "0sQUFCQg==");
|
||||
assert_eq!(
|
||||
Format::Base64.format(0x4141414141414141, &options),
|
||||
"0sQUFBQUFBQUE="
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_padded_prefix() {
|
||||
let mut options = FormatOptions::default();
|
||||
options.set_prefix(true);
|
||||
options.set_padding(true);
|
||||
|
||||
assert_eq!(Format::Dec.format(1337, &options), "0d1337");
|
||||
assert_eq!(
|
||||
Format::Dec.format(u128::MAX, &options),
|
||||
format!("0d{}", u128::MAX)
|
||||
);
|
||||
|
||||
assert_eq!(Format::Hex.format(0xFFF, &options), "0x0FFF");
|
||||
assert_eq!(Format::Hex.format(0xFFFF, &options), "0xFFFF");
|
||||
assert_eq!(
|
||||
Format::Hex.format(u128::MAX, &options),
|
||||
format!("0x{:X}", u128::MAX)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Format::Bin.format(0b11110000_00001111, &options),
|
||||
"0b1111000000001111"
|
||||
);
|
||||
assert_eq!(
|
||||
Format::Bin.format(0b110000_00001111, &options),
|
||||
"0b0011000000001111"
|
||||
);
|
||||
assert_eq!(
|
||||
Format::Bin.format(u128::MAX, &options),
|
||||
format!("0b{:b}", u128::MAX)
|
||||
);
|
||||
|
||||
assert_eq!(Format::Octal.format(0o13377331, &options), "0o13377331");
|
||||
assert_eq!(
|
||||
Format::Octal.format(u128::MAX, &options),
|
||||
format!("0o{:o}", u128::MAX)
|
||||
);
|
||||
|
||||
assert_eq!(Format::Base32.format(0x41414242, &options), "032sIFAUEQQ=");
|
||||
assert_eq!(
|
||||
Format::Base32.format(0x4141414141414141, &options),
|
||||
"032sIFAUCQKBIFAUC==="
|
||||
);
|
||||
|
||||
assert_eq!(Format::Base64.format(0x41414242, &options), "0sQUFCQg==");
|
||||
assert_eq!(
|
||||
Format::Base64.format(0x4141414141414141, &options),
|
||||
"0sQUFBQUFBQUE="
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_format_checker() {
|
||||
let mut options = FormatOptions::default();
|
||||
assert_eq!(options.format(), Format::Hex);
|
||||
options.set_format(Format::Base32);
|
||||
assert_eq!(options.format(), Format::Base32);
|
||||
options.set_format(Format::Base64);
|
||||
assert_eq!(options.format(), Format::Base64);
|
||||
}
|
Reference in a new issue