From f3a71215bc99265c2f8c473681c39dfd65da4252 Mon Sep 17 00:00:00 2001 From: Jamie McClymont Date: Tue, 25 Sep 2018 01:29:05 +1200 Subject: [PATCH] numfmt: support neither or both of --to and --from matches GNU behaviour --- src/numfmt/numfmt.rs | 59 ++++++++++++++++++++++---------------------- tests/test_numfmt.rs | 25 +++++++++++++++++++ 2 files changed, 54 insertions(+), 30 deletions(-) diff --git a/src/numfmt/numfmt.rs b/src/numfmt/numfmt.rs index 1fe387291..3c34d4a19 100644 --- a/src/numfmt/numfmt.rs +++ b/src/numfmt/numfmt.rs @@ -34,17 +34,13 @@ const IEC_BASES: [f64; 10] = [ type Result = std::result::Result; -enum TransformDirection { - From, - To, -} - type WithI = bool; enum Unit { Auto, Si, Iec(WithI), + None, } enum RawSuffix { @@ -119,12 +115,17 @@ fn parse_unit(s: String) -> Result { "si" => Ok(Unit::Si), "iec" => Ok(Unit::Iec(false)), "iec-i" => Ok(Unit::Iec(true)), + "none" => Ok(Unit::None), _ => Err("Unsupported unit is specified".to_owned()), } } struct TransformOptions { - direction: TransformDirection, + from: Transform, + to: Transform, +} + +struct Transform { unit: Unit, } @@ -165,9 +166,9 @@ fn remove_suffix(i: f64, s: Option, u: &Unit) -> Result { } } -fn transform_from(s: String, unit: &Unit) -> Result { +fn transform_from(s: String, opts: &Transform) -> Result { let (i, suffix) = parse_suffix(s)?; - remove_suffix(i, suffix, unit).map(|n| n.round().to_string()) + remove_suffix(i, suffix, &opts.unit).map(|n| n.round()) } fn consider_suffix(i: f64, u: &Unit) -> Result<(f64, Option)> { @@ -198,12 +199,12 @@ fn consider_suffix(i: f64, u: &Unit) -> Result<(f64, Option)> { _ => Err("Number is too big and unsupported".to_owned()), }, Unit::Auto => Err("Unit 'auto' isn't supported with --to options".to_owned()), + Unit::None => Ok((i, None)), } } -fn transform_to(s: String, unit: &Unit) -> Result { - let i = s.parse::().map_err(|err| err.to_string())?; - let (i2, s) = consider_suffix(i, unit)?; +fn transform_to(s: f64, opts: &Transform) -> Result { + let (i2, s) = consider_suffix(s, &opts.unit)?; Ok(match s { None => format!("{}", i2), Some(s) => format!("{:.1}{}", i2, DisplayableSuffix(s)), @@ -211,10 +212,10 @@ fn transform_to(s: String, unit: &Unit) -> Result { } fn format_string(source: String, options: &NumfmtOptions) -> Result { - let number = match options.transform.direction { - TransformDirection::From => transform_from(source, &options.transform.unit)?, - TransformDirection::To => transform_to(source, &options.transform.unit)?, - }; + let number = transform_to( + transform_from(source, &options.transform.from)?, + &options.transform.to, + )?; Ok(match options.padding { p if p == 0 => number, @@ -224,21 +225,19 @@ fn format_string(source: String, options: &NumfmtOptions) -> Result { } fn parse_options(args: &Matches) -> Result { - let transform = if args.opt_present("from") { - TransformOptions { - direction: TransformDirection::From, - unit: parse_unit( - args.opt_str("from") - .ok_or("'--from' should have argument")?, - )?, - } - } else if args.opt_present("to") { - TransformOptions { - direction: TransformDirection::To, - unit: parse_unit(args.opt_str("to").ok_or("'--to' should have argument")?)?, - } - } else { - return Err("Either '--from' or '--to' should be specified".to_owned()); + let transform = TransformOptions { + from: Transform { + unit: args + .opt_str("from") + .map(parse_unit) + .unwrap_or(Ok(Unit::None))?, + }, + to: Transform { + unit: args + .opt_str("to") + .map(parse_unit) + .unwrap_or(Ok(Unit::None))?, + }, }; let padding = match args.opt_str("padding") { diff --git a/tests/test_numfmt.rs b/tests/test_numfmt.rs index 919b40e27..56f5a0a95 100644 --- a/tests/test_numfmt.rs +++ b/tests/test_numfmt.rs @@ -120,3 +120,28 @@ fn test_negative() { .run() .stdout_is("-1.0Ki\n-1.1Mi\n-102.4Mi"); } + +#[test] +fn test_no_op() { + new_ucmd!() + .pipe_in("1024\n1234567") + .run() + .stdout_is("1024\n1234567"); +} + +#[test] +fn test_normalize() { + new_ucmd!() + .args(&["--from=si", "--to=si"]) + .pipe_in("10000000K\n0.001K") + .run() + .stdout_is("10.0G\n1"); +} + +#[test] +fn test_si_to_iec() { + new_ucmd!() + .args(&["--from=si", "--to=iec", "15334263563K"]) + .run() + .stdout_is("13.9T"); +}