Convert some packages into plugins.

This commit is contained in:
Stephen Chung 2020-08-14 13:43:26 +08:00
parent 2495b367e5
commit c0dc47c9db
5 changed files with 361 additions and 261 deletions

View File

@ -535,45 +535,47 @@ impl Dynamic {
/// ```
#[inline(always)]
pub fn from<T: Variant + Clone>(value: T) -> Self {
let type_id = TypeId::of::<T>();
if type_id == TypeId::of::<INT>() {
if TypeId::of::<T>() == TypeId::of::<INT>() {
return <dyn Any>::downcast_ref::<INT>(&value)
.unwrap()
.clone()
.into();
}
#[cfg(not(feature = "no_float"))]
if type_id == TypeId::of::<FLOAT>() {
if TypeId::of::<T>() == TypeId::of::<FLOAT>() {
return <dyn Any>::downcast_ref::<FLOAT>(&value)
.unwrap()
.clone()
.into();
}
if type_id == TypeId::of::<bool>() {
if TypeId::of::<T>() == TypeId::of::<bool>() {
return <dyn Any>::downcast_ref::<bool>(&value)
.unwrap()
.clone()
.into();
}
if type_id == TypeId::of::<char>() {
if TypeId::of::<T>() == TypeId::of::<char>() {
return <dyn Any>::downcast_ref::<char>(&value)
.unwrap()
.clone()
.into();
}
if type_id == TypeId::of::<ImmutableString>() {
if TypeId::of::<T>() == TypeId::of::<ImmutableString>() {
return <dyn Any>::downcast_ref::<ImmutableString>(&value)
.unwrap()
.clone()
.into();
}
if type_id == TypeId::of::<()>() {
if TypeId::of::<T>() == 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<T: Variant>(self) -> Option<T> {
let type_id = TypeId::of::<T>();
match self.0 {
#[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))]
@ -673,11 +668,11 @@ impl Dynamic {
_ => (),
}
if type_id == TypeId::of::<Dynamic>() {
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
return unsafe_cast_box::<_, T>(Box::new(self)).ok().map(|v| *v);
}
if type_id == TypeId::of::<INT>() {
if TypeId::of::<T>() == TypeId::of::<INT>() {
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::<FLOAT>() {
if TypeId::of::<T>() == TypeId::of::<FLOAT>() {
return match self.0 {
Union::Float(value) => unsafe_try_cast(value),
_ => None,
};
}
if type_id == TypeId::of::<bool>() {
if TypeId::of::<T>() == TypeId::of::<bool>() {
return match self.0 {
Union::Bool(value) => unsafe_try_cast(value),
_ => None,
};
}
if type_id == TypeId::of::<ImmutableString>() {
if TypeId::of::<T>() == TypeId::of::<ImmutableString>() {
return match self.0 {
Union::Str(value) => unsafe_try_cast(value),
_ => None,
};
}
if type_id == TypeId::of::<String>() {
if TypeId::of::<T>() == TypeId::of::<String>() {
return match self.0 {
Union::Str(value) => unsafe_try_cast(value.into_owned()),
_ => None,
};
}
if type_id == TypeId::of::<char>() {
if TypeId::of::<T>() == TypeId::of::<char>() {
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::<Array>() {
if TypeId::of::<T>() == TypeId::of::<Array>() {
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::<Map>() {
if TypeId::of::<T>() == TypeId::of::<Map>() {
return match self.0 {
Union::Map(value) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v),
_ => None,
};
}
if type_id == TypeId::of::<FnPtr>() {
if TypeId::of::<T>() == TypeId::of::<FnPtr>() {
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::<T>() == 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<T: Variant + Clone>(&self) -> Option<&T> {
let type_id = TypeId::of::<T>();
if type_id == TypeId::of::<INT>() {
if TypeId::of::<T>() == TypeId::of::<INT>() {
return match &self.0 {
Union::Int(value) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
#[cfg(not(feature = "no_float"))]
if type_id == TypeId::of::<FLOAT>() {
if TypeId::of::<T>() == TypeId::of::<FLOAT>() {
return match &self.0 {
Union::Float(value) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
if type_id == TypeId::of::<bool>() {
if TypeId::of::<T>() == TypeId::of::<bool>() {
return match &self.0 {
Union::Bool(value) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
if type_id == TypeId::of::<ImmutableString>() {
if TypeId::of::<T>() == TypeId::of::<ImmutableString>() {
return match &self.0 {
Union::Str(value) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
if type_id == TypeId::of::<String>() {
if TypeId::of::<T>() == TypeId::of::<String>() {
return match &self.0 {
Union::Str(value) => <dyn Any>::downcast_ref::<T>(value.as_ref()),
_ => None,
};
}
if type_id == TypeId::of::<char>() {
if TypeId::of::<T>() == TypeId::of::<char>() {
return match &self.0 {
Union::Char(value) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
#[cfg(not(feature = "no_index"))]
if type_id == TypeId::of::<Array>() {
if TypeId::of::<T>() == TypeId::of::<Array>() {
return match &self.0 {
Union::Array(value) => <dyn Any>::downcast_ref::<T>(value.as_ref()),
_ => None,
};
}
#[cfg(not(feature = "no_object"))]
if type_id == TypeId::of::<Map>() {
if TypeId::of::<T>() == TypeId::of::<Map>() {
return match &self.0 {
Union::Map(value) => <dyn Any>::downcast_ref::<T>(value.as_ref()),
_ => None,
};
}
if type_id == TypeId::of::<FnPtr>() {
if TypeId::of::<T>() == TypeId::of::<FnPtr>() {
return match &self.0 {
Union::FnPtr(value) => <dyn Any>::downcast_ref::<T>(value.as_ref()),
_ => None,
};
}
if type_id == TypeId::of::<()>() {
if TypeId::of::<T>() == TypeId::of::<()>() {
return match &self.0 {
Union::Unit(value) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
if type_id == TypeId::of::<Dynamic>() {
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
return <dyn Any>::downcast_ref::<T>(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<T: Variant + Clone>(&mut self) -> Option<&mut T> {
let type_id = TypeId::of::<T>();
if type_id == TypeId::of::<INT>() {
if TypeId::of::<T>() == TypeId::of::<INT>() {
return match &mut self.0 {
Union::Int(value) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
#[cfg(not(feature = "no_float"))]
if type_id == TypeId::of::<FLOAT>() {
if TypeId::of::<T>() == TypeId::of::<FLOAT>() {
return match &mut self.0 {
Union::Float(value) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
if type_id == TypeId::of::<bool>() {
if TypeId::of::<T>() == TypeId::of::<bool>() {
return match &mut self.0 {
Union::Bool(value) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
if type_id == TypeId::of::<ImmutableString>() {
if TypeId::of::<T>() == TypeId::of::<ImmutableString>() {
return match &mut self.0 {
Union::Str(value) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
if type_id == TypeId::of::<char>() {
if TypeId::of::<T>() == TypeId::of::<char>() {
return match &mut self.0 {
Union::Char(value) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
#[cfg(not(feature = "no_index"))]
if type_id == TypeId::of::<Array>() {
if TypeId::of::<T>() == TypeId::of::<Array>() {
return match &mut self.0 {
Union::Array(value) => <dyn Any>::downcast_mut::<T>(value.as_mut()),
_ => None,
};
}
#[cfg(not(feature = "no_object"))]
if type_id == TypeId::of::<Map>() {
if TypeId::of::<T>() == TypeId::of::<Map>() {
return match &mut self.0 {
Union::Map(value) => <dyn Any>::downcast_mut::<T>(value.as_mut()),
_ => None,
};
}
if type_id == TypeId::of::<FnPtr>() {
if TypeId::of::<T>() == TypeId::of::<FnPtr>() {
return match &mut self.0 {
Union::FnPtr(value) => <dyn Any>::downcast_mut::<T>(value.as_mut()),
_ => None,
};
}
if type_id == TypeId::of::<()>() {
if TypeId::of::<T>() == TypeId::of::<()>() {
return match &mut self.0 {
Union::Unit(value) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
if type_id == TypeId::of::<Dynamic>() {
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
return <dyn Any>::downcast_mut::<T>(self);
}

View File

@ -1,65 +1,126 @@
use crate::def_package;
use crate::module::FuncReturn;
use crate::plugin::*;
// Comparison operators
pub fn lt<T: PartialOrd>(x: T, y: T) -> FuncReturn<bool> {
Ok(x < y)
}
pub fn lte<T: PartialOrd>(x: T, y: T) -> FuncReturn<bool> {
Ok(x <= y)
}
pub fn gt<T: PartialOrd>(x: T, y: T) -> FuncReturn<bool> {
Ok(x > y)
}
pub fn gte<T: PartialOrd>(x: T, y: T) -> FuncReturn<bool> {
Ok(x >= y)
}
pub fn eq<T: PartialEq>(x: T, y: T) -> FuncReturn<bool> {
Ok(x == y)
}
pub fn ne<T: PartialEq>(x: T, y: T) -> FuncReturn<bool> {
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<bool> {
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<T: PartialOrd>(x: T, y: T) -> bool {
x < y
}
#[inline(always)]
pub fn lte<T: PartialOrd>(x: T, y: T) -> bool {
x <= y
}
#[inline(always)]
pub fn gt<T: PartialOrd>(x: T, y: T) -> bool {
x > y
}
#[inline(always)]
pub fn gte<T: PartialOrd>(x: T, y: T) -> bool {
x >= y
}
#[inline(always)]
pub fn eq<T: PartialEq>(x: T, y: T) -> bool {
x == y
}
#[inline(always)]
pub fn ne<T: PartialEq>(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);
}

View File

@ -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()
}
}

View File

@ -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<Dynamic, Box<EvalAltResult>> {
let seconds = timestamp.elapsed().as_secs();
lib.set_fn_2("<", lt::<Instant>);
lib.set_fn_2("<=", lte::<Instant>);
lib.set_fn_2(">", gt::<Instant>);
lib.set_fn_2(">=", gte::<Instant>);
lib.set_fn_2("==", eq::<Instant>);
lib.set_fn_2("!=", ne::<Instant>);
#[cfg(not(feature = "no_float"))]
fn elapsed (timestamp: &mut Instant) -> Result<FLOAT, Box<EvalAltResult>> {
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<INT, Box<EvalAltResult>> {
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<Dynamic, Box<EvalAltResult>> {
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
}
}

View File

@ -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<T: std::fmt::Display>(n: T) -> String {
format!("{} kitties", n)
}
gen_unary_functions!(greet = make_greeting(INT, bool, char) -> String);
#[test]
fn test_plugins_package() -> Result<(), Box<EvalAltResult>> {
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::<INT>("let a = [1, 2, 3]; len(a, 2)")?, 6);
assert_eq!(
engine.eval::<String>("let a = [1, 2, 3]; greet(len(a, 2))")?,