Fix decimal build.

This commit is contained in:
Stephen Chung 2021-04-24 15:53:02 +08:00
parent c82a47ac26
commit 41d3709db1
2 changed files with 203 additions and 42 deletions

View File

@ -5,24 +5,20 @@ use std::ops::Range;
use std::prelude::v1::*; use std::prelude::v1::*;
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
use num_traits::{CheckedAdd as Add, CheckedSub as Sub}; use num_traits::{CheckedAdd, CheckedSub};
#[cfg(feature = "unchecked")] #[cfg(feature = "unchecked")]
use std::ops::{Add, Sub}; use std::ops::{Add, Sub};
fn get_range<T: Variant + Clone>(from: T, to: T) -> Result<Range<T>, Box<EvalAltResult>> {
Ok(from..to)
}
// Register range function with step // Register range function with step
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
struct StepRange<T>(T, T, T) struct StepRange<T>(T, T, T)
where where
T: Variant + Copy + PartialOrd + Add<Output = T> + Sub<Output = T>; T: Variant + Copy + PartialOrd + CheckedAdd<Output = T> + CheckedSub<Output = T>;
impl<T> StepRange<T> impl<T> StepRange<T>
where where
T: Variant + Copy + PartialOrd + Add<Output = T> + Sub<Output = T>, T: Variant + Copy + PartialOrd + CheckedAdd<Output = T> + CheckedSub<Output = T>,
{ {
pub fn new(from: T, to: T, step: T) -> Result<Self, Box<EvalAltResult>> { pub fn new(from: T, to: T, step: T) -> Result<Self, Box<EvalAltResult>> {
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
@ -47,7 +43,7 @@ where
impl<T> Iterator for StepRange<T> impl<T> Iterator for StepRange<T>
where where
T: Variant + Copy + PartialOrd + Add<Output = T> + Sub<Output = T>, T: Variant + Copy + PartialOrd + CheckedAdd<Output = T> + CheckedSub<Output = T>,
{ {
type Item = T; type Item = T;
@ -130,18 +126,11 @@ where
} }
} }
fn get_step_range<T>(from: T, to: T, step: T) -> Result<StepRange<T>, Box<EvalAltResult>>
where
T: Variant + Copy + PartialOrd + Add<Output = T> + Sub<Output = T>,
{
StepRange::<T>::new(from, to, step)
}
macro_rules! reg_range { macro_rules! reg_range {
($lib:ident | $x:expr => $( $y:ty ),*) => { ($lib:ident | $x:expr => $( $y:ty ),*) => {
$( $(
$lib.set_iterator::<Range<$y>>(); $lib.set_iterator::<Range<$y>>();
let _hash = $lib.set_native_fn($x, get_range::<$y>); let _hash = $lib.set_native_fn($x, |from: $y, to: $y| Ok(from..to));
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
$lib.update_fn_metadata(_hash, &[ $lib.update_fn_metadata(_hash, &[
@ -154,7 +143,7 @@ macro_rules! reg_range {
($lib:ident | step $x:expr => $( $y:ty ),*) => { ($lib:ident | step $x:expr => $( $y:ty ),*) => {
$( $(
$lib.set_iterator::<StepRange<$y>>(); $lib.set_iterator::<StepRange<$y>>();
let _hash = $lib.set_native_fn($x, get_step_range::<$y>); let _hash = $lib.set_native_fn($x, |from: $y, to: $y, step: $y| StepRange::new(from, to, step));
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
$lib.update_fn_metadata(_hash, &[ $lib.update_fn_metadata(_hash, &[
@ -192,12 +181,72 @@ def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
} }
} }
#[cfg(not(feature = "no_float"))]
{
use crate::FLOAT;
#[derive(Debug, Clone, Copy, PartialEq)]
struct StepFloatRange(FLOAT, FLOAT, FLOAT);
impl StepFloatRange {
pub fn new(from: FLOAT, to: FLOAT, step: FLOAT) -> Result<Self, Box<EvalAltResult>> {
#[cfg(not(feature = "unchecked"))]
if step == 0.0 {
return EvalAltResult::ErrorInFunctionCall("range".to_string(), "".to_string(),
Box::new(EvalAltResult::ErrorArithmetic("step value cannot be zero".to_string(), crate::Position::NONE)),
crate::Position::NONE,
).into();
}
Ok(Self(from, to, step))
}
}
impl Iterator for StepFloatRange {
type Item = FLOAT;
fn next(&mut self) -> Option<FLOAT> {
if self.0 == self.1 {
None
} else if self.0 < self.1 {
#[cfg(not(feature = "unchecked"))]
if self.2 < 0.0 {
return None;
}
let v = self.0;
let n = self.0 + self.2;
self.0 = if n >= self.1 { self.1 } else { n };
Some(v)
} else {
#[cfg(not(feature = "unchecked"))]
if self.2 > 0.0 {
return None;
}
let v = self.0;
let n = self.0 + self.2;
self.0 = if n <= self.1 { self.1 } else { n };
Some(v)
}
}
}
impl std::iter::FusedIterator for StepFloatRange {}
lib.set_iterator::<StepFloatRange>();
let _hash = lib.set_native_fn("range", |from, to, step| StepFloatRange::new(from, to, step));
#[cfg(feature = "metadata")]
lib.update_fn_metadata(_hash, &["from: FLOAT", "to: FLOAT", "step: FLOAT", "Iterator<Item=FLOAT>"]);
}
#[cfg(feature = "decimal")] #[cfg(feature = "decimal")]
{ {
use rust_decimal::{ use rust_decimal::Decimal;
prelude::{One, Zero}, use num_traits::Zero;
Decimal,
};
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
struct StepDecimalRange(Decimal, Decimal, Decimal); struct StepDecimalRange(Decimal, Decimal, Decimal);
@ -252,10 +301,6 @@ def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
lib.set_iterator::<StepDecimalRange>(); lib.set_iterator::<StepDecimalRange>();
let _hash = lib.set_native_fn("range", |from, to| StepDecimalRange::new(from, to, Decimal::one()));
#[cfg(feature = "metadata")]
lib.update_fn_metadata(_hash, &["from: Decimal", "to: Decimal", "Iterator<Item=Decimal>"]);
let _hash = lib.set_native_fn("range", |from, to, step| StepDecimalRange::new(from, to, step)); let _hash = lib.set_native_fn("range", |from, to, step| StepDecimalRange::new(from, to, step));
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
lib.update_fn_metadata(_hash, &["from: Decimal", "to: Decimal", "step: Decimal", "Iterator<Item=Decimal>"]); lib.update_fn_metadata(_hash, &["from: Decimal", "to: Decimal", "step: Decimal", "Iterator<Item=Decimal>"]);

View File

@ -1,31 +1,52 @@
use rhai::{Engine, EvalAltResult, Module, INT}; use rhai::{Engine, EvalAltResult, Module, INT};
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_float"))]
use rhai::FLOAT;
#[cfg(feature = "decimal")]
#[cfg(not(feature = "no_float"))]
use rust_decimal::Decimal;
#[test] #[test]
fn test_for() -> Result<(), Box<EvalAltResult>> { fn test_for() -> Result<(), Box<EvalAltResult>> {
let engine = Engine::new(); let engine = Engine::new();
let script = " #[cfg(not(feature = "no_index"))]
let sum1 = 0; assert_eq!(
let sum2 = 0; engine.eval::<INT>(
let inputs = [1, 2, 3, 4, 5]; "
let sum1 = 0;
let sum2 = 0;
let inputs = [1, 2, 3, 4, 5];
for x in inputs { for x in inputs {
sum1 += x; sum1 += x;
} }
for x in range(1, 6) { for x in range(1, 6) {
sum2 += x; sum2 += x;
} }
for x in range(1, 6, 3) { for x in range(1, 6, 3) {
sum2 += x; sum2 += x;
} }
sum1 + sum2 sum1 + sum2
"; "
)?,
35
);
assert_eq!(engine.eval::<INT>(script)?, 35); assert_eq!(
engine.eval::<INT>(
"
let sum = 0;
for x in range(1, 10) { sum += x; }
sum
"
)?,
45
);
assert_eq!( assert_eq!(
engine.eval::<INT>( engine.eval::<INT>(
@ -71,6 +92,101 @@ fn test_for() -> Result<(), Box<EvalAltResult>> {
30 30
); );
#[cfg(not(feature = "no_float"))]
{
assert_eq!(
engine.eval::<FLOAT>(
"
let sum = 0.0;
for x in range(1.0, 10.0, 2.0) { sum += x; }
sum
"
)?,
25.0
);
assert_eq!(
engine.eval::<FLOAT>(
"
let sum = 0.0;
for x in range(10.0, 1.0, 2.0) { sum += x; }
sum
"
)?,
0.0
);
assert_eq!(
engine.eval::<FLOAT>(
"
let sum = 0.0;
for x in range(1.0, 10.0, -2.0) { sum += x; }
sum
"
)?,
0.0
);
assert_eq!(
engine.eval::<FLOAT>(
"
let sum = 0.0;
for x in range(10.0, 1.0, -2.0) { sum += x; }
sum
"
)?,
30.0
);
}
#[cfg(not(feature = "no_float"))]
#[cfg(feature = "decimal")]
{
assert_eq!(
engine.eval::<Decimal>(
"
let sum = to_decimal(0);
for x in range(to_decimal(1), to_decimal(10), to_decimal(2)) { sum += x; }
sum
"
)?,
Decimal::from(25)
);
assert_eq!(
engine.eval::<Decimal>(
"
let sum = to_decimal(0);
for x in range(to_decimal(10), to_decimal(1), to_decimal(2)) { sum += x; }
sum
"
)?,
Decimal::from(0)
);
assert_eq!(
engine.eval::<Decimal>(
"
let sum = to_decimal(0);
for x in range(to_decimal(1), to_decimal(10), to_decimal(-2)) { sum += x; }
sum
"
)?,
Decimal::from(0)
);
assert_eq!(
engine.eval::<Decimal>(
"
let sum = to_decimal(0);
for x in range(to_decimal(10), to_decimal(1), to_decimal(-2)) { sum += x; }
sum
"
)?,
Decimal::from(30)
);
}
Ok(()) Ok(())
} }