refactor: use the cli struct as format options #11 #9
cargo devel CI / cargo CI (push) Has been cancelled Details

This commit is contained in:
Christoph J. Scherr 2024-05-12 19:53:38 +02:00
parent 82c1bf8d8a
commit cae701815e
2 changed files with 131 additions and 98 deletions

View File

@ -1,3 +1,6 @@
#![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;
@ -13,29 +16,137 @@ pub enum Format {
Base32,
}
/// Options to use when formatting a number
/// Describes what the formatter should do
///
/// Used by [Format::format].
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
/// Use [Self::default] to get a basic variant or create a object yourself.
///
/// This struct can be parsed with [clap] derive.
#[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"]),
))]
pub struct FormatOptions {
/// add a prefix to the formatted number, such as `0x` for hex
#[arg(short, long)]
/// add a prefix (like "0x" for hex)
prefix: bool,
/// fill the formatted number with zeros (or the equivalent) to make a whole byte
#[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 {
/// set prefix
pub fn prefix(mut self, value: bool) -> Self {
self.prefix = value;
self
/// 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![],
}
/// set padding
///
/// Does not apply to all formats
pub fn padding(mut self, value: bool) -> Self {
self.padding = value;
self
}
}
@ -58,7 +169,7 @@ impl Format {
}
.to_string()
}
pub fn format(&self, num: Num, options: FormatOptions) -> String {
pub fn format(&self, num: Num, options: &FormatOptions) -> String {
let mut buf = String::new();
if options.prefix {
buf += &self.prefix();

View File

@ -3,96 +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 = '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 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 = FormatOptions::default()
.padding(cli.padding)
.prefix(cli.prefix);
let options = FormatOptions::parse();
let mut out: Vec<String> = Vec::new();
for num in &cli.numbers {
out.push(cli.format().format(*num, options));
for num in options.numbers() {
out.push(options.format().format(*num, &options));
}
for o in out {
println!("{o}")