feat: padding and FormatOptions #9 #11

Merged
PlexSheep merged 3 commits from feat/padding into master 2024-05-12 19:59:19 +02:00
2 changed files with 156 additions and 77 deletions

View File

@ -1,7 +1,11 @@
#![allow(dead_code)] // this is exported to lib.rs
use clap::{ArgGroup, Parser};
use clap_num::maybe_hex;
use libpt::bintols::split; use libpt::bintols::split;
pub type Num = u128; pub type Num = u128;
/// formats supported by numf
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum Format { pub enum Format {
Dec, Dec,
@ -12,6 +16,140 @@ pub enum Format {
Base32, Base32,
} }
/// Describes what the formatter should do
///
PlexSheep marked this conversation as resolved
Review

Use the Cli struct instead somehow. It already contains all this information

Use the Cli struct instead somehow. It already contains all this information
/// 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,
PlexSheep marked this conversation as resolved Outdated

also maybe shorten this

also maybe shorten this
#[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 {
PlexSheep marked this conversation as resolved
Review

can this not be shortened?

can this not be shortened?
/// 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;
}
/// get padding
pub fn padding(&self) -> bool {
self.padding
}
/// get prefix
pub fn prefix(&self) -> bool {
self.prefix
}
}
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 { impl Format {
pub fn prefix(&self) -> String { pub fn prefix(&self) -> String {
match self { match self {
@ -31,17 +169,27 @@ impl Format {
} }
.to_string() .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(); let mut buf = String::new();
if prefix { if options.prefix {
buf += &self.prefix(); buf += &self.prefix();
} }
match self { match self {
Format::Hex => { Format::Hex => {
buf += &format!("{num:X}"); if options.padding {
let tmp = &format!("{num:X}");
buf += &("0".repeat((2 - tmp.len() % 2) % 2) + tmp);
} else {
buf += &format!("{num:X}");
}
} }
Format::Bin => { Format::Bin => {
buf += &format!("{num:b}"); if options.padding {
let tmp = &format!("{num:b}");
buf += &("0".repeat((8 - tmp.len() % 8) % 8) + tmp);
} else {
buf += &format!("{num:b}");
}
} }
Format::Octal => { Format::Octal => {
buf += &format!("{num:o}"); buf += &format!("{num:o}");

View File

@ -3,87 +3,18 @@
//! This binary should just take any amount of numbers and print them out formatted to some other //! This binary should just take any amount of numbers and print them out formatted to some other
//! system. //! system.
use clap::{ArgGroup, Parser}; use clap::Parser;
use clap_num::maybe_hex;
mod format; mod format;
use 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() { fn main() {
let cli = Cli::parse(); let options = FormatOptions::parse();
let mut out: Vec<String> = Vec::new(); let mut out: Vec<String> = Vec::new();
for num in &cli.numbers { for num in options.numbers() {
out.push(cli.format().format(*num, cli.prefix)); out.push(options.format().format(*num, &options));
} }
for o in out { for o in out {
println!("{o}") println!("{o}")