Merge pull request #352 from schungx/master
Add comparison operators and rounding methods to Decimal.
This commit is contained in:
commit
1b35b55e4d
@ -9,6 +9,7 @@ Bug fixes
|
|||||||
|
|
||||||
* Empty statements (i.e. statements with only one `;`) now parse correctly and no longer hang.
|
* 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.
|
* `continue`, `break` and `return` statements no longer panic inside a `try .. catch` block.
|
||||||
|
* `round` function for `f64` is now implemented correctly.
|
||||||
|
|
||||||
Breaking changes
|
Breaking changes
|
||||||
----------------
|
----------------
|
||||||
|
@ -152,25 +152,38 @@ pub struct Dynamic(pub(crate) Union);
|
|||||||
///
|
///
|
||||||
/// Most variants are boxed to reduce the size.
|
/// Most variants are boxed to reduce the size.
|
||||||
pub enum Union {
|
pub enum Union {
|
||||||
|
/// The Unit value - ().
|
||||||
Unit((), AccessMode),
|
Unit((), AccessMode),
|
||||||
|
/// A boolean value.
|
||||||
Bool(bool, AccessMode),
|
Bool(bool, AccessMode),
|
||||||
|
/// An [`ImmutableString`] value.
|
||||||
Str(ImmutableString, AccessMode),
|
Str(ImmutableString, AccessMode),
|
||||||
|
/// A character value.
|
||||||
Char(char, AccessMode),
|
Char(char, AccessMode),
|
||||||
|
/// An integer value.
|
||||||
Int(INT, AccessMode),
|
Int(INT, AccessMode),
|
||||||
|
/// A floating-point value.
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Float(FloatWrapper, AccessMode),
|
Float(FloatWrapper, AccessMode),
|
||||||
|
/// A fixed-precision decimal value.
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
Decimal(Box<Decimal>, AccessMode),
|
Decimal(Box<Decimal>, AccessMode),
|
||||||
|
/// An array value.
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Array(Box<Array>, AccessMode),
|
Array(Box<Array>, AccessMode),
|
||||||
|
/// An object map value.
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Map(Box<Map>, AccessMode),
|
Map(Box<Map>, AccessMode),
|
||||||
|
/// A function pointer.
|
||||||
FnPtr(Box<FnPtr>, AccessMode),
|
FnPtr(Box<FnPtr>, AccessMode),
|
||||||
|
/// A timestamp value.
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
TimeStamp(Box<Instant>, AccessMode),
|
TimeStamp(Box<Instant>, AccessMode),
|
||||||
|
|
||||||
|
/// Any type as a trait object.
|
||||||
Variant(Box<Box<dyn Variant>>, AccessMode),
|
Variant(Box<Box<dyn Variant>>, AccessMode),
|
||||||
|
|
||||||
|
/// A _shared_ value of any type.
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Shared(crate::Shared<crate::Locked<Dynamic>>, AccessMode),
|
Shared(crate::Shared<crate::Locked<Dynamic>>, AccessMode),
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
use rust_decimal::Decimal;
|
||||||
|
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
not(feature = "no_float"),
|
not(feature = "no_float"),
|
||||||
all(not(feature = "only_i32"), not(feature = "only_i64"))
|
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);
|
reg_functions!(lib += float; f64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
reg_functions!(lib += decimal; Decimal);
|
||||||
|
|
||||||
set_exported_fn!(lib, "!", not);
|
set_exported_fn!(lib, "!", not);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -95,3 +103,6 @@ gen_cmp_functions!(float => f32);
|
|||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
#[cfg(feature = "f32_float")]
|
#[cfg(feature = "f32_float")]
|
||||||
gen_cmp_functions!(float => f64);
|
gen_cmp_functions!(float => f64);
|
||||||
|
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
gen_cmp_functions!(decimal => Decimal);
|
||||||
|
@ -19,6 +19,9 @@ use crate::stdlib::format;
|
|||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
use rust_decimal::Decimal;
|
use rust_decimal::Decimal;
|
||||||
|
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
use super::arithmetic::make_err;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[cfg(feature = "only_i32")]
|
#[cfg(feature = "only_i32")]
|
||||||
pub const MAX_INT: INT = i32::MAX;
|
pub const MAX_INT: INT = i32::MAX;
|
||||||
@ -228,7 +231,7 @@ mod float_functions {
|
|||||||
}
|
}
|
||||||
#[rhai_fn(name = "round", get = "round")]
|
#[rhai_fn(name = "round", get = "round")]
|
||||||
pub fn round(x: FLOAT) -> FLOAT {
|
pub fn round(x: FLOAT) -> FLOAT {
|
||||||
x.ceil()
|
x.round()
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "int", get = "int")]
|
#[rhai_fn(name = "int", get = "int")]
|
||||||
pub fn int(x: FLOAT) -> FLOAT {
|
pub fn int(x: FLOAT) -> FLOAT {
|
||||||
@ -311,7 +314,114 @@ mod decimal_functions {
|
|||||||
}
|
}
|
||||||
#[rhai_fn(name = "round", get = "round")]
|
#[rhai_fn(name = "round", get = "round")]
|
||||||
pub fn round(x: Decimal) -> Decimal {
|
pub fn round(x: Decimal) -> Decimal {
|
||||||
x.ceil()
|
x.round()
|
||||||
|
}
|
||||||
|
#[rhai_fn(return_raw)]
|
||||||
|
pub fn round_dp(x: Decimal, dp: INT) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
|
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<Dynamic, Box<EvalAltResult>> {
|
||||||
|
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<Dynamic, Box<EvalAltResult>> {
|
||||||
|
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<Dynamic, Box<EvalAltResult>> {
|
||||||
|
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<Dynamic, Box<EvalAltResult>> {
|
||||||
|
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")]
|
#[rhai_fn(name = "int", get = "int")]
|
||||||
pub fn int(x: Decimal) -> Decimal {
|
pub fn int(x: Decimal) -> Decimal {
|
||||||
|
Loading…
Reference in New Issue
Block a user