Update bigint/bigdecimal (#2585)

* Update bigint/bigdecimal

* clippy
This commit is contained in:
Jonathan Turner
2020-09-22 05:28:31 +12:00
committed by GitHub
parent 7a595827f1
commit 9b577b8679
35 changed files with 263 additions and 132 deletions

View File

@ -14,6 +14,7 @@ fn from_delimited_string_to_value(
.delimiter(separator as u8)
.from_reader(s.as_bytes());
let tag = tag.into();
let span = tag.span;
let headers = if headerless {
(1..=reader.headers()?.len())
@ -30,7 +31,10 @@ fn from_delimited_string_to_value(
if let Ok(i) = value.parse::<i64>() {
tagged_row.insert_value(header, UntaggedValue::int(i).into_value(&tag))
} else if let Ok(f) = value.parse::<f64>() {
tagged_row.insert_value(header, UntaggedValue::decimal(f).into_value(&tag))
tagged_row.insert_value(
header,
UntaggedValue::decimal_from_float(f, span).into_value(&tag),
)
} else {
tagged_row.insert_value(header, UntaggedValue::string(value).into_value(&tag))
}

View File

@ -39,11 +39,12 @@ impl WholeStreamCommand for FromJSON {
fn convert_json_value_to_nu_value(v: &serde_hjson::Value, tag: impl Into<Tag>) -> Value {
let tag = tag.into();
let span = tag.span;
match v {
serde_hjson::Value::Null => UntaggedValue::Primitive(Primitive::Nothing).into_value(&tag),
serde_hjson::Value::Bool(b) => UntaggedValue::boolean(*b).into_value(&tag),
serde_hjson::Value::F64(n) => UntaggedValue::decimal(*n).into_value(&tag),
serde_hjson::Value::F64(n) => UntaggedValue::decimal_from_float(*n, span).into_value(&tag),
serde_hjson::Value::U64(n) => UntaggedValue::int(*n).into_value(&tag),
serde_hjson::Value::I64(n) => UntaggedValue::int(*n).into_value(&tag),
serde_hjson::Value::String(s) => {

View File

@ -45,6 +45,7 @@ async fn from_ods(
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let tag = args.call_info.name_tag.clone();
let span = tag.span;
let registry = registry.clone();
let (
@ -73,7 +74,7 @@ async fn from_ods(
let value = match cell {
DataType::Empty => UntaggedValue::nothing(),
DataType::String(s) => UntaggedValue::string(s),
DataType::Float(f) => UntaggedValue::decimal(*f),
DataType::Float(f) => UntaggedValue::decimal_from_float(*f, span),
DataType::Int(i) => UntaggedValue::int(*i),
DataType::Bool(b) => UntaggedValue::boolean(*b),
_ => UntaggedValue::nothing(),

View File

@ -30,11 +30,12 @@ impl WholeStreamCommand for FromTOML {
pub fn convert_toml_value_to_nu_value(v: &toml::Value, tag: impl Into<Tag>) -> Value {
let tag = tag.into();
let span = tag.span;
match v {
toml::Value::Boolean(b) => UntaggedValue::boolean(*b).into_value(tag),
toml::Value::Integer(n) => UntaggedValue::int(*n).into_value(tag),
toml::Value::Float(n) => UntaggedValue::decimal(*n).into_value(tag),
toml::Value::Float(n) => UntaggedValue::decimal_from_float(*n, span).into_value(tag),
toml::Value::String(s) => {
UntaggedValue::Primitive(Primitive::String(String::from(s))).into_value(tag)
}

View File

@ -45,6 +45,7 @@ async fn from_xlsx(
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let tag = args.call_info.name_tag.clone();
let span = tag.span;
let registry = registry.clone();
let (
FromXLSXArgs {
@ -73,7 +74,7 @@ async fn from_xlsx(
let value = match cell {
DataType::Empty => UntaggedValue::nothing(),
DataType::String(s) => UntaggedValue::string(s),
DataType::Float(f) => UntaggedValue::decimal(*f),
DataType::Float(f) => UntaggedValue::decimal_from_float(*f, span),
DataType::Int(i) => UntaggedValue::int(*i),
DataType::Bool(b) => UntaggedValue::boolean(*b),
_ => UntaggedValue::nothing(),

View File

@ -58,6 +58,7 @@ fn convert_yaml_value_to_nu_value(
tag: impl Into<Tag>,
) -> Result<Value, ShellError> {
let tag = tag.into();
let span = tag.span;
let err_not_compatible_number = ShellError::labeled_error(
"Expected a compatible number",
@ -69,10 +70,11 @@ fn convert_yaml_value_to_nu_value(
serde_yaml::Value::Number(n) if n.is_i64() => {
UntaggedValue::int(n.as_i64().ok_or_else(|| err_not_compatible_number)?).into_value(tag)
}
serde_yaml::Value::Number(n) if n.is_f64() => {
UntaggedValue::decimal(n.as_f64().ok_or_else(|| err_not_compatible_number)?)
.into_value(tag)
}
serde_yaml::Value::Number(n) if n.is_f64() => UntaggedValue::decimal_from_float(
n.as_f64().ok_or_else(|| err_not_compatible_number)?,
span,
)
.into_value(tag),
serde_yaml::Value::String(s) => UntaggedValue::string(s).into_value(tag),
serde_yaml::Value::Sequence(a) => {
let result: Result<Vec<Value>, ShellError> = a

View File

@ -53,7 +53,11 @@ impl WholeStreamCommand for SubCommand {
vec![Example {
description: "Get the average of a list of numbers",
example: "echo [-50 100.0 25] | math avg",
result: Some(vec![UntaggedValue::decimal(25).into()]),
result: Some(vec![UntaggedValue::decimal_from_float(
25.0,
Span::unknown(),
)
.into()]),
}]
}
}

View File

@ -39,7 +39,7 @@ mod tests {
sum::summation, utils::calculate, utils::MathFunction, variance::variance,
};
use nu_plugin::row;
use nu_plugin::test_helpers::value::{decimal, int, table};
use nu_plugin::test_helpers::value::{decimal, decimal_from_float, int, table};
use nu_protocol::Value;
use std::str::FromStr;
@ -98,17 +98,17 @@ mod tests {
},
TestCase {
description: "Mixed Values",
values: vec![int(10), decimal(26.5), decimal(26.5)],
values: vec![int(10), decimal_from_float(26.5), decimal_from_float(26.5)],
expected_err: None,
expected_res: vec![
Ok(decimal(21)),
Ok(int(10)),
Ok(decimal(26.5)),
Ok(decimal(26.5)),
Ok(table(&[decimal(26.5)])),
Ok(decimal_from_float(26.5)),
Ok(decimal_from_float(26.5)),
Ok(table(&[decimal_from_float(26.5)])),
Ok(decimal(BigDecimal::from_str("7.77817459305202276840928798315333943213319531457321440247173855894902863154158871367713143880202865").expect("Could not convert to decimal from string"))),
Ok(decimal(63)),
Ok(decimal(60.5)),
Ok(decimal_from_float(60.5)),
],
},
TestCase {
@ -128,14 +128,14 @@ mod tests {
},
TestCase {
description: "Mixed Negative Values",
values: vec![decimal(-13.5), decimal(-11.5), int(10)],
values: vec![decimal_from_float(-13.5), decimal_from_float(-11.5), int(10)],
expected_err: None,
expected_res: vec![
Ok(decimal(-5)),
Ok(decimal(-13.5)),
Ok(decimal_from_float(-13.5)),
Ok(int(10)),
Ok(decimal(-11.5)),
Ok(table(&[decimal(-13.5), decimal(-11.5), int(10)])),
Ok(decimal_from_float(-11.5)),
Ok(table(&[decimal_from_float(-13.5), decimal_from_float(-11.5), int(10)])),
Ok(decimal(BigDecimal::from_str("10.63798226482196513098036125801342585449179971588207816421068645273754903468375890632981926875247027").expect("Could not convert to decimal from string"))),
Ok(decimal(-15)),
Ok(decimal(BigDecimal::from_str("113.1666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667").expect("Could not convert to decimal from string"))),
@ -151,10 +151,10 @@ mod tests {
],
expected_err: None,
expected_res: vec![
Ok(row!["col1".to_owned() => decimal(2.5), "col2".to_owned() => decimal(6.5)]),
Ok(row!["col1".to_owned() => decimal_from_float(2.5), "col2".to_owned() => decimal_from_float(6.5)]),
Ok(row!["col1".to_owned() => int(1), "col2".to_owned() => int(5)]),
Ok(row!["col1".to_owned() => int(4), "col2".to_owned() => int(8)]),
Ok(row!["col1".to_owned() => decimal(2.5), "col2".to_owned() => decimal(6.5)]),
Ok(row!["col1".to_owned() => decimal_from_float(2.5), "col2".to_owned() => decimal_from_float(6.5)]),
Ok(row![
"col1".to_owned() => table(&[int(1), int(2), int(3), int(4)]),
"col2".to_owned() => table(&[int(5), int(6), int(7), int(8)])
@ -164,7 +164,7 @@ mod tests {
"col2".to_owned() => decimal(BigDecimal::from_str("1.118033988749894848204586834365638117720309179805762862135448622705260462818902449707207204189391137").expect("Could not convert to decimal from string"))
]),
Ok(row!["col1".to_owned() => int(10), "col2".to_owned() => int(26)]),
Ok(row!["col1".to_owned() => decimal(1.25), "col2".to_owned() => decimal(1.25)]),
Ok(row!["col1".to_owned() => decimal_from_float(1.25), "col2".to_owned() => decimal_from_float(1.25)]),
],
},
// TODO-Uncomment once Issue: https://github.com/nushell/nushell/issues/1883 is resolved

View File

@ -41,7 +41,11 @@ impl WholeStreamCommand for SubCommand {
vec![Example {
description: "Evalulate math in the pipeline",
example: "echo '10 / 4' | math eval",
result: Some(vec![UntaggedValue::decimal(2.5).into()]),
result: Some(vec![UntaggedValue::decimal_from_float(
2.5,
Span::unknown(),
)
.into()]),
}]
}
}

View File

@ -50,7 +50,11 @@ impl WholeStreamCommand for SubCommand {
vec![Example {
description: "Get the median of a list of numbers",
example: "echo [3 8 9 12 12 15] | math median",
result: Some(vec![UntaggedValue::decimal(10.5).into()]),
result: Some(vec![UntaggedValue::decimal_from_float(
10.5,
Span::unknown(),
)
.into()]),
}]
}
}

View File

@ -99,12 +99,20 @@ impl WholeStreamCommand for SubCommand {
Example {
description: "Get the variance of a list of numbers",
example: "echo [1 2 3 4 5] | math variance",
result: Some(vec![UntaggedValue::decimal(2).into()]),
result: Some(vec![UntaggedValue::decimal_from_float(
2.0,
Span::unknown(),
)
.into()]),
},
Example {
description: "Get the sample variance of a list of numbers",
example: "echo [1 2 3 4 5] | math variance -s",
result: Some(vec![UntaggedValue::decimal(2.5).into()]),
result: Some(vec![UntaggedValue::decimal_from_float(
2.5,
Span::unknown(),
)
.into()]),
},
]
}

View File

@ -8,7 +8,7 @@ use nu_source::Tagged;
use num_bigint::{BigInt, BigUint, ToBigInt};
// TODO num_format::SystemLocale once platform-specific dependencies are stable (see Cargo.toml)
use num_format::{Locale, ToFormattedString};
use num_format::Locale;
use num_traits::{Pow, Signed};
use std::iter;
@ -40,12 +40,15 @@ impl WholeStreamCommand for SubCommand {
"decimal digits to which to round",
Some('d'),
)
.switch(
"group-digits",
// TODO according to system localization
"group digits, currently by thousand with commas",
Some('g'),
)
/*
FIXME: this isn't currently supported because of num_format being out of date. Once it's updated, re-enable this
.switch(
"group-digits",
// TODO according to system localization
"group digits, currently by thousand with commas",
Some('g'),
)
*/
}
fn usage(&self) -> &str {
@ -67,6 +70,8 @@ impl WholeStreamCommand for SubCommand {
example: "= 1.7 | str from -d 0",
result: Some(vec![UntaggedValue::string("2").into_untagged_value()]),
},
/*
FIXME: this isn't currently supported because of num_format being out of date. Once it's updated, re-enable this
Example {
description: "format large number with localized digit grouping",
example: "= 1000000.2 | str from -g",
@ -74,6 +79,7 @@ impl WholeStreamCommand for SubCommand {
UntaggedValue::string("1,000,000.2").into_untagged_value()
]),
},
*/
]
}
}
@ -147,7 +153,7 @@ pub fn action(
}
fn format_bigint(int: &BigInt) -> String {
int.to_formatted_string(&Locale::en)
format!("{}", int)
// TODO once platform-specific dependencies are stable (see Cargo.toml)
// #[cfg(windows)]
@ -200,10 +206,8 @@ fn format_decimal(mut decimal: BigDecimal, digits: Option<u64>, group_digits: bo
let format_default_loc = |int_part: BigInt| {
let loc = Locale::en;
let (int_str, sep) = (
int_part.to_formatted_string(&loc),
String::from(loc.decimal()),
);
//TODO: when num_format is available for recent bigint, replace this with the locale-based format
let (int_str, sep) = (format!("{}", int_part), String::from(loc.decimal()));
format!("{}{}{}", int_str, sep, dec_str)
};

View File

@ -113,7 +113,7 @@ fn action(input: &Value, tag: impl Into<Tag>) -> Result<Value, ShellError> {
#[cfg(test)]
mod tests {
use super::{action, SubCommand};
use nu_plugin::test_helpers::value::{decimal, string};
use nu_plugin::test_helpers::value::{decimal_from_float, string};
use nu_source::Tag;
#[test]
@ -127,7 +127,7 @@ mod tests {
#[allow(clippy::approx_constant)]
fn turns_to_integer() {
let word = string("3.1415");
let expected = decimal(3.1415);
let expected = decimal_from_float(3.1415);
let actual = action(&word, Tag::unknown()).unwrap();
assert_eq!(actual, expected);