From 82c1bf8d8a268aafb38229f3759050c45c282292 Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 12 May 2024 19:33:48 +0200 Subject: [PATCH 1/3] feat: padding and FormatOptions #9 --- src/format.rs | 45 +++++++++++++++++++++++++++++++++++++++++---- src/main.rs | 11 ++++++++++- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/format.rs b/src/format.rs index fe425df..f4b1dc8 100644 --- a/src/format.rs +++ b/src/format.rs @@ -2,6 +2,7 @@ use libpt::bintols::split; pub type Num = u128; +/// formats supported by numf #[derive(Copy, Clone, Debug)] pub enum Format { Dec, @@ -12,6 +13,32 @@ pub enum Format { Base32, } +/// Options to use when formatting a number +/// +/// Used by [Format::format]. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub struct FormatOptions { + /// add a prefix to the formatted number, such as `0x` for hex + prefix: bool, + /// fill the formatted number with zeros (or the equivalent) to make a whole byte + padding: bool, +} + +impl FormatOptions { + /// set prefix + pub fn prefix(mut self, value: bool) -> Self { + self.prefix = value; + self + } + /// set padding + /// + /// Does not apply to all formats + pub fn padding(mut self, value: bool) -> Self { + self.padding = value; + self + } +} + impl Format { pub fn prefix(&self) -> String { match self { @@ -31,17 +58,27 @@ 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 => { - 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 => { - 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 => { buf += &format!("{num:o}"); diff --git a/src/main.rs b/src/main.rs index 927ddfb..8559138 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,6 +32,12 @@ 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, @@ -79,11 +85,14 @@ impl Cli { fn main() { let cli = Cli::parse(); + let options: FormatOptions = FormatOptions::default() + .padding(cli.padding) + .prefix(cli.prefix); let mut out: Vec = Vec::new(); for num in &cli.numbers { - out.push(cli.format().format(*num, cli.prefix)); + out.push(cli.format().format(*num, options)); } for o in out { println!("{o}") From cae701815ee1bcf0d7486b9126cc0b300acdd510 Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 12 May 2024 19:53:38 +0200 Subject: [PATCH 2/3] refactor: use the cli struct as format options #11 #9 --- src/format.rs | 143 ++++++++++++++++++++++++++++++++++++++++++++------ src/main.rs | 86 ++---------------------------- 2 files changed, 131 insertions(+), 98 deletions(-) diff --git a/src/format.rs b/src/format.rs index f4b1dc8..041ff28 100644 --- a/src/format.rs +++ b/src/format.rs @@ -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::, required=true)] + /// at least one number that should be formatted + /// + /// supports either base 10 or base 16 inputs (with 0xaaaa) + numbers: Vec, } 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 padding - /// - /// Does not apply to all formats - pub fn padding(mut self, value: bool) -> Self { - self.padding = value; - self + + /// 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) { + 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![], + } } } @@ -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(); diff --git a/src/main.rs b/src/main.rs index 8559138..1aa0470 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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::, required=true)] - /// at least one number that should be formatted - /// - /// supports either base 10 or base 16 inputs (with 0xaaaa) - numbers: Vec, -} - -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 = 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}") From 4f269fb50917c0f11e16c875b43ab56d33d593d1 Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 12 May 2024 19:54:45 +0200 Subject: [PATCH 3/3] refactor: add more derives --- src/format.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/format.rs b/src/format.rs index 041ff28..f756b1b 100644 --- a/src/format.rs +++ b/src/format.rs @@ -21,7 +21,7 @@ pub enum Format { /// Use [Self::default] to get a basic variant or create a object yourself. /// /// This struct can be parsed with [clap] derive. -#[derive(Parser, Debug)] +#[derive(Parser, Debug, Clone, PartialEq, Eq, Hash)] #[clap(author, version, about, long_about = None)] #[command( author,