Merge pull request #1293 from JJJollyjim/master

numfmt: support neither or both of --to and --from
This commit is contained in:
Alex Lyon 2018-10-09 18:06:49 -07:00 committed by GitHub
commit 5008b4db2e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 54 additions and 30 deletions

View file

@ -34,17 +34,13 @@ const IEC_BASES: [f64; 10] = [
type Result<T> = std::result::Result<T, String>;
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<Unit> {
"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<Suffix>, u: &Unit) -> Result<f64> {
}
}
fn transform_from(s: String, unit: &Unit) -> Result<String> {
fn transform_from(s: String, opts: &Transform) -> Result<f64> {
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<Suffix>)> {
@ -198,12 +199,12 @@ fn consider_suffix(i: f64, u: &Unit) -> Result<(f64, Option<Suffix>)> {
_ => 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<String> {
let i = s.parse::<f64>().map_err(|err| err.to_string())?;
let (i2, s) = consider_suffix(i, unit)?;
fn transform_to(s: f64, opts: &Transform) -> Result<String> {
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<String> {
}
fn format_string(source: String, options: &NumfmtOptions) -> Result<String> {
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<String> {
}
fn parse_options(args: &Matches) -> Result<NumfmtOptions> {
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") {

View file

@ -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");
}