diff --git a/core/expression/Cargo.toml b/core/expression/Cargo.toml index c1430d28..94c146c4 100644 --- a/core/expression/Cargo.toml +++ b/core/expression/Cargo.toml @@ -17,7 +17,7 @@ once_cell = { workspace = true } regex = { workspace = true, optional = true } regex-lite = { workspace = true, optional = true } serde = { workspace = true } -serde_json = { workspace = true, features = ["arbitrary_precision"] } +serde_json = { workspace = true, features = [] } strum = { workspace = true } strum_macros = { workspace = true } thiserror = { workspace = true } @@ -36,6 +36,7 @@ serde_json5 = "0.1.0" default = ["regex-deprecated"] regex-deprecated = ["dep:regex"] regex-lite = ["dep:regex-lite"] +arbitrary_precision = ["serde_json/arbitrary_precision"] [[bench]] harness = false diff --git a/core/expression/src/variable/conv.rs b/core/expression/src/variable/conv.rs index b6bf4184..68ae70bb 100644 --- a/core/expression/src/variable/conv.rs +++ b/core/expression/src/variable/conv.rs @@ -1,5 +1,6 @@ use bumpalo::collections::Vec as BumpVec; use bumpalo::Bump; +use rust_decimal::prelude::FromPrimitive; use rust_decimal::Decimal; use serde_json::Value; @@ -19,9 +20,30 @@ impl<'arena> ToVariable<'arena> for Value { match self { Value::Null => Ok(Variable::Null), Value::Bool(v) => Ok(Variable::Bool(*v)), - Value::Number(n) => Ok(Variable::Number( - Decimal::from_str_exact(n.as_str()).map_err(|_| ())?, - )), + Value::Number(n) => { + #[cfg(feature = "arbitrary_precision")] + { + Decimal::from_str_exact(n.as_str()) + .map_err(|_| ()) + .map(Variable::Number) + } + + #[cfg(not(feature = "arbitrary_precision"))] + { + let decimal = match n.as_u64() { + Some(n) => Decimal::from_u64(n).ok_or(())?, + None => match n.as_i64() { + Some(n) => Decimal::from(n), + None => match n.as_f64() { + Some(n) => Decimal::from_f64(n).ok_or(())?, + None => return Err(()), + }, + }, + }; + + Ok(Variable::Number(decimal)) + } + } Value::String(s) => Ok(Variable::String(arena.alloc_str(s.as_str()))), Value::Array(arr) => { let mut vec = BumpVec::with_capacity_in(arr.len(), arena); diff --git a/core/expression/src/variable/mod.rs b/core/expression/src/variable/mod.rs index 6757f874..f5bf79e4 100644 --- a/core/expression/src/variable/mod.rs +++ b/core/expression/src/variable/mod.rs @@ -80,7 +80,31 @@ impl<'arena> Variable<'arena> { Variable::Null => Value::Null, Variable::Bool(b) => Value::Bool(*b), Variable::Number(n) => { - Value::Number(Number::from_string_unchecked(n.normalize().to_string())) + #[cfg(feature = "arbitrary_precision")] + { + Value::Number(Number::from_string_unchecked(n.normalize().to_string())) + } + + #[cfg(not(feature = "arbitrary_precision"))] + { + if let Some(n_uint) = n.to_u64() { + if Decimal::from(n_uint) == *n { + return Value::Number(Number::from(n_uint)); + } + } + + if let Some(n_int) = n.to_i64() { + if Decimal::from(n_int) == *n { + return Value::Number(Number::from(n_int)); + } + } + + if let Some(n_float) = n.to_f64() { + return Value::Number(Number::from_f64(n_float).unwrap()); + } + + Value::Null + } } Variable::String(str) => Value::String(str.to_string()), Variable::Array(arr) => Value::Array(arr.iter().map(|i| i.to_value()).collect()), diff --git a/core/expression/tests/isolate.rs b/core/expression/tests/isolate.rs index 093b742d..452440b8 100644 --- a/core/expression/tests/isolate.rs +++ b/core/expression/tests/isolate.rs @@ -61,6 +61,42 @@ fn isolate_standard_test() { }, ]), }, + TestEnv { + env: json!({ + "a": 3.14f64, + "b": 2, + "c": 3.141592653589793f64, + "d": 18446744073709551615u64, + "e": 9_223_372_036_854_775_807i64, + + }), + cases: Vec::from([ + TestCase { + expr: "a", + result: json!(3.14), + }, + TestCase { + expr: "b", + result: json!(2), + }, + TestCase { + expr: "e", + result: json!(9_223_372_036_854_775_807i64), + }, + TestCase { + expr: "a + b", + result: json!(5.14), + }, + TestCase { + expr: "(b + c) - (c + b)", + result: json!(0), + }, + TestCase { + expr: "d", + result: json!(18446744073709551615u64), + }, + ]), + }, TestEnv { env: json!({ "a": 3, diff --git a/core/expression/tests/standard.rs b/core/expression/tests/standard.rs index 350c962e..d8908658 100644 --- a/core/expression/tests/standard.rs +++ b/core/expression/tests/standard.rs @@ -281,6 +281,14 @@ fn standard_test() { right: &Node::Array(&[]), }, }, + StandardTest { + src: "25 + 2.5", + result: &Node::Binary { + left: &Node::Number(D25), + right: &Node::Number(D2P5), + operator: Operator::Arithmetic(ArithmeticOperator::Add), + }, + }, ]); let mut lexer = Lexer::new();