diff --git a/src/any.rs b/src/any.rs index c154a682..7b1fa184 100644 --- a/src/any.rs +++ b/src/any.rs @@ -535,45 +535,47 @@ impl Dynamic { /// ``` #[inline(always)] pub fn from(value: T) -> Self { - let type_id = TypeId::of::(); - - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return ::downcast_ref::(&value) .unwrap() .clone() .into(); } #[cfg(not(feature = "no_float"))] - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return ::downcast_ref::(&value) .unwrap() .clone() .into(); } - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return ::downcast_ref::(&value) .unwrap() .clone() .into(); } - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return ::downcast_ref::(&value) .unwrap() .clone() .into(); } - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return ::downcast_ref::(&value) .unwrap() .clone() .into(); } - if type_id == TypeId::of::<()>() { + if TypeId::of::() == TypeId::of::<()>() { return ().into(); } let mut boxed = Box::new(value); + boxed = match unsafe_cast_box::<_, Dynamic>(boxed) { + Ok(d) => return *d, + Err(val) => val, + }; boxed = match unsafe_cast_box::<_, String>(boxed) { Ok(s) => return (*s).into(), Err(val) => val, @@ -599,11 +601,6 @@ impl Dynamic { Err(val) => val, }; - boxed = match unsafe_cast_box::<_, Dynamic>(boxed) { - Ok(d) => return *d, - Err(val) => val, - }; - Self(Union::Variant(Box::new(boxed))) } @@ -660,8 +657,6 @@ impl Dynamic { /// ``` #[inline(always)] pub fn try_cast(self) -> Option { - let type_id = TypeId::of::(); - match self.0 { #[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "sync"))] @@ -673,11 +668,11 @@ impl Dynamic { _ => (), } - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return unsafe_cast_box::<_, T>(Box::new(self)).ok().map(|v| *v); } - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match self.0 { Union::Int(value) => unsafe_try_cast(value), _ => None, @@ -685,35 +680,35 @@ impl Dynamic { } #[cfg(not(feature = "no_float"))] - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match self.0 { Union::Float(value) => unsafe_try_cast(value), _ => None, }; } - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match self.0 { Union::Bool(value) => unsafe_try_cast(value), _ => None, }; } - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match self.0 { Union::Str(value) => unsafe_try_cast(value), _ => None, }; } - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match self.0 { Union::Str(value) => unsafe_try_cast(value.into_owned()), _ => None, }; } - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match self.0 { Union::Char(value) => unsafe_try_cast(value), _ => None, @@ -721,7 +716,7 @@ impl Dynamic { } #[cfg(not(feature = "no_index"))] - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match self.0 { Union::Array(value) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v), _ => None, @@ -729,21 +724,21 @@ impl Dynamic { } #[cfg(not(feature = "no_object"))] - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match self.0 { Union::Map(value) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v), _ => None, }; } - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match self.0 { Union::FnPtr(value) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v), _ => None, }; } - if type_id == TypeId::of::<()>() { + if TypeId::of::() == TypeId::of::<()>() { return match self.0 { Union::Unit(value) => unsafe_try_cast(value), _ => None, @@ -928,72 +923,70 @@ impl Dynamic { /// Returns `None` if the cast fails, or if the value is shared. #[inline(always)] pub(crate) fn downcast_ref(&self) -> Option<&T> { - let type_id = TypeId::of::(); - - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match &self.0 { Union::Int(value) => ::downcast_ref::(value), _ => None, }; } #[cfg(not(feature = "no_float"))] - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match &self.0 { Union::Float(value) => ::downcast_ref::(value), _ => None, }; } - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match &self.0 { Union::Bool(value) => ::downcast_ref::(value), _ => None, }; } - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match &self.0 { Union::Str(value) => ::downcast_ref::(value), _ => None, }; } - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match &self.0 { Union::Str(value) => ::downcast_ref::(value.as_ref()), _ => None, }; } - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match &self.0 { Union::Char(value) => ::downcast_ref::(value), _ => None, }; } #[cfg(not(feature = "no_index"))] - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match &self.0 { Union::Array(value) => ::downcast_ref::(value.as_ref()), _ => None, }; } #[cfg(not(feature = "no_object"))] - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match &self.0 { Union::Map(value) => ::downcast_ref::(value.as_ref()), _ => None, }; } - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match &self.0 { Union::FnPtr(value) => ::downcast_ref::(value.as_ref()), _ => None, }; } - if type_id == TypeId::of::<()>() { + if TypeId::of::() == TypeId::of::<()>() { return match &self.0 { Union::Unit(value) => ::downcast_ref::(value), _ => None, }; } - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return ::downcast_ref::(self); } @@ -1011,66 +1004,64 @@ impl Dynamic { /// Returns `None` if the cast fails, or if the value is shared. #[inline(always)] pub(crate) fn downcast_mut(&mut self) -> Option<&mut T> { - let type_id = TypeId::of::(); - - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match &mut self.0 { Union::Int(value) => ::downcast_mut::(value), _ => None, }; } #[cfg(not(feature = "no_float"))] - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match &mut self.0 { Union::Float(value) => ::downcast_mut::(value), _ => None, }; } - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match &mut self.0 { Union::Bool(value) => ::downcast_mut::(value), _ => None, }; } - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match &mut self.0 { Union::Str(value) => ::downcast_mut::(value), _ => None, }; } - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match &mut self.0 { Union::Char(value) => ::downcast_mut::(value), _ => None, }; } #[cfg(not(feature = "no_index"))] - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match &mut self.0 { Union::Array(value) => ::downcast_mut::(value.as_mut()), _ => None, }; } #[cfg(not(feature = "no_object"))] - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match &mut self.0 { Union::Map(value) => ::downcast_mut::(value.as_mut()), _ => None, }; } - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return match &mut self.0 { Union::FnPtr(value) => ::downcast_mut::(value.as_mut()), _ => None, }; } - if type_id == TypeId::of::<()>() { + if TypeId::of::() == TypeId::of::<()>() { return match &mut self.0 { Union::Unit(value) => ::downcast_mut::(value), _ => None, }; } - if type_id == TypeId::of::() { + if TypeId::of::() == TypeId::of::() { return ::downcast_mut::(self); } diff --git a/src/packages/logic.rs b/src/packages/logic.rs index 6c70a38c..22f60d93 100644 --- a/src/packages/logic.rs +++ b/src/packages/logic.rs @@ -1,65 +1,126 @@ use crate::def_package; -use crate::module::FuncReturn; +use crate::plugin::*; -// Comparison operators -pub fn lt(x: T, y: T) -> FuncReturn { - Ok(x < y) -} -pub fn lte(x: T, y: T) -> FuncReturn { - Ok(x <= y) -} -pub fn gt(x: T, y: T) -> FuncReturn { - Ok(x > y) -} -pub fn gte(x: T, y: T) -> FuncReturn { - Ok(x >= y) -} -pub fn eq(x: T, y: T) -> FuncReturn { - Ok(x == y) -} -pub fn ne(x: T, y: T) -> FuncReturn { - Ok(x != y) +macro_rules! gen_cmp_functions { + ($op_name:tt = $op_fn:ident ( $($arg_type:ident),+ ) -> $return_type:ident) => { + pub mod $op_fn { $( + pub mod $arg_type { + use crate::plugin::*; + + pub const OP_NAME: &'static str = $op_name; + + #[export_fn] + pub fn cmp_func(x: $arg_type, y: $arg_type) -> $return_type { + super::super::super::$op_fn(x, y) + } + } + )* } + } } -// Logic operators -fn not(x: bool) -> FuncReturn { - Ok(!x) -} - -macro_rules! reg_op { - ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => { - $( $lib.set_fn_2($op, $func::<$par>); )* - }; +macro_rules! reg_functions { + ($mod_name:ident += $root:ident :: $op_name:ident ( $($arg_type:ident),+ )) => { + $(set_exported_fn!($mod_name, $root::$op_name::$arg_type::OP_NAME, $root::$op_name::$arg_type::cmp_func);)* + } } def_package!(crate:LogicPackage:"Logical operators.", lib, { - if cfg!(not(feature = "only_i32")) && cfg!(not(feature = "only_i64")) { - reg_op!(lib, "<", lt, i8, u8, i16, u16, i32, u32, u64); - reg_op!(lib, "<=", lte, i8, u8, i16, u16, i32, u32, u64); - reg_op!(lib, ">", gt, i8, u8, i16, u16, i32, u32, u64); - reg_op!(lib, ">=", gte, i8, u8, i16, u16, i32, u32, u64); - reg_op!(lib, "==", eq, i8, u8, i16, u16, i32, u32, u64); - reg_op!(lib, "!=", ne, i8, u8, i16, u16, i32, u32, u64); + #[cfg(not(feature = "only_i32"))] + #[cfg(not(feature = "only_i64"))] + { + reg_functions!(lib += cmp::lt(i8, u8, i16, u16, i32, u32, u64)); + reg_functions!(lib += cmp::lte(i8, u8, i16, u16, i32, u32, u64)); + reg_functions!(lib += cmp::gt(i8, u8, i16, u16, i32, u32, u64)); + reg_functions!(lib += cmp::gte(i8, u8, i16, u16, i32, u32, u64)); + reg_functions!(lib += cmp::eq(i8, u8, i16, u16, i32, u32, u64)); + reg_functions!(lib += cmp::ne(i8, u8, i16, u16, i32, u32, u64)); - if cfg!(not(target_arch = "wasm32")) { - reg_op!(lib, "<", lt, i128, u128); - reg_op!(lib, "<=", lte, i128, u128); - reg_op!(lib, ">", gt, i128, u128); - reg_op!(lib, ">=", gte, i128, u128); - reg_op!(lib, "==", eq, i128, u128); - reg_op!(lib, "!=", ne, i128, u128); + #[cfg(not(target_arch = "wasm32"))] + { + reg_functions!(lib += cmp_128::lt(i128, u128)); + reg_functions!(lib += cmp_128::lte(i128, u128)); + reg_functions!(lib += cmp_128::gt(i128, u128)); + reg_functions!(lib += cmp_128::gte(i128, u128)); + reg_functions!(lib += cmp_128::eq(i128, u128)); + reg_functions!(lib += cmp_128::ne(i128, u128)); } } #[cfg(not(feature = "no_float"))] { - reg_op!(lib, "<", lt, f32); - reg_op!(lib, "<=", lte, f32); - reg_op!(lib, ">", gt, f32); - reg_op!(lib, ">=", gte, f32); - reg_op!(lib, "==", eq, f32); - reg_op!(lib, "!=", ne, f32); + reg_functions!(lib += cmp_float::lt(f32)); + reg_functions!(lib += cmp_float::lte(f32)); + reg_functions!(lib += cmp_float::gt(f32)); + reg_functions!(lib += cmp_float::gte(f32)); + reg_functions!(lib += cmp_float::eq(f32)); + reg_functions!(lib += cmp_float::ne(f32)); } - lib.set_fn_1("!", not); + set_exported_fn!(lib, "!", not); }); + +// Comparison operators +#[inline(always)] +pub fn lt(x: T, y: T) -> bool { + x < y +} +#[inline(always)] +pub fn lte(x: T, y: T) -> bool { + x <= y +} +#[inline(always)] +pub fn gt(x: T, y: T) -> bool { + x > y +} +#[inline(always)] +pub fn gte(x: T, y: T) -> bool { + x >= y +} +#[inline(always)] +pub fn eq(x: T, y: T) -> bool { + x == y +} +#[inline(always)] +pub fn ne(x: T, y: T) -> bool { + x != y +} + +// Logic operators +#[export_fn] +#[inline(always)] +fn not(x: bool) -> bool { + !x +} + +#[cfg(not(feature = "only_i32"))] +#[cfg(not(feature = "only_i64"))] +mod cmp { + gen_cmp_functions!("<" = lt(i8, u8, i16, u16, i32, u32, u64) -> bool); + gen_cmp_functions!("<=" = lte(i8, u8, i16, u16, i32, u32, u64) -> bool); + gen_cmp_functions!(">" = gt(i8, u8, i16, u16, i32, u32, u64) -> bool); + gen_cmp_functions!(">=" = gte(i8, u8, i16, u16, i32, u32, u64) -> bool); + gen_cmp_functions!("==" = eq(i8, u8, i16, u16, i32, u32, u64) -> bool); + gen_cmp_functions!("!=" = ne(i8, u8, i16, u16, i32, u32, u64) -> bool); +} + +#[cfg(not(feature = "only_i32"))] +#[cfg(not(feature = "only_i64"))] +#[cfg(not(target_arch = "wasm32"))] +mod cmp_128 { + gen_cmp_functions!("<" = lt(i128, u128) -> bool); + gen_cmp_functions!("<=" = lte(i128, u128) -> bool); + gen_cmp_functions!(">" = gt(i128, u128) -> bool); + gen_cmp_functions!(">=" = gte(i128, u128) -> bool); + gen_cmp_functions!("==" = eq(i128, u128) -> bool); + gen_cmp_functions!("!=" = ne(i128, u128) -> bool); +} + +#[cfg(not(feature = "no_float"))] +mod cmp_float { + gen_cmp_functions!("<" = lt(f32) -> bool); + gen_cmp_functions!("<=" = lte(f32) -> bool); + gen_cmp_functions!(">" = gt(f32) -> bool); + gen_cmp_functions!(">=" = gte(f32) -> bool); + gen_cmp_functions!("==" = eq(f32) -> bool); + gen_cmp_functions!("!=" = ne(f32) -> bool); +} diff --git a/src/packages/math_basic.rs b/src/packages/math_basic.rs index 389a7bec..322626e7 100644 --- a/src/packages/math_basic.rs +++ b/src/packages/math_basic.rs @@ -1,5 +1,4 @@ use crate::def_package; -use crate::module::Module; use crate::parser::INT; use crate::plugin::*; @@ -24,99 +23,6 @@ pub const MAX_INT: INT = i32::MAX; pub const MAX_INT: INT = i64::MAX; def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, { - init_module(lib); -}); - -#[cfg(not(feature = "no_float"))] -#[export_module] -mod trig { - use crate::parser::FLOAT; - - pub fn sin(x: FLOAT) -> FLOAT { - x.to_radians().sin() - } - pub fn cos(x: FLOAT) -> FLOAT { - x.to_radians().cos() - } - pub fn tan(x: FLOAT) -> FLOAT { - x.to_radians().tan() - } - pub fn sinh(x: FLOAT) -> FLOAT { - x.to_radians().sinh() - } - pub fn cosh(x: FLOAT) -> FLOAT { - x.to_radians().cosh() - } - pub fn tanh(x: FLOAT) -> FLOAT { - x.to_radians().tanh() - } - pub fn asin(x: FLOAT) -> FLOAT { - x.asin().to_degrees() - } - pub fn acos(x: FLOAT) -> FLOAT { - x.acos().to_degrees() - } - pub fn atan(x: FLOAT) -> FLOAT { - x.atan().to_degrees() - } - pub fn asinh(x: FLOAT) -> FLOAT { - x.asinh().to_degrees() - } - pub fn acosh(x: FLOAT) -> FLOAT { - x.acosh().to_degrees() - } - pub fn atanh(x: FLOAT) -> FLOAT { - x.atanh().to_degrees() - } -} - -#[cfg(not(feature = "no_float"))] -#[export_module] -mod float { - use crate::parser::FLOAT; - - pub fn sqrt(x: FLOAT) -> FLOAT { - x.sqrt() - } - pub fn exp(x: FLOAT) -> FLOAT { - x.exp() - } - pub fn ln(x: FLOAT) -> FLOAT { - x.ln() - } - pub fn log(x: FLOAT, base: FLOAT) -> FLOAT { - x.log(base) - } - pub fn log10(x: FLOAT) -> FLOAT { - x.log10() - } - pub fn floor(x: FLOAT) -> FLOAT { - x.floor() - } - pub fn ceiling(x: FLOAT) -> FLOAT { - x.ceil() - } - pub fn round(x: FLOAT) -> FLOAT { - x.ceil() - } - pub fn int(x: FLOAT) -> FLOAT { - x.trunc() - } - pub fn fraction(x: FLOAT) -> FLOAT { - x.fract() - } - pub fn is_nan(x: FLOAT) -> bool { - x.is_nan() - } - pub fn is_finite(x: FLOAT) -> bool { - x.is_finite() - } - pub fn is_infinite(x: FLOAT) -> bool { - x.is_infinite() - } -} - -fn init_module(lib: &mut Module) { #[cfg(not(feature = "no_float"))] { // Floating point functions @@ -209,4 +115,93 @@ fn init_module(lib: &mut Module) { lib.set_fn_1("to_int", |x: f64| Ok(x as INT)); } } +}); + +#[cfg(not(feature = "no_float"))] +#[export_module] +mod trig { + use crate::parser::FLOAT; + + pub fn sin(x: FLOAT) -> FLOAT { + x.to_radians().sin() + } + pub fn cos(x: FLOAT) -> FLOAT { + x.to_radians().cos() + } + pub fn tan(x: FLOAT) -> FLOAT { + x.to_radians().tan() + } + pub fn sinh(x: FLOAT) -> FLOAT { + x.to_radians().sinh() + } + pub fn cosh(x: FLOAT) -> FLOAT { + x.to_radians().cosh() + } + pub fn tanh(x: FLOAT) -> FLOAT { + x.to_radians().tanh() + } + pub fn asin(x: FLOAT) -> FLOAT { + x.asin().to_degrees() + } + pub fn acos(x: FLOAT) -> FLOAT { + x.acos().to_degrees() + } + pub fn atan(x: FLOAT) -> FLOAT { + x.atan().to_degrees() + } + pub fn asinh(x: FLOAT) -> FLOAT { + x.asinh().to_degrees() + } + pub fn acosh(x: FLOAT) -> FLOAT { + x.acosh().to_degrees() + } + pub fn atanh(x: FLOAT) -> FLOAT { + x.atanh().to_degrees() + } +} + +#[cfg(not(feature = "no_float"))] +#[export_module] +mod float { + use crate::parser::FLOAT; + + pub fn sqrt(x: FLOAT) -> FLOAT { + x.sqrt() + } + pub fn exp(x: FLOAT) -> FLOAT { + x.exp() + } + pub fn ln(x: FLOAT) -> FLOAT { + x.ln() + } + pub fn log(x: FLOAT, base: FLOAT) -> FLOAT { + x.log(base) + } + pub fn log10(x: FLOAT) -> FLOAT { + x.log10() + } + pub fn floor(x: FLOAT) -> FLOAT { + x.floor() + } + pub fn ceiling(x: FLOAT) -> FLOAT { + x.ceil() + } + pub fn round(x: FLOAT) -> FLOAT { + x.ceil() + } + pub fn int(x: FLOAT) -> FLOAT { + x.trunc() + } + pub fn fraction(x: FLOAT) -> FLOAT { + x.fract() + } + pub fn is_nan(x: FLOAT) -> bool { + x.is_nan() + } + pub fn is_finite(x: FLOAT) -> bool { + x.is_finite() + } + pub fn is_infinite(x: FLOAT) -> bool { + x.is_infinite() + } } diff --git a/src/packages/time_basic.rs b/src/packages/time_basic.rs index 34f6821d..61843b14 100644 --- a/src/packages/time_basic.rs +++ b/src/packages/time_basic.rs @@ -6,6 +6,8 @@ use super::logic::{eq, gt, gte, lt, lte, ne}; use super::math_basic::MAX_INT; use crate::def_package; +use crate::engine::make_getter; +use crate::plugin::*; use crate::result::EvalAltResult; #[cfg(not(feature = "no_float"))] @@ -26,83 +28,112 @@ use instant::Instant; def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, { // Register date/time functions - lib.set_fn_0("timestamp", || Ok(Instant::now())); + set_exported_fn!(lib, "timestamp", create_timestamp); + set_exported_fn!(lib, "elapsed", elapsed); - lib.set_fn_2( - "-", - |ts1: Instant, ts2: Instant| { - if ts2 > ts1 { - #[cfg(not(feature = "no_float"))] - return Ok(-(ts2 - ts1).as_secs_f64()); + #[cfg(not(feature = "no_object"))] + set_exported_fn!(lib, make_getter("elapsed"), elapsed); - #[cfg(feature = "no_float")] - { - let seconds = (ts2 - ts1).as_secs(); + set_exported_fn!(lib, "-", time_diff); - #[cfg(not(feature = "unchecked"))] - if seconds > (MAX_INT as u64) { - return EvalAltResult::ErrorArithmetic( - format!( - "Integer overflow for timestamp duration: {}", - -(seconds as i64) - ), - Position::none(), - ).into(); - } + //lib.merge(&exported_module!(time_compare)); - return Ok(-(seconds as INT)); - } - } else { - #[cfg(not(feature = "no_float"))] - return Ok((ts1 - ts2).as_secs_f64()); + lib.set_fn_2("<", |x:Instant, y:Instant| Ok(lt(x, y))); + lib.set_fn_2("<=", |x:Instant, y:Instant| Ok(lte(x, y))); + lib.set_fn_2(">", |x:Instant, y:Instant| Ok(gt(x, y))); + lib.set_fn_2(">=", |x:Instant, y:Instant| Ok(gte(x, y))); + lib.set_fn_2("==", |x:Instant, y:Instant| Ok(eq(x, y))); + lib.set_fn_2("!=", |x:Instant, y:Instant| Ok(ne(x, y))); +}); - #[cfg(feature = "no_float")] - { - let seconds = (ts1 - ts2).as_secs(); +#[export_fn] +fn create_timestamp() -> Instant { + Instant::now() +} - #[cfg(not(feature = "unchecked"))] - if seconds > (MAX_INT as u64) { - return EvalAltResult::ErrorArithmetic( - format!("Integer overflow for timestamp duration: {}", seconds), - Position::none(), - ).into(); - } +#[cfg(not(feature = "no_float"))] +#[export_fn] +fn elapsed(timestamp: &mut Instant) -> FLOAT { + timestamp.elapsed().as_secs_f64() as FLOAT +} - return Ok(seconds as INT); - } - } - }, - ); +#[cfg(feature = "no_float")] +#[export_fn(return_raw)] +fn elapsed(timestamp: &mut Instant) -> Result> { + let seconds = timestamp.elapsed().as_secs(); - lib.set_fn_2("<", lt::); - lib.set_fn_2("<=", lte::); - lib.set_fn_2(">", gt::); - lib.set_fn_2(">=", gte::); - lib.set_fn_2("==", eq::); - lib.set_fn_2("!=", ne::); - - #[cfg(not(feature = "no_float"))] - fn elapsed (timestamp: &mut Instant) -> Result> { - Ok(timestamp.elapsed().as_secs_f64()) + #[cfg(not(feature = "unchecked"))] + if seconds > (MAX_INT as u64) { + return EvalAltResult::ErrorArithmetic( + format!("Integer overflow for timestamp.elapsed: {}", seconds), + Position::none(), + ) + .into(); } - #[cfg(feature = "no_float")] - fn elapsed (timestamp: &mut Instant) -> Result> { - let seconds = timestamp.elapsed().as_secs(); + Ok((seconds as INT).into()) +} + +#[cfg(not(feature = "no_float"))] +#[export_fn] +fn time_diff(ts1: Instant, ts2: Instant) -> FLOAT { + if ts2 > ts1 { + -(ts2 - ts1).as_secs_f64() as FLOAT + } else { + (ts1 - ts2).as_secs_f64() as FLOAT + } +} + +#[cfg(feature = "no_float")] +#[export_fn(return_raw)] +fn time_diff(ts1: Instant, ts2: Instant) -> Result> { + if ts2 > ts1 { + let seconds = (ts2 - ts1).as_secs(); #[cfg(not(feature = "unchecked"))] if seconds > (MAX_INT as u64) { return EvalAltResult::ErrorArithmetic( - format!("Integer overflow for timestamp.elapsed: {}", seconds), + format!("Integer overflow for timestamp duration: -{}", seconds), Position::none(), - ).into(); + ) + .into(); } - Ok(seconds as INT) + Ok(-(seconds as INT).into()) + } else { + let seconds = (ts1 - ts2).as_secs(); + + #[cfg(not(feature = "unchecked"))] + if seconds > (MAX_INT as u64) { + return EvalAltResult::ErrorArithmetic( + format!("Integer overflow for timestamp duration: {}", seconds), + Position::none(), + ) + .into(); + } + + Ok((seconds as INT).into()) } +} - lib.set_fn_1_mut("elapsed", elapsed); - - #[cfg(not(feature = "no_object"))] - lib.set_getter_fn("elapsed", elapsed); -}); +#[export_module] +mod time_compare { + pub fn eq(x: Instant, y: Instant) -> bool { + x == y + } + pub fn ne(x: Instant, y: Instant) -> bool { + x != y + } + pub fn lt(x: Instant, y: Instant) -> bool { + x < y + } + pub fn lte(x: Instant, y: Instant) -> bool { + x <= y + } + pub fn gt(x: Instant, y: Instant) -> bool { + x > y + } + pub fn gte(x: Instant, y: Instant) -> bool { + x >= y + } +} diff --git a/tests/plugins.rs b/tests/plugins.rs index 02fdf7c0..b6399ced 100644 --- a/tests/plugins.rs +++ b/tests/plugins.rs @@ -12,20 +12,42 @@ mod special_array_package { } } -#[export_fn] -fn make_greeting(n: INT) -> String { - format!("{} {}", n, if n > 1 { "kitties" } else { "kitty" }).into() +macro_rules! gen_unary_functions { + ($op_name:ident = $op_fn:ident ( $($arg_type:ident),+ ) -> $return_type:ident) => { + mod $op_name { $( + pub mod $arg_type { + use super::super::*; + + #[export_fn] + pub fn single(x: $arg_type) -> $return_type { + super::super::$op_fn(x) + } + } + )* } + } } +macro_rules! reg_functions { + ($mod_name:ident += $op_name:ident :: $func:ident ( $($arg_type:ident),+ )) => { + $(register_exported_fn!($mod_name, stringify!($op_name), $op_name::$arg_type::$func);)* + } +} + +fn make_greeting(n: T) -> String { + format!("{} kitties", n) +} + +gen_unary_functions!(greet = make_greeting(INT, bool, char) -> String); + #[test] fn test_plugins_package() -> Result<(), Box> { let mut engine = Engine::new(); - let mut m = exported_module!(special_array_package); - set_exported_fn!(m, "greet", make_greeting); - + let m = exported_module!(special_array_package); engine.load_package(m); + reg_functions!(engine += greet::single(INT, bool, char)); + assert_eq!(engine.eval::("let a = [1, 2, 3]; len(a, 2)")?, 6); assert_eq!( engine.eval::("let a = [1, 2, 3]; greet(len(a, 2))")?,