From 54326869e481208bb40561873aa7ce18be5c9a66 Mon Sep 17 00:00:00 2001 From: Chris Gillespie <6572184+gillespiecd@users.noreply.github.com> Date: Tue, 6 Oct 2020 18:01:40 -0700 Subject: [PATCH] Parse decimals as BigDecimal (#2644) Use implicit serde from BigDecimal crate --- crates/nu-parser/src/parse.rs | 47 ++++++++++++------- crates/nu-protocol/src/hir.rs | 14 +----- crates/nu-protocol/src/value.rs | 1 - crates/nu-protocol/src/value/primitive.rs | 2 - .../nu-protocol/src/value/serde_bigdecimal.rs | 26 ---------- 5 files changed, 32 insertions(+), 58 deletions(-) delete mode 100644 crates/nu-protocol/src/value/serde_bigdecimal.rs diff --git a/crates/nu-parser/src/parse.rs b/crates/nu-parser/src/parse.rs index 0a5d1928cf..d17ab72271 100644 --- a/crates/nu-parser/src/parse.rs +++ b/crates/nu-parser/src/parse.rs @@ -15,6 +15,7 @@ use num_bigint::BigInt; use crate::lite_parse::{lite_parse, LiteBlock, LiteCommand, LitePipeline}; use crate::path::expand_path; use crate::signature::SignatureRegistry; +use bigdecimal::BigDecimal; /// Parses a simple column path, one without a variable (implied or explicit) at the head fn parse_simple_column_path(lite_arg: &Spanned) -> (SpannedExpression, Option) { @@ -740,15 +741,11 @@ fn parse_arg( SpannedExpression::new(Expression::integer(x), lite_arg.span), None, ) - } else if let Ok(x) = lite_arg.item.parse::() { - if let Ok(x) = Expression::decimal(x) { - (SpannedExpression::new(x, lite_arg.span), None) - } else { - ( - garbage(lite_arg.span), - Some(ParseError::mismatch("number", lite_arg.clone())), - ) - } + } else if let Ok(x) = lite_arg.item.parse::() { + ( + SpannedExpression::new(Expression::decimal(x), lite_arg.span), + None, + ) } else { ( garbage(lite_arg.span), @@ -765,7 +762,7 @@ fn parse_arg( } else { ( garbage(lite_arg.span), - Some(ParseError::mismatch("number", lite_arg.clone())), + Some(ParseError::mismatch("int", lite_arg.clone())), ) } } @@ -951,43 +948,59 @@ mod test { #[test] fn parse_number() -> Result<(), ParseError> { + let registry = MockRegistry::new(); + let raw = "-32.2".to_string(); let input = raw.clone().spanned(Span::new(0, raw.len())); - let registry = MockRegistry::new(); let result = parse_arg(SyntaxShape::Number, ®istry, &input); assert_eq!(result.1, None); - assert_eq!(result.0.expr, Expression::decimal(-32.2)?); + assert_eq!( + result.0.expr, + Expression::decimal(BigDecimal::new(BigInt::from(-322), 1)) + ); let raw = "32.2".to_string(); let input = raw.clone().spanned(Span::new(0, raw.len())); - let registry = MockRegistry::new(); let result = parse_arg(SyntaxShape::Number, ®istry, &input); assert_eq!(result.1, None); - assert_eq!(result.0.expr, Expression::decimal(32.2)?); + assert_eq!( + result.0.expr, + Expression::decimal(BigDecimal::new(BigInt::from(322), 1)) + ); + + let raw = "36893488147419103232.54".to_string(); + let input = raw.clone().spanned(Span::new(0, raw.len())); + let result = parse_arg(SyntaxShape::Number, ®istry, &input); + assert_eq!(result.1, None); + assert_eq!( + result.0.expr, + Expression::decimal(BigDecimal::new( + BigInt::from(3689348814741910323254 as i128), + 2 + )) + ); let raw = "-34".to_string(); let input = raw.clone().spanned(Span::new(0, raw.len())); - let registry = MockRegistry::new(); let result = parse_arg(SyntaxShape::Number, ®istry, &input); assert_eq!(result.1, None); assert_eq!(result.0.expr, Expression::integer(BigInt::from(-34))); let raw = "34".to_string(); let input = raw.clone().spanned(Span::new(0, raw.len())); - let registry = MockRegistry::new(); let result = parse_arg(SyntaxShape::Number, ®istry, &input); assert_eq!(result.1, None); assert_eq!(result.0.expr, Expression::integer(BigInt::from(34))); let raw = "36893488147419103232".to_string(); let input = raw.clone().spanned(Span::new(0, raw.len())); - let registry = MockRegistry::new(); let result = parse_arg(SyntaxShape::Number, ®istry, &input); assert_eq!(result.1, None); assert_eq!( result.0.expr, Expression::integer(BigInt::from(36893488147419103232 as u128)) ); + Ok(()) } } diff --git a/crates/nu-protocol/src/hir.rs b/crates/nu-protocol/src/hir.rs index 0480eca571..2576c61dd3 100644 --- a/crates/nu-protocol/src/hir.rs +++ b/crates/nu-protocol/src/hir.rs @@ -1099,18 +1099,8 @@ impl Expression { Expression::Literal(Literal::Number(Number::Int(i))) } - pub fn decimal(f: f64) -> Result { - let dec = BigDecimal::from_f64(f); - - let dec = match dec { - Some(x) => Ok(x), - None => Err(ParseError::internal_error( - "Can not convert f64 to big decimal" - .to_string() - .spanned_unknown(), - )), - }?; - Ok(Expression::Literal(Literal::Number(Number::Decimal(dec)))) + pub fn decimal(dec: BigDecimal) -> Expression { + Expression::Literal(Literal::Number(Number::Decimal(dec))) } pub fn string(s: String) -> Expression { diff --git a/crates/nu-protocol/src/value.rs b/crates/nu-protocol/src/value.rs index 669e7bfd47..90c55c98a0 100644 --- a/crates/nu-protocol/src/value.rs +++ b/crates/nu-protocol/src/value.rs @@ -7,7 +7,6 @@ pub mod evaluate; pub mod iter; pub mod primitive; pub mod range; -mod serde_bigdecimal; use crate::hir; use crate::type_name::{ShellTypeName, SpannedTypeName}; diff --git a/crates/nu-protocol/src/value/primitive.rs b/crates/nu-protocol/src/value/primitive.rs index bb74bcabae..ebfb4bb272 100644 --- a/crates/nu-protocol/src/value/primitive.rs +++ b/crates/nu-protocol/src/value/primitive.rs @@ -1,7 +1,6 @@ use crate::type_name::ShellTypeName; use crate::value::column_path::ColumnPath; use crate::value::range::{Range, RangeInclusion}; -use crate::value::serde_bigdecimal; use bigdecimal::BigDecimal; use chrono::{DateTime, Utc}; use nu_errors::{ExpectedRange, ShellError}; @@ -27,7 +26,6 @@ pub enum Primitive { /// A "big int", an integer with arbitrarily large size (aka not limited to 64-bit) Int(BigInt), /// A "big decimal", an decimal number with arbitrarily large size (aka not limited to 64-bit) - #[serde(with = "serde_bigdecimal")] Decimal(BigDecimal), /// A count in the number of bytes, used as a filesize Filesize(u64), diff --git a/crates/nu-protocol/src/value/serde_bigdecimal.rs b/crates/nu-protocol/src/value/serde_bigdecimal.rs deleted file mode 100644 index 0bc407f232..0000000000 --- a/crates/nu-protocol/src/value/serde_bigdecimal.rs +++ /dev/null @@ -1,26 +0,0 @@ -use bigdecimal::BigDecimal; -use num_traits::cast::FromPrimitive; -use num_traits::cast::ToPrimitive; - -/// Enable big decimal serialization by providing a `serialize` function -pub fn serialize(big_decimal: &BigDecimal, serializer: S) -> Result -where - S: serde::Serializer, -{ - serde::Serialize::serialize( - &big_decimal - .to_f64() - .ok_or_else(|| serde::ser::Error::custom("expected a f64-sized bignum"))?, - serializer, - ) -} - -/// Enable big decimal deserialization by providing a `deserialize` function -pub fn deserialize<'de, D>(deserializer: D) -> Result -where - D: serde::Deserializer<'de>, -{ - let x: f64 = serde::Deserialize::deserialize(deserializer)?; - Ok(BigDecimal::from_f64(x) - .ok_or_else(|| serde::de::Error::custom("expected a f64-sized bigdecimal"))?) -}