From 61a01ea957c7b7a842f8ad768bf0a43fabed6fb9 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sat, 13 Feb 2021 23:01:26 +0800 Subject: [PATCH 1/3] Add comments to Union. --- src/dynamic.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/dynamic.rs b/src/dynamic.rs index c5a2743b..afd1e099 100644 --- a/src/dynamic.rs +++ b/src/dynamic.rs @@ -152,25 +152,38 @@ pub struct Dynamic(pub(crate) Union); /// /// Most variants are boxed to reduce the size. pub enum Union { + /// The Unit value - (). Unit((), AccessMode), + /// A boolean value. Bool(bool, AccessMode), + /// An [`ImmutableString`] value. Str(ImmutableString, AccessMode), + /// A character value. Char(char, AccessMode), + /// An integer value. Int(INT, AccessMode), + /// A floating-point value. #[cfg(not(feature = "no_float"))] Float(FloatWrapper, AccessMode), + /// A fixed-precision decimal value. #[cfg(feature = "decimal")] Decimal(Box, AccessMode), + /// An array value. #[cfg(not(feature = "no_index"))] Array(Box, AccessMode), + /// An object map value. #[cfg(not(feature = "no_object"))] Map(Box, AccessMode), + /// A function pointer. FnPtr(Box, AccessMode), + /// A timestamp value. #[cfg(not(feature = "no_std"))] TimeStamp(Box, AccessMode), + /// Any type as a trait object. Variant(Box>, AccessMode), + /// A _shared_ value of any type. #[cfg(not(feature = "no_closure"))] Shared(crate::Shared>, AccessMode), } From 224d93f167ab6d4c08ff70e2d82f0a5176200d3e Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sat, 13 Feb 2021 23:01:34 +0800 Subject: [PATCH 2/3] Add comparison operators for Decimals. --- src/packages/logic.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/packages/logic.rs b/src/packages/logic.rs index f312bc93..deb85c74 100644 --- a/src/packages/logic.rs +++ b/src/packages/logic.rs @@ -1,6 +1,11 @@ +#![allow(non_snake_case)] + use crate::def_package; use crate::plugin::*; +#[cfg(feature = "decimal")] +use rust_decimal::Decimal; + #[cfg(any( not(feature = "no_float"), all(not(feature = "only_i32"), not(feature = "only_i64")) @@ -70,6 +75,9 @@ def_package!(crate:LogicPackage:"Logical operators.", lib, { reg_functions!(lib += float; f64); } + #[cfg(feature = "decimal")] + reg_functions!(lib += decimal; Decimal); + set_exported_fn!(lib, "!", not); }); @@ -95,3 +103,6 @@ gen_cmp_functions!(float => f32); #[cfg(not(feature = "no_float"))] #[cfg(feature = "f32_float")] gen_cmp_functions!(float => f64); + +#[cfg(feature = "decimal")] +gen_cmp_functions!(decimal => Decimal); From fc21756785a157aa1340259964c13aa636028324 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sat, 13 Feb 2021 23:25:22 +0800 Subject: [PATCH 3/3] Add rounding functions to Decimal numbers. --- RELEASES.md | 1 + src/packages/math_basic.rs | 114 ++++++++++++++++++++++++++++++++++++- 2 files changed, 113 insertions(+), 2 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 0d01c4e7..89d2fd3b 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -9,6 +9,7 @@ Bug fixes * Empty statements (i.e. statements with only one `;`) now parse correctly and no longer hang. * `continue`, `break` and `return` statements no longer panic inside a `try .. catch` block. +* `round` function for `f64` is now implemented correctly. Breaking changes ---------------- diff --git a/src/packages/math_basic.rs b/src/packages/math_basic.rs index a6a82c42..ff485154 100644 --- a/src/packages/math_basic.rs +++ b/src/packages/math_basic.rs @@ -19,6 +19,9 @@ use crate::stdlib::format; #[cfg(feature = "decimal")] use rust_decimal::Decimal; +#[cfg(feature = "decimal")] +use super::arithmetic::make_err; + #[allow(dead_code)] #[cfg(feature = "only_i32")] pub const MAX_INT: INT = i32::MAX; @@ -228,7 +231,7 @@ mod float_functions { } #[rhai_fn(name = "round", get = "round")] pub fn round(x: FLOAT) -> FLOAT { - x.ceil() + x.round() } #[rhai_fn(name = "int", get = "int")] pub fn int(x: FLOAT) -> FLOAT { @@ -311,7 +314,114 @@ mod decimal_functions { } #[rhai_fn(name = "round", get = "round")] pub fn round(x: Decimal) -> Decimal { - x.ceil() + x.round() + } + #[rhai_fn(return_raw)] + pub fn round_dp(x: Decimal, dp: INT) -> Result> { + if cfg!(not(feature = "unchecked")) { + if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) { + return Err(make_err(format!( + "Decimal value {} round to too many decimal points: {}", + x, dp + ))); + } + if dp < 0 { + return Err(make_err(format!( + "Decimal value {} round to a negative index: {}", + x, dp + ))); + } + } + + Ok(Dynamic::from(x.round_dp(dp as u32))) + } + #[rhai_fn(return_raw)] + pub fn round_up(x: Decimal, dp: INT) -> Result> { + if cfg!(not(feature = "unchecked")) { + if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) { + return Err(make_err(format!( + "Decimal value {} round to too many decimal points: {}", + x, dp + ))); + } + if dp < 0 { + return Err(make_err(format!( + "Decimal value {} round to a negative index: {}", + x, dp + ))); + } + } + + Ok(Dynamic::from(x.round_dp_with_strategy( + dp as u32, + rust_decimal::prelude::RoundingStrategy::RoundUp, + ))) + } + #[rhai_fn(return_raw)] + pub fn round_down(x: Decimal, dp: INT) -> Result> { + if cfg!(not(feature = "unchecked")) { + if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) { + return Err(make_err(format!( + "Decimal value {} round to too many decimal points: {}", + x, dp + ))); + } + if dp < 0 { + return Err(make_err(format!( + "Decimal value {} round to a negative index: {}", + x, dp + ))); + } + } + + Ok(Dynamic::from(x.round_dp_with_strategy( + dp as u32, + rust_decimal::prelude::RoundingStrategy::RoundDown, + ))) + } + #[rhai_fn(return_raw)] + pub fn round_half_up(x: Decimal, dp: INT) -> Result> { + if cfg!(not(feature = "unchecked")) { + if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) { + return Err(make_err(format!( + "Decimal value {} round to too many decimal points: {}", + x, dp + ))); + } + if dp < 0 { + return Err(make_err(format!( + "Decimal value {} round to a negative index: {}", + x, dp + ))); + } + } + + Ok(Dynamic::from(x.round_dp_with_strategy( + dp as u32, + rust_decimal::prelude::RoundingStrategy::RoundHalfUp, + ))) + } + #[rhai_fn(return_raw)] + pub fn round_half_down(x: Decimal, dp: INT) -> Result> { + if cfg!(not(feature = "unchecked")) { + if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) { + return Err(make_err(format!( + "Decimal value {} round to too many decimal points: {}", + x, dp + ))); + } + if dp < 0 { + return Err(make_err(format!( + "Decimal value {} round to a negative index: {}", + x, dp + ))); + } + } + + Ok(Dynamic::from(x.round_dp_with_strategy( + dp as u32, + rust_decimal::prelude::RoundingStrategy::RoundHalfDown, + ))) } #[rhai_fn(name = "int", get = "int")] pub fn int(x: Decimal) -> Decimal {