Use modules to implement packages.
This commit is contained in:
parent
d613764c03
commit
30e5e2f034
@ -125,9 +125,8 @@ impl Engine {
|
|||||||
/// Register an iterator adapter for a type with the `Engine`.
|
/// Register an iterator adapter for a type with the `Engine`.
|
||||||
/// This is an advanced feature.
|
/// This is an advanced feature.
|
||||||
pub fn register_iterator<T: Variant + Clone, F: IteratorCallback>(&mut self, f: F) {
|
pub fn register_iterator<T: Variant + Clone, F: IteratorCallback>(&mut self, f: F) {
|
||||||
self.base_package
|
self.global_module
|
||||||
.type_iterators
|
.set_iterator(TypeId::of::<T>(), Box::new(f));
|
||||||
.insert(TypeId::of::<T>(), Box::new(f));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register a getter function for a member of a registered type with the `Engine`.
|
/// Register a getter function for a member of a registered type with the `Engine`.
|
||||||
@ -419,7 +418,7 @@ impl Engine {
|
|||||||
/// // into function calls and operators.
|
/// // into function calls and operators.
|
||||||
/// let ast = engine.compile_scripts_with_scope(&mut scope, &[
|
/// let ast = engine.compile_scripts_with_scope(&mut scope, &[
|
||||||
/// "if x > 40", // all 'x' are replaced with 42
|
/// "if x > 40", // all 'x' are replaced with 42
|
||||||
/// "{ x } el"
|
/// "{ x } el",
|
||||||
/// "se { 0 }" // segments do not need to be valid scripts!
|
/// "se { 0 }" // segments do not need to be valid scripts!
|
||||||
/// ])?;
|
/// ])?;
|
||||||
///
|
///
|
||||||
|
@ -4,10 +4,9 @@ use crate::any::{Dynamic, Union};
|
|||||||
use crate::calc_fn_hash;
|
use crate::calc_fn_hash;
|
||||||
use crate::error::ParseErrorType;
|
use crate::error::ParseErrorType;
|
||||||
use crate::fn_native::{FnCallArgs, NativeFunctionABI, PrintCallback};
|
use crate::fn_native::{FnCallArgs, NativeFunctionABI, PrintCallback};
|
||||||
|
use crate::module::Module;
|
||||||
use crate::optimize::OptimizationLevel;
|
use crate::optimize::OptimizationLevel;
|
||||||
use crate::packages::{
|
use crate::packages::{CorePackage, Package, PackageLibrary, PackagesCollection, StandardPackage};
|
||||||
CorePackage, Package, PackageLibrary, PackageStore, PackagesCollection, StandardPackage,
|
|
||||||
};
|
|
||||||
use crate::parser::{Expr, FnAccess, FnDef, ReturnType, SharedFnDef, Stmt, AST};
|
use crate::parser::{Expr, FnAccess, FnDef, ReturnType, SharedFnDef, Stmt, AST};
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
||||||
@ -15,7 +14,7 @@ use crate::token::Position;
|
|||||||
use crate::utils::{StaticVec, EMPTY_TYPE_ID};
|
use crate::utils::{StaticVec, EMPTY_TYPE_ID};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
use crate::module::{resolvers, Module, ModuleRef, ModuleResolver};
|
use crate::module::{resolvers, ModuleRef, ModuleResolver};
|
||||||
|
|
||||||
#[cfg(feature = "no_module")]
|
#[cfg(feature = "no_module")]
|
||||||
use crate::parser::ModuleRef;
|
use crate::parser::ModuleRef;
|
||||||
@ -277,13 +276,15 @@ impl DerefMut for FunctionsLib {
|
|||||||
///
|
///
|
||||||
/// Currently, `Engine` is neither `Send` nor `Sync`. Turn on the `sync` feature to make it `Send + Sync`.
|
/// Currently, `Engine` is neither `Send` nor `Sync`. Turn on the `sync` feature to make it `Send + Sync`.
|
||||||
pub struct Engine {
|
pub struct Engine {
|
||||||
/// A collection of all library packages loaded into the engine.
|
/// A module containing all functions directly loaded into the Engine.
|
||||||
|
pub(crate) global_module: Module,
|
||||||
|
/// A collection of all library packages loaded into the Engine.
|
||||||
pub(crate) packages: PackagesCollection,
|
pub(crate) packages: PackagesCollection,
|
||||||
/// A collection of all library packages loaded into the engine.
|
|
||||||
pub(crate) base_package: PackageStore,
|
|
||||||
/// A module resolution service.
|
/// A module resolution service.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub(crate) module_resolver: Option<Box<dyn ModuleResolver>>,
|
pub(crate) module_resolver: Option<Box<dyn ModuleResolver>>,
|
||||||
|
|
||||||
/// A hashmap mapping type names to pretty-print names.
|
/// A hashmap mapping type names to pretty-print names.
|
||||||
pub(crate) type_names: HashMap<String, String>,
|
pub(crate) type_names: HashMap<String, String>,
|
||||||
|
|
||||||
@ -305,7 +306,7 @@ impl Default for Engine {
|
|||||||
// Create the new scripting Engine
|
// Create the new scripting Engine
|
||||||
let mut engine = Self {
|
let mut engine = Self {
|
||||||
packages: Default::default(),
|
packages: Default::default(),
|
||||||
base_package: Default::default(),
|
global_module: Default::default(),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
@ -450,7 +451,7 @@ impl Engine {
|
|||||||
pub fn new_raw() -> Self {
|
pub fn new_raw() -> Self {
|
||||||
Self {
|
Self {
|
||||||
packages: Default::default(),
|
packages: Default::default(),
|
||||||
base_package: Default::default(),
|
global_module: Default::default(),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
module_resolver: None,
|
module_resolver: None,
|
||||||
@ -549,8 +550,8 @@ impl Engine {
|
|||||||
|
|
||||||
// Search built-in's and external functions
|
// Search built-in's and external functions
|
||||||
if let Some(func) = self
|
if let Some(func) = self
|
||||||
.base_package
|
.global_module
|
||||||
.get_function(hashes.0)
|
.get_fn(hashes.0)
|
||||||
.or_else(|| self.packages.get_function(hashes.0))
|
.or_else(|| self.packages.get_function(hashes.0))
|
||||||
{
|
{
|
||||||
let mut backup: Dynamic = Default::default();
|
let mut backup: Dynamic = Default::default();
|
||||||
@ -725,7 +726,7 @@ impl Engine {
|
|||||||
// Has a system function an override?
|
// Has a system function an override?
|
||||||
fn has_override(&self, state: &State, hashes: (u64, u64)) -> bool {
|
fn has_override(&self, state: &State, hashes: (u64, u64)) -> bool {
|
||||||
// First check registered functions
|
// First check registered functions
|
||||||
self.base_package.contains_function(hashes.0)
|
self.global_module.contains_fn(hashes.0)
|
||||||
// Then check packages
|
// Then check packages
|
||||||
|| self.packages.contains_function(hashes.0)
|
|| self.packages.contains_function(hashes.0)
|
||||||
// Then check script-defined functions
|
// Then check script-defined functions
|
||||||
@ -1571,7 +1572,7 @@ impl Engine {
|
|||||||
let tid = iter_type.type_id();
|
let tid = iter_type.type_id();
|
||||||
|
|
||||||
if let Some(iter_fn) = self
|
if let Some(iter_fn) = self
|
||||||
.base_package
|
.global_module
|
||||||
.get_iterator(tid)
|
.get_iterator(tid)
|
||||||
.or_else(|| self.packages.get_iterator(tid))
|
.or_else(|| self.packages.get_iterator(tid))
|
||||||
{
|
{
|
||||||
|
@ -127,3 +127,10 @@ pub type SharedNativeFunction = Rc<Box<dyn NativeCallable>>;
|
|||||||
/// An external native Rust function.
|
/// An external native Rust function.
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
pub type SharedNativeFunction = Arc<Box<dyn NativeCallable>>;
|
pub type SharedNativeFunction = Arc<Box<dyn NativeCallable>>;
|
||||||
|
|
||||||
|
/// A type iterator function.
|
||||||
|
#[cfg(not(feature = "sync"))]
|
||||||
|
pub type SharedIteratorFunction = Rc<Box<IteratorFn>>;
|
||||||
|
/// An external native Rust function.
|
||||||
|
#[cfg(feature = "sync")]
|
||||||
|
pub type SharedIteratorFunction = Arc<Box<IteratorFn>>;
|
||||||
|
@ -4,10 +4,10 @@
|
|||||||
|
|
||||||
use crate::any::{Dynamic, Variant};
|
use crate::any::{Dynamic, Variant};
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::fn_native::{FnCallArgs, NativeFunction, NativeFunctionABI::*};
|
use crate::fn_native::{FnCallArgs, NativeFunctionABI::*};
|
||||||
|
use crate::parser::FnAccess;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
use crate::utils::calc_fn_spec;
|
|
||||||
|
|
||||||
use crate::stdlib::{any::TypeId, boxed::Box, iter::empty, mem, string::ToString};
|
use crate::stdlib::{any::TypeId, boxed::Box, iter::empty, mem, string::ToString};
|
||||||
|
|
||||||
@ -134,14 +134,13 @@ pub fn by_value<T: Variant + Clone>(data: &mut Dynamic) -> T {
|
|||||||
|
|
||||||
/// This macro creates a closure wrapping a registered function.
|
/// This macro creates a closure wrapping a registered function.
|
||||||
macro_rules! make_func {
|
macro_rules! make_func {
|
||||||
($fn:ident : $abi:expr ; $map:expr ; $($par:ident => $convert:expr),*) => {
|
($fn:ident : $map:expr ; $($par:ident => $convert:expr),*) => {
|
||||||
// ^ function pointer
|
// ^ function pointer
|
||||||
// ^ function ABI type
|
// ^ result mapping function
|
||||||
// ^ result mapping function
|
// ^ function parameter generic type name (A, B, C etc.)
|
||||||
// ^ function parameter generic type name (A, B, C etc.)
|
// ^ dereferencing function
|
||||||
// ^ dereferencing function
|
|
||||||
|
|
||||||
NativeFunction::new(Box::new(move |args: &mut FnCallArgs, pos: Position| {
|
Box::new(move |args: &mut FnCallArgs, pos: Position| {
|
||||||
// The arguments are assumed to be of the correct number and types!
|
// The arguments are assumed to be of the correct number and types!
|
||||||
|
|
||||||
#[allow(unused_variables, unused_mut)]
|
#[allow(unused_variables, unused_mut)]
|
||||||
@ -157,7 +156,7 @@ macro_rules! make_func {
|
|||||||
|
|
||||||
// Map the result
|
// Map the result
|
||||||
$map(r, pos)
|
$map(r, pos)
|
||||||
}), $abi);
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,9 +208,10 @@ macro_rules! def_register {
|
|||||||
> RegisterFn<FN, ($($mark,)*), RET> for Engine
|
> RegisterFn<FN, ($($mark,)*), RET> for Engine
|
||||||
{
|
{
|
||||||
fn register_fn(&mut self, name: &str, f: FN) {
|
fn register_fn(&mut self, name: &str, f: FN) {
|
||||||
let func = make_func!(f : $abi ; map_dynamic ; $($par => $clone),*);
|
self.global_module.set_fn(name.to_string(), $abi, FnAccess::Public,
|
||||||
let hash = calc_fn_spec(empty(), name, [$(TypeId::of::<$par>()),*].iter().cloned());
|
&[$(TypeId::of::<$par>()),*],
|
||||||
self.base_package.functions.insert(hash, Box::new(func));
|
make_func!(f : map_dynamic ; $($par => $clone),*)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,9 +226,10 @@ macro_rules! def_register {
|
|||||||
> RegisterDynamicFn<FN, ($($mark,)*)> for Engine
|
> RegisterDynamicFn<FN, ($($mark,)*)> for Engine
|
||||||
{
|
{
|
||||||
fn register_dynamic_fn(&mut self, name: &str, f: FN) {
|
fn register_dynamic_fn(&mut self, name: &str, f: FN) {
|
||||||
let func = make_func!(f : $abi ; map_identity ; $($par => $clone),*);
|
self.global_module.set_fn(name.to_string(), $abi, FnAccess::Public,
|
||||||
let hash = calc_fn_spec(empty(), name, [$(TypeId::of::<$par>()),*].iter().cloned());
|
&[$(TypeId::of::<$par>()),*],
|
||||||
self.base_package.functions.insert(hash, Box::new(func));
|
make_func!(f : map_identity ; $($par => $clone),*)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,9 +245,10 @@ macro_rules! def_register {
|
|||||||
> RegisterResultFn<FN, ($($mark,)*), RET> for Engine
|
> RegisterResultFn<FN, ($($mark,)*), RET> for Engine
|
||||||
{
|
{
|
||||||
fn register_result_fn(&mut self, name: &str, f: FN) {
|
fn register_result_fn(&mut self, name: &str, f: FN) {
|
||||||
let func = make_func!(f : $abi ; map_result ; $($par => $clone),*);
|
self.global_module.set_fn(name.to_string(), $abi, FnAccess::Public,
|
||||||
let hash = calc_fn_spec(empty(), name, [$(TypeId::of::<$par>()),*].iter().cloned());
|
&[$(TypeId::of::<$par>()),*],
|
||||||
self.base_package.functions.insert(hash, Box::new(func));
|
make_func!(f : map_result ; $($par => $clone),*)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,6 +93,7 @@ pub use error::{ParseError, ParseErrorType};
|
|||||||
pub use fn_call::FuncArgs;
|
pub use fn_call::FuncArgs;
|
||||||
pub use fn_native::NativeCallable;
|
pub use fn_native::NativeCallable;
|
||||||
pub use fn_register::{RegisterDynamicFn, RegisterFn, RegisterResultFn};
|
pub use fn_register::{RegisterDynamicFn, RegisterFn, RegisterResultFn};
|
||||||
|
pub use module::Module;
|
||||||
pub use parser::{AST, INT};
|
pub use parser::{AST, INT};
|
||||||
pub use result::EvalAltResult;
|
pub use result::EvalAltResult;
|
||||||
pub use scope::Scope;
|
pub use scope::Scope;
|
||||||
@ -112,7 +113,7 @@ pub use engine::Map;
|
|||||||
pub use parser::FLOAT;
|
pub use parser::FLOAT;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub use module::{Module, ModuleResolver};
|
pub use module::ModuleResolver;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub mod module_resolvers {
|
pub mod module_resolvers {
|
||||||
|
269
src/module.rs
269
src/module.rs
@ -1,12 +1,11 @@
|
|||||||
//! Module defining external-loaded modules for Rhai.
|
//! Module defining external-loaded modules for Rhai.
|
||||||
#![cfg(not(feature = "no_module"))]
|
|
||||||
|
|
||||||
use crate::any::{Dynamic, Variant};
|
use crate::any::{Dynamic, Variant};
|
||||||
use crate::calc_fn_hash;
|
use crate::calc_fn_hash;
|
||||||
use crate::engine::{Engine, FunctionsLib};
|
use crate::engine::{Engine, FunctionsLib};
|
||||||
use crate::fn_native::{
|
use crate::fn_native::{
|
||||||
FnAny, FnCallArgs, NativeCallable, NativeFunction, NativeFunctionABI, NativeFunctionABI::*,
|
FnAny, FnCallArgs, IteratorFn, NativeCallable, NativeFunction, NativeFunctionABI,
|
||||||
SharedNativeFunction,
|
NativeFunctionABI::*, SharedIteratorFunction, SharedNativeFunction,
|
||||||
};
|
};
|
||||||
use crate::parser::{FnAccess, FnDef, SharedFnDef, AST};
|
use crate::parser::{FnAccess, FnDef, SharedFnDef, AST};
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
@ -30,43 +29,17 @@ use crate::stdlib::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A trait that encapsulates a module resolution service.
|
|
||||||
#[cfg(not(feature = "sync"))]
|
|
||||||
pub trait ModuleResolver {
|
|
||||||
/// Resolve a module based on a path string.
|
|
||||||
fn resolve(
|
|
||||||
&self,
|
|
||||||
engine: &Engine,
|
|
||||||
scope: Scope,
|
|
||||||
path: &str,
|
|
||||||
pos: Position,
|
|
||||||
) -> Result<Module, Box<EvalAltResult>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A trait that encapsulates a module resolution service.
|
|
||||||
#[cfg(feature = "sync")]
|
|
||||||
pub trait ModuleResolver: Send + Sync {
|
|
||||||
/// Resolve a module based on a path string.
|
|
||||||
fn resolve(
|
|
||||||
&self,
|
|
||||||
engine: &Engine,
|
|
||||||
scope: Scope,
|
|
||||||
path: &str,
|
|
||||||
pos: Position,
|
|
||||||
) -> Result<Module, Box<EvalAltResult>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Default function access mode.
|
/// Default function access mode.
|
||||||
const DEF_ACCESS: FnAccess = FnAccess::Public;
|
const DEF_ACCESS: FnAccess = FnAccess::Public;
|
||||||
|
|
||||||
/// Return type of module-level Rust function.
|
/// Return type of module-level Rust function.
|
||||||
type FuncReturn<T> = Result<T, Box<EvalAltResult>>;
|
pub type FuncReturn<T> = Result<T, Box<EvalAltResult>>;
|
||||||
|
|
||||||
/// An imported module, which may contain variables, sub-modules,
|
/// An imported module, which may contain variables, sub-modules,
|
||||||
/// external Rust functions, and script-defined functions.
|
/// external Rust functions, and script-defined functions.
|
||||||
///
|
///
|
||||||
/// Not available under the `no_module` feature.
|
/// Not available under the `no_module` feature.
|
||||||
#[derive(Default, Clone)]
|
#[derive(Clone, Default)]
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
/// Sub-modules.
|
/// Sub-modules.
|
||||||
modules: HashMap<String, Module>,
|
modules: HashMap<String, Module>,
|
||||||
@ -88,6 +61,9 @@ pub struct Module {
|
|||||||
|
|
||||||
/// Flattened collection of all script-defined functions, including those in sub-modules.
|
/// Flattened collection of all script-defined functions, including those in sub-modules.
|
||||||
all_fn_lib: FunctionsLib,
|
all_fn_lib: FunctionsLib,
|
||||||
|
|
||||||
|
/// Iterator functions, keyed by the type producing the iterator.
|
||||||
|
type_iterators: HashMap<TypeId, SharedIteratorFunction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Module {
|
impl fmt::Debug for Module {
|
||||||
@ -176,8 +152,8 @@ impl Module {
|
|||||||
/// module.set_var("answer", 42_i64);
|
/// module.set_var("answer", 42_i64);
|
||||||
/// assert_eq!(module.get_var_value::<i64>("answer").unwrap(), 42);
|
/// assert_eq!(module.get_var_value::<i64>("answer").unwrap(), 42);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn set_var<K: Into<String>, T: Into<Dynamic>>(&mut self, name: K, value: T) {
|
pub fn set_var<K: Into<String>, T: Variant + Clone>(&mut self, name: K, value: T) {
|
||||||
self.variables.insert(name.into(), value.into());
|
self.variables.insert(name.into(), Dynamic::from(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a mutable reference to a modules-qualified variable.
|
/// Get a mutable reference to a modules-qualified variable.
|
||||||
@ -286,7 +262,7 @@ impl Module {
|
|||||||
name: String,
|
name: String,
|
||||||
abi: NativeFunctionABI,
|
abi: NativeFunctionABI,
|
||||||
access: FnAccess,
|
access: FnAccess,
|
||||||
params: Vec<TypeId>,
|
params: &[TypeId],
|
||||||
func: Box<FnAny>,
|
func: Box<FnAny>,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let hash_fn = calc_fn_hash(empty(), &name, params.iter().cloned());
|
let hash_fn = calc_fn_hash(empty(), &name, params.iter().cloned());
|
||||||
@ -298,7 +274,8 @@ impl Module {
|
|||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
let func = Arc::new(f);
|
let func = Arc::new(f);
|
||||||
|
|
||||||
self.functions.insert(hash_fn, (name, access, params, func));
|
self.functions
|
||||||
|
.insert(hash_fn, (name, access, params.to_vec(), func));
|
||||||
|
|
||||||
hash_fn
|
hash_fn
|
||||||
}
|
}
|
||||||
@ -316,7 +293,7 @@ impl Module {
|
|||||||
/// let hash = module.set_fn_0("calc", || Ok(42_i64));
|
/// let hash = module.set_fn_0("calc", || Ok(42_i64));
|
||||||
/// assert!(module.get_fn(hash).is_some());
|
/// assert!(module.get_fn(hash).is_some());
|
||||||
/// ```
|
/// ```
|
||||||
pub fn set_fn_0<K: Into<String>, T: Into<Dynamic>>(
|
pub fn set_fn_0<K: Into<String>, T: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: K,
|
name: K,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn() -> FuncReturn<T> + 'static,
|
#[cfg(not(feature = "sync"))] func: impl Fn() -> FuncReturn<T> + 'static,
|
||||||
@ -324,11 +301,11 @@ impl Module {
|
|||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |_: &mut FnCallArgs, pos| {
|
let f = move |_: &mut FnCallArgs, pos| {
|
||||||
func()
|
func()
|
||||||
.map(Into::<Dynamic>::into)
|
.map(Dynamic::from)
|
||||||
.map_err(|err| EvalAltResult::set_position(err, pos))
|
.map_err(|err| EvalAltResult::set_position(err, pos))
|
||||||
};
|
};
|
||||||
let arg_types = vec![];
|
let arg_types = [];
|
||||||
self.set_fn(name.into(), Pure, DEF_ACCESS, arg_types, Box::new(f))
|
self.set_fn(name.into(), Pure, DEF_ACCESS, &arg_types, Box::new(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a Rust function taking one parameter into the module, returning a hash key.
|
/// Set a Rust function taking one parameter into the module, returning a hash key.
|
||||||
@ -344,7 +321,7 @@ impl Module {
|
|||||||
/// let hash = module.set_fn_1("calc", |x: i64| Ok(x + 1));
|
/// let hash = module.set_fn_1("calc", |x: i64| Ok(x + 1));
|
||||||
/// assert!(module.get_fn(hash).is_some());
|
/// assert!(module.get_fn(hash).is_some());
|
||||||
/// ```
|
/// ```
|
||||||
pub fn set_fn_1<K: Into<String>, A: Variant + Clone, T: Into<Dynamic>>(
|
pub fn set_fn_1<K: Into<String>, A: Variant + Clone, T: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: K,
|
name: K,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(A) -> FuncReturn<T> + 'static,
|
#[cfg(not(feature = "sync"))] func: impl Fn(A) -> FuncReturn<T> + 'static,
|
||||||
@ -352,11 +329,11 @@ impl Module {
|
|||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |args: &mut FnCallArgs, pos| {
|
let f = move |args: &mut FnCallArgs, pos| {
|
||||||
func(mem::take(args[0]).cast::<A>())
|
func(mem::take(args[0]).cast::<A>())
|
||||||
.map(Into::<Dynamic>::into)
|
.map(Dynamic::from)
|
||||||
.map_err(|err| EvalAltResult::set_position(err, pos))
|
.map_err(|err| EvalAltResult::set_position(err, pos))
|
||||||
};
|
};
|
||||||
let arg_types = vec![TypeId::of::<A>()];
|
let arg_types = [TypeId::of::<A>()];
|
||||||
self.set_fn(name.into(), Pure, DEF_ACCESS, arg_types, Box::new(f))
|
self.set_fn(name.into(), Pure, DEF_ACCESS, &arg_types, Box::new(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a Rust function taking one mutable parameter into the module, returning a hash key.
|
/// Set a Rust function taking one mutable parameter into the module, returning a hash key.
|
||||||
@ -372,7 +349,7 @@ impl Module {
|
|||||||
/// let hash = module.set_fn_1_mut("calc", |x: &mut i64| { *x += 1; Ok(*x) });
|
/// let hash = module.set_fn_1_mut("calc", |x: &mut i64| { *x += 1; Ok(*x) });
|
||||||
/// assert!(module.get_fn(hash).is_some());
|
/// assert!(module.get_fn(hash).is_some());
|
||||||
/// ```
|
/// ```
|
||||||
pub fn set_fn_1_mut<K: Into<String>, A: Variant + Clone, T: Into<Dynamic>>(
|
pub fn set_fn_1_mut<K: Into<String>, A: Variant + Clone, T: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: K,
|
name: K,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A) -> FuncReturn<T> + 'static,
|
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A) -> FuncReturn<T> + 'static,
|
||||||
@ -380,11 +357,11 @@ impl Module {
|
|||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |args: &mut FnCallArgs, pos| {
|
let f = move |args: &mut FnCallArgs, pos| {
|
||||||
func(args[0].downcast_mut::<A>().unwrap())
|
func(args[0].downcast_mut::<A>().unwrap())
|
||||||
.map(Into::<Dynamic>::into)
|
.map(Dynamic::from)
|
||||||
.map_err(|err| EvalAltResult::set_position(err, pos))
|
.map_err(|err| EvalAltResult::set_position(err, pos))
|
||||||
};
|
};
|
||||||
let arg_types = vec![TypeId::of::<A>()];
|
let arg_types = [TypeId::of::<A>()];
|
||||||
self.set_fn(name.into(), Method, DEF_ACCESS, arg_types, Box::new(f))
|
self.set_fn(name.into(), Method, DEF_ACCESS, &arg_types, Box::new(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a Rust function taking two parameters into the module, returning a hash key.
|
/// Set a Rust function taking two parameters into the module, returning a hash key.
|
||||||
@ -402,7 +379,7 @@ impl Module {
|
|||||||
/// });
|
/// });
|
||||||
/// assert!(module.get_fn(hash).is_some());
|
/// assert!(module.get_fn(hash).is_some());
|
||||||
/// ```
|
/// ```
|
||||||
pub fn set_fn_2<K: Into<String>, A: Variant + Clone, B: Variant + Clone, T: Into<Dynamic>>(
|
pub fn set_fn_2<K: Into<String>, A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: K,
|
name: K,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(A, B) -> FuncReturn<T> + 'static,
|
#[cfg(not(feature = "sync"))] func: impl Fn(A, B) -> FuncReturn<T> + 'static,
|
||||||
@ -413,11 +390,11 @@ impl Module {
|
|||||||
let b = mem::take(args[1]).cast::<B>();
|
let b = mem::take(args[1]).cast::<B>();
|
||||||
|
|
||||||
func(a, b)
|
func(a, b)
|
||||||
.map(Into::<Dynamic>::into)
|
.map(Dynamic::from)
|
||||||
.map_err(|err| EvalAltResult::set_position(err, pos))
|
.map_err(|err| EvalAltResult::set_position(err, pos))
|
||||||
};
|
};
|
||||||
let arg_types = vec![TypeId::of::<A>(), TypeId::of::<B>()];
|
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>()];
|
||||||
self.set_fn(name.into(), Pure, DEF_ACCESS, arg_types, Box::new(f))
|
self.set_fn(name.into(), Pure, DEF_ACCESS, &arg_types, Box::new(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a Rust function taking two parameters (the first one mutable) into the module,
|
/// Set a Rust function taking two parameters (the first one mutable) into the module,
|
||||||
@ -438,7 +415,7 @@ impl Module {
|
|||||||
K: Into<String>,
|
K: Into<String>,
|
||||||
A: Variant + Clone,
|
A: Variant + Clone,
|
||||||
B: Variant + Clone,
|
B: Variant + Clone,
|
||||||
T: Into<Dynamic>,
|
T: Variant + Clone,
|
||||||
>(
|
>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: K,
|
name: K,
|
||||||
@ -450,11 +427,11 @@ impl Module {
|
|||||||
let a = args[0].downcast_mut::<A>().unwrap();
|
let a = args[0].downcast_mut::<A>().unwrap();
|
||||||
|
|
||||||
func(a, b)
|
func(a, b)
|
||||||
.map(Into::<Dynamic>::into)
|
.map(Dynamic::from)
|
||||||
.map_err(|err| EvalAltResult::set_position(err, pos))
|
.map_err(|err| EvalAltResult::set_position(err, pos))
|
||||||
};
|
};
|
||||||
let arg_types = vec![TypeId::of::<A>(), TypeId::of::<B>()];
|
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>()];
|
||||||
self.set_fn(name.into(), Method, DEF_ACCESS, arg_types, Box::new(f))
|
self.set_fn(name.into(), Method, DEF_ACCESS, &arg_types, Box::new(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a Rust function taking three parameters into the module, returning a hash key.
|
/// Set a Rust function taking three parameters into the module, returning a hash key.
|
||||||
@ -477,7 +454,7 @@ impl Module {
|
|||||||
A: Variant + Clone,
|
A: Variant + Clone,
|
||||||
B: Variant + Clone,
|
B: Variant + Clone,
|
||||||
C: Variant + Clone,
|
C: Variant + Clone,
|
||||||
T: Into<Dynamic>,
|
T: Variant + Clone,
|
||||||
>(
|
>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: K,
|
name: K,
|
||||||
@ -490,11 +467,11 @@ impl Module {
|
|||||||
let c = mem::take(args[2]).cast::<C>();
|
let c = mem::take(args[2]).cast::<C>();
|
||||||
|
|
||||||
func(a, b, c)
|
func(a, b, c)
|
||||||
.map(Into::<Dynamic>::into)
|
.map(Dynamic::from)
|
||||||
.map_err(|err| EvalAltResult::set_position(err, pos))
|
.map_err(|err| EvalAltResult::set_position(err, pos))
|
||||||
};
|
};
|
||||||
let arg_types = vec![TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
|
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
|
||||||
self.set_fn(name.into(), Pure, DEF_ACCESS, arg_types, Box::new(f))
|
self.set_fn(name.into(), Pure, DEF_ACCESS, &arg_types, Box::new(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a Rust function taking three parameters (the first one mutable) into the module,
|
/// Set a Rust function taking three parameters (the first one mutable) into the module,
|
||||||
@ -518,7 +495,7 @@ impl Module {
|
|||||||
A: Variant + Clone,
|
A: Variant + Clone,
|
||||||
B: Variant + Clone,
|
B: Variant + Clone,
|
||||||
C: Variant + Clone,
|
C: Variant + Clone,
|
||||||
T: Into<Dynamic>,
|
T: Variant + Clone,
|
||||||
>(
|
>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: K,
|
name: K,
|
||||||
@ -531,11 +508,11 @@ impl Module {
|
|||||||
let a = args[0].downcast_mut::<A>().unwrap();
|
let a = args[0].downcast_mut::<A>().unwrap();
|
||||||
|
|
||||||
func(a, b, c)
|
func(a, b, c)
|
||||||
.map(Into::<Dynamic>::into)
|
.map(Dynamic::from)
|
||||||
.map_err(|err| EvalAltResult::set_position(err, pos))
|
.map_err(|err| EvalAltResult::set_position(err, pos))
|
||||||
};
|
};
|
||||||
let arg_types = vec![TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
|
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
|
||||||
self.set_fn(name.into(), Method, DEF_ACCESS, arg_types, Box::new(f))
|
self.set_fn(name.into(), Method, DEF_ACCESS, &arg_types, Box::new(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a Rust function.
|
/// Get a Rust function.
|
||||||
@ -609,6 +586,7 @@ impl Module {
|
|||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub fn eval_ast_as_new(mut scope: Scope, ast: &AST, engine: &Engine) -> FuncReturn<Self> {
|
pub fn eval_ast_as_new(mut scope: Scope, ast: &AST, engine: &Engine) -> FuncReturn<Self> {
|
||||||
// Run the script
|
// Run the script
|
||||||
engine.eval_ast_with_scope_raw(&mut scope, &ast)?;
|
engine.eval_ast_with_scope_raw(&mut scope, &ast)?;
|
||||||
@ -722,9 +700,114 @@ impl Module {
|
|||||||
self.all_functions = functions.into_iter().collect();
|
self.all_functions = functions.into_iter().collect();
|
||||||
self.all_fn_lib = fn_lib.into();
|
self.all_fn_lib = fn_lib.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Does a type iterator exist in the module?
|
||||||
|
pub fn contains_iterator(&self, id: TypeId) -> bool {
|
||||||
|
self.type_iterators.contains_key(&id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a type iterator into the module.
|
||||||
|
pub fn set_iterator(&mut self, typ: TypeId, func: Box<IteratorFn>) {
|
||||||
|
#[cfg(not(feature = "sync"))]
|
||||||
|
self.type_iterators.insert(typ, Rc::new(func));
|
||||||
|
#[cfg(feature = "sync")]
|
||||||
|
self.type_iterators.insert(typ, Arc::new(func));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the specified type iterator.
|
||||||
|
pub fn get_iterator(&self, id: TypeId) -> Option<&SharedIteratorFunction> {
|
||||||
|
self.type_iterators.get(&id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A chain of module names to qualify a variable or function call.
|
||||||
|
/// A `u64` hash key is kept for quick search purposes.
|
||||||
|
///
|
||||||
|
/// A `StaticVec` is used because most module-level access contains only one level,
|
||||||
|
/// and it is wasteful to always allocate a `Vec` with one element.
|
||||||
|
#[derive(Clone, Eq, PartialEq, Hash, Default)]
|
||||||
|
pub struct ModuleRef(StaticVec<(String, Position)>, Option<NonZeroUsize>);
|
||||||
|
|
||||||
|
impl fmt::Debug for ModuleRef {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt::Debug::fmt(&self.0, f)?;
|
||||||
|
|
||||||
|
if let Some(index) = self.1 {
|
||||||
|
write!(f, " -> {}", index)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for ModuleRef {
|
||||||
|
type Target = StaticVec<(String, Position)>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for ModuleRef {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ModuleRef {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
for (m, _) in self.0.iter() {
|
||||||
|
write!(f, "{}{}", m, Token::DoubleColon.syntax())?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<StaticVec<(String, Position)>> for ModuleRef {
|
||||||
|
fn from(modules: StaticVec<(String, Position)>) -> Self {
|
||||||
|
Self(modules, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModuleRef {
|
||||||
|
pub(crate) fn index(&self) -> Option<NonZeroUsize> {
|
||||||
|
self.1
|
||||||
|
}
|
||||||
|
pub(crate) fn set_index(&mut self, index: Option<NonZeroUsize>) {
|
||||||
|
self.1 = index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A trait that encapsulates a module resolution service.
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
#[cfg(not(feature = "sync"))]
|
||||||
|
pub trait ModuleResolver {
|
||||||
|
/// Resolve a module based on a path string.
|
||||||
|
fn resolve(
|
||||||
|
&self,
|
||||||
|
engine: &Engine,
|
||||||
|
scope: Scope,
|
||||||
|
path: &str,
|
||||||
|
pos: Position,
|
||||||
|
) -> Result<Module, Box<EvalAltResult>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A trait that encapsulates a module resolution service.
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
#[cfg(feature = "sync")]
|
||||||
|
pub trait ModuleResolver: Send + Sync {
|
||||||
|
/// Resolve a module based on a path string.
|
||||||
|
fn resolve(
|
||||||
|
&self,
|
||||||
|
engine: &Engine,
|
||||||
|
scope: Scope,
|
||||||
|
path: &str,
|
||||||
|
pos: Position,
|
||||||
|
) -> Result<Module, Box<EvalAltResult>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Re-export module resolvers.
|
/// Re-export module resolvers.
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub mod resolvers {
|
pub mod resolvers {
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
pub use super::file::FileModuleResolver;
|
pub use super::file::FileModuleResolver;
|
||||||
@ -732,6 +815,7 @@ pub mod resolvers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Script file-based module resolver.
|
/// Script file-based module resolver.
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
mod file {
|
mod file {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -870,65 +954,8 @@ mod file {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A chain of module names to qualify a variable or function call.
|
|
||||||
/// A `u64` hash key is kept for quick search purposes.
|
|
||||||
///
|
|
||||||
/// A `StaticVec` is used because most module-level access contains only one level,
|
|
||||||
/// and it is wasteful to always allocate a `Vec` with one element.
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Default)]
|
|
||||||
pub struct ModuleRef(StaticVec<(String, Position)>, Option<NonZeroUsize>);
|
|
||||||
|
|
||||||
impl fmt::Debug for ModuleRef {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
fmt::Debug::fmt(&self.0, f)?;
|
|
||||||
|
|
||||||
if let Some(index) = self.1 {
|
|
||||||
write!(f, " -> {}", index)
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for ModuleRef {
|
|
||||||
type Target = StaticVec<(String, Position)>;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for ModuleRef {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for ModuleRef {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
for (m, _) in self.0.iter() {
|
|
||||||
write!(f, "{}{}", m, Token::DoubleColon.syntax())?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<StaticVec<(String, Position)>> for ModuleRef {
|
|
||||||
fn from(modules: StaticVec<(String, Position)>) -> Self {
|
|
||||||
Self(modules, None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ModuleRef {
|
|
||||||
pub(crate) fn index(&self) -> Option<NonZeroUsize> {
|
|
||||||
self.1
|
|
||||||
}
|
|
||||||
pub(crate) fn set_index(&mut self, index: Option<NonZeroUsize>) {
|
|
||||||
self.1 = index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Static module resolver.
|
/// Static module resolver.
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
mod stat {
|
mod stat {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -4,7 +4,8 @@ use crate::engine::{
|
|||||||
Engine, FunctionsLib, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
Engine, FunctionsLib, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
||||||
};
|
};
|
||||||
use crate::fn_native::FnCallArgs;
|
use crate::fn_native::FnCallArgs;
|
||||||
use crate::packages::{PackageStore, PackagesCollection};
|
use crate::module::Module;
|
||||||
|
use crate::packages::PackagesCollection;
|
||||||
use crate::parser::{map_dynamic_to_expr, Expr, FnDef, ReturnType, Stmt, AST};
|
use crate::parser::{map_dynamic_to_expr, Expr, FnDef, ReturnType, Stmt, AST};
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope};
|
use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope};
|
||||||
@ -112,7 +113,7 @@ impl<'a> State<'a> {
|
|||||||
/// Call a registered function
|
/// Call a registered function
|
||||||
fn call_fn(
|
fn call_fn(
|
||||||
packages: &PackagesCollection,
|
packages: &PackagesCollection,
|
||||||
base_package: &PackageStore,
|
global_module: &Module,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
args: &mut FnCallArgs,
|
args: &mut FnCallArgs,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
@ -120,8 +121,8 @@ fn call_fn(
|
|||||||
// Search built-in's and external functions
|
// Search built-in's and external functions
|
||||||
let hash = calc_fn_hash(empty(), fn_name, args.iter().map(|a| a.type_id()));
|
let hash = calc_fn_hash(empty(), fn_name, args.iter().map(|a| a.type_id()));
|
||||||
|
|
||||||
base_package
|
global_module
|
||||||
.get_function(hash)
|
.get_fn(hash)
|
||||||
.or_else(|| packages.get_function(hash))
|
.or_else(|| packages.get_function(hash))
|
||||||
.map(|func| func.call(args, pos))
|
.map(|func| func.call(args, pos))
|
||||||
.transpose()
|
.transpose()
|
||||||
@ -556,7 +557,7 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
|
|||||||
""
|
""
|
||||||
};
|
};
|
||||||
|
|
||||||
call_fn(&state.engine.packages, &state.engine.base_package, name, &mut call_args, *pos).ok()
|
call_fn(&state.engine.packages, &state.engine.global_module, name, &mut call_args, *pos).ok()
|
||||||
.and_then(|result|
|
.and_then(|result|
|
||||||
result.or_else(|| {
|
result.or_else(|| {
|
||||||
if !arg_for_type_of.is_empty() {
|
if !arg_for_type_of.is_empty() {
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
use super::{reg_binary, reg_unary};
|
|
||||||
|
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::fn_register::{map_dynamic as map, map_result as result};
|
use crate::module::FuncReturn;
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
@ -22,7 +20,7 @@ use crate::stdlib::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Checked add
|
// Checked add
|
||||||
fn add<T: Display + CheckedAdd>(x: T, y: T) -> Result<T, Box<EvalAltResult>> {
|
fn add<T: Display + CheckedAdd>(x: T, y: T) -> FuncReturn<T> {
|
||||||
x.checked_add(&y).ok_or_else(|| {
|
x.checked_add(&y).ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorArithmetic(
|
Box::new(EvalAltResult::ErrorArithmetic(
|
||||||
format!("Addition overflow: {} + {}", x, y),
|
format!("Addition overflow: {} + {}", x, y),
|
||||||
@ -31,7 +29,7 @@ fn add<T: Display + CheckedAdd>(x: T, y: T) -> Result<T, Box<EvalAltResult>> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Checked subtract
|
// Checked subtract
|
||||||
fn sub<T: Display + CheckedSub>(x: T, y: T) -> Result<T, Box<EvalAltResult>> {
|
fn sub<T: Display + CheckedSub>(x: T, y: T) -> FuncReturn<T> {
|
||||||
x.checked_sub(&y).ok_or_else(|| {
|
x.checked_sub(&y).ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorArithmetic(
|
Box::new(EvalAltResult::ErrorArithmetic(
|
||||||
format!("Subtraction underflow: {} - {}", x, y),
|
format!("Subtraction underflow: {} - {}", x, y),
|
||||||
@ -40,7 +38,7 @@ fn sub<T: Display + CheckedSub>(x: T, y: T) -> Result<T, Box<EvalAltResult>> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Checked multiply
|
// Checked multiply
|
||||||
fn mul<T: Display + CheckedMul>(x: T, y: T) -> Result<T, Box<EvalAltResult>> {
|
fn mul<T: Display + CheckedMul>(x: T, y: T) -> FuncReturn<T> {
|
||||||
x.checked_mul(&y).ok_or_else(|| {
|
x.checked_mul(&y).ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorArithmetic(
|
Box::new(EvalAltResult::ErrorArithmetic(
|
||||||
format!("Multiplication overflow: {} * {}", x, y),
|
format!("Multiplication overflow: {} * {}", x, y),
|
||||||
@ -49,7 +47,7 @@ fn mul<T: Display + CheckedMul>(x: T, y: T) -> Result<T, Box<EvalAltResult>> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Checked divide
|
// Checked divide
|
||||||
fn div<T>(x: T, y: T) -> Result<T, Box<EvalAltResult>>
|
fn div<T>(x: T, y: T) -> FuncReturn<T>
|
||||||
where
|
where
|
||||||
T: Display + CheckedDiv + PartialEq + Zero,
|
T: Display + CheckedDiv + PartialEq + Zero,
|
||||||
{
|
{
|
||||||
@ -69,7 +67,7 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Checked negative - e.g. -(i32::MIN) will overflow i32::MAX
|
// Checked negative - e.g. -(i32::MIN) will overflow i32::MAX
|
||||||
fn neg<T: Display + CheckedNeg>(x: T) -> Result<T, Box<EvalAltResult>> {
|
fn neg<T: Display + CheckedNeg>(x: T) -> FuncReturn<T> {
|
||||||
x.checked_neg().ok_or_else(|| {
|
x.checked_neg().ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorArithmetic(
|
Box::new(EvalAltResult::ErrorArithmetic(
|
||||||
format!("Negation overflow: -{}", x),
|
format!("Negation overflow: -{}", x),
|
||||||
@ -78,7 +76,7 @@ fn neg<T: Display + CheckedNeg>(x: T) -> Result<T, Box<EvalAltResult>> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Checked absolute
|
// Checked absolute
|
||||||
fn abs<T: Display + CheckedNeg + PartialOrd + Zero>(x: T) -> Result<T, Box<EvalAltResult>> {
|
fn abs<T: Display + CheckedNeg + PartialOrd + Zero>(x: T) -> FuncReturn<T> {
|
||||||
// FIX - We don't use Signed::abs() here because, contrary to documentation, it panics
|
// FIX - We don't use Signed::abs() here because, contrary to documentation, it panics
|
||||||
// when the number is ::MIN instead of returning ::MIN itself.
|
// when the number is ::MIN instead of returning ::MIN itself.
|
||||||
if x >= <T as Zero>::zero() {
|
if x >= <T as Zero>::zero() {
|
||||||
@ -93,49 +91,49 @@ fn abs<T: Display + CheckedNeg + PartialOrd + Zero>(x: T) -> Result<T, Box<EvalA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Unchecked add - may panic on overflow
|
// Unchecked add - may panic on overflow
|
||||||
fn add_u<T: Add>(x: T, y: T) -> <T as Add>::Output {
|
fn add_u<T: Add>(x: T, y: T) -> FuncReturn<<T as Add>::Output> {
|
||||||
x + y
|
Ok(x + y)
|
||||||
}
|
}
|
||||||
// Unchecked subtract - may panic on underflow
|
// Unchecked subtract - may panic on underflow
|
||||||
fn sub_u<T: Sub>(x: T, y: T) -> <T as Sub>::Output {
|
fn sub_u<T: Sub>(x: T, y: T) -> FuncReturn<<T as Sub>::Output> {
|
||||||
x - y
|
Ok(x - y)
|
||||||
}
|
}
|
||||||
// Unchecked multiply - may panic on overflow
|
// Unchecked multiply - may panic on overflow
|
||||||
fn mul_u<T: Mul>(x: T, y: T) -> <T as Mul>::Output {
|
fn mul_u<T: Mul>(x: T, y: T) -> FuncReturn<<T as Mul>::Output> {
|
||||||
x * y
|
Ok(x * y)
|
||||||
}
|
}
|
||||||
// Unchecked divide - may panic when dividing by zero
|
// Unchecked divide - may panic when dividing by zero
|
||||||
fn div_u<T: Div>(x: T, y: T) -> <T as Div>::Output {
|
fn div_u<T: Div>(x: T, y: T) -> FuncReturn<<T as Div>::Output> {
|
||||||
x / y
|
Ok(x / y)
|
||||||
}
|
}
|
||||||
// Unchecked negative - may panic on overflow
|
// Unchecked negative - may panic on overflow
|
||||||
fn neg_u<T: Neg>(x: T) -> <T as Neg>::Output {
|
fn neg_u<T: Neg>(x: T) -> FuncReturn<<T as Neg>::Output> {
|
||||||
-x
|
Ok(-x)
|
||||||
}
|
}
|
||||||
// Unchecked absolute - may panic on overflow
|
// Unchecked absolute - may panic on overflow
|
||||||
fn abs_u<T>(x: T) -> <T as Neg>::Output
|
fn abs_u<T>(x: T) -> FuncReturn<<T as Neg>::Output>
|
||||||
where
|
where
|
||||||
T: Neg + PartialOrd + Default + Into<<T as Neg>::Output>,
|
T: Neg + PartialOrd + Default + Into<<T as Neg>::Output>,
|
||||||
{
|
{
|
||||||
// Numbers should default to zero
|
// Numbers should default to zero
|
||||||
if x < Default::default() {
|
if x < Default::default() {
|
||||||
-x
|
Ok(-x)
|
||||||
} else {
|
} else {
|
||||||
x.into()
|
Ok(x.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Bit operators
|
// Bit operators
|
||||||
fn binary_and<T: BitAnd>(x: T, y: T) -> <T as BitAnd>::Output {
|
fn binary_and<T: BitAnd>(x: T, y: T) -> FuncReturn<<T as BitAnd>::Output> {
|
||||||
x & y
|
Ok(x & y)
|
||||||
}
|
}
|
||||||
fn binary_or<T: BitOr>(x: T, y: T) -> <T as BitOr>::Output {
|
fn binary_or<T: BitOr>(x: T, y: T) -> FuncReturn<<T as BitOr>::Output> {
|
||||||
x | y
|
Ok(x | y)
|
||||||
}
|
}
|
||||||
fn binary_xor<T: BitXor>(x: T, y: T) -> <T as BitXor>::Output {
|
fn binary_xor<T: BitXor>(x: T, y: T) -> FuncReturn<<T as BitXor>::Output> {
|
||||||
x ^ y
|
Ok(x ^ y)
|
||||||
}
|
}
|
||||||
// Checked left-shift
|
// Checked left-shift
|
||||||
fn shl<T: Display + CheckedShl>(x: T, y: INT) -> Result<T, Box<EvalAltResult>> {
|
fn shl<T: Display + CheckedShl>(x: T, y: INT) -> FuncReturn<T> {
|
||||||
// Cannot shift by a negative number of bits
|
// Cannot shift by a negative number of bits
|
||||||
if y < 0 {
|
if y < 0 {
|
||||||
return Err(Box::new(EvalAltResult::ErrorArithmetic(
|
return Err(Box::new(EvalAltResult::ErrorArithmetic(
|
||||||
@ -152,7 +150,7 @@ fn shl<T: Display + CheckedShl>(x: T, y: INT) -> Result<T, Box<EvalAltResult>> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Checked right-shift
|
// Checked right-shift
|
||||||
fn shr<T: Display + CheckedShr>(x: T, y: INT) -> Result<T, Box<EvalAltResult>> {
|
fn shr<T: Display + CheckedShr>(x: T, y: INT) -> FuncReturn<T> {
|
||||||
// Cannot shift by a negative number of bits
|
// Cannot shift by a negative number of bits
|
||||||
if y < 0 {
|
if y < 0 {
|
||||||
return Err(Box::new(EvalAltResult::ErrorArithmetic(
|
return Err(Box::new(EvalAltResult::ErrorArithmetic(
|
||||||
@ -169,15 +167,15 @@ fn shr<T: Display + CheckedShr>(x: T, y: INT) -> Result<T, Box<EvalAltResult>> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Unchecked left-shift - may panic if shifting by a negative number of bits
|
// Unchecked left-shift - may panic if shifting by a negative number of bits
|
||||||
fn shl_u<T: Shl<T>>(x: T, y: T) -> <T as Shl<T>>::Output {
|
fn shl_u<T: Shl<T>>(x: T, y: T) -> FuncReturn<<T as Shl<T>>::Output> {
|
||||||
x.shl(y)
|
Ok(x.shl(y))
|
||||||
}
|
}
|
||||||
// Unchecked right-shift - may panic if shifting by a negative number of bits
|
// Unchecked right-shift - may panic if shifting by a negative number of bits
|
||||||
fn shr_u<T: Shr<T>>(x: T, y: T) -> <T as Shr<T>>::Output {
|
fn shr_u<T: Shr<T>>(x: T, y: T) -> FuncReturn<<T as Shr<T>>::Output> {
|
||||||
x.shr(y)
|
Ok(x.shr(y))
|
||||||
}
|
}
|
||||||
// Checked modulo
|
// Checked modulo
|
||||||
fn modulo<T: Display + CheckedRem>(x: T, y: T) -> Result<T, Box<EvalAltResult>> {
|
fn modulo<T: Display + CheckedRem>(x: T, y: T) -> FuncReturn<T> {
|
||||||
x.checked_rem(&y).ok_or_else(|| {
|
x.checked_rem(&y).ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorArithmetic(
|
Box::new(EvalAltResult::ErrorArithmetic(
|
||||||
format!("Modulo division by zero or overflow: {} % {}", x, y),
|
format!("Modulo division by zero or overflow: {} % {}", x, y),
|
||||||
@ -186,11 +184,11 @@ fn modulo<T: Display + CheckedRem>(x: T, y: T) -> Result<T, Box<EvalAltResult>>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Unchecked modulo - may panic if dividing by zero
|
// Unchecked modulo - may panic if dividing by zero
|
||||||
fn modulo_u<T: Rem>(x: T, y: T) -> <T as Rem>::Output {
|
fn modulo_u<T: Rem>(x: T, y: T) -> FuncReturn<<T as Rem>::Output> {
|
||||||
x % y
|
Ok(x % y)
|
||||||
}
|
}
|
||||||
// Checked power
|
// Checked power
|
||||||
fn pow_i_i(x: INT, y: INT) -> Result<INT, Box<EvalAltResult>> {
|
fn pow_i_i(x: INT, y: INT) -> FuncReturn<INT> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
{
|
{
|
||||||
if y > (u32::MAX as INT) {
|
if y > (u32::MAX as INT) {
|
||||||
@ -231,17 +229,17 @@ fn pow_i_i(x: INT, y: INT) -> Result<INT, Box<EvalAltResult>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Unchecked integer power - may panic on overflow or if the power index is too high (> u32::MAX)
|
// Unchecked integer power - may panic on overflow or if the power index is too high (> u32::MAX)
|
||||||
fn pow_i_i_u(x: INT, y: INT) -> INT {
|
fn pow_i_i_u(x: INT, y: INT) -> FuncReturn<INT> {
|
||||||
x.pow(y as u32)
|
Ok(x.pow(y as u32))
|
||||||
}
|
}
|
||||||
// Floating-point power - always well-defined
|
// Floating-point power - always well-defined
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
fn pow_f_f(x: FLOAT, y: FLOAT) -> FLOAT {
|
fn pow_f_f(x: FLOAT, y: FLOAT) -> FuncReturn<FLOAT> {
|
||||||
x.powf(y)
|
Ok(x.powf(y))
|
||||||
}
|
}
|
||||||
// Checked power
|
// Checked power
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
fn pow_f_i(x: FLOAT, y: INT) -> Result<FLOAT, Box<EvalAltResult>> {
|
fn pow_f_i(x: FLOAT, y: INT) -> FuncReturn<FLOAT> {
|
||||||
// Raise to power that is larger than an i32
|
// Raise to power that is larger than an i32
|
||||||
if y > (i32::MAX as INT) {
|
if y > (i32::MAX as INT) {
|
||||||
return Err(Box::new(EvalAltResult::ErrorArithmetic(
|
return Err(Box::new(EvalAltResult::ErrorArithmetic(
|
||||||
@ -255,39 +253,37 @@ fn pow_f_i(x: FLOAT, y: INT) -> Result<FLOAT, Box<EvalAltResult>> {
|
|||||||
// Unchecked power - may be incorrect if the power index is too high (> i32::MAX)
|
// Unchecked power - may be incorrect if the power index is too high (> i32::MAX)
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
fn pow_f_i_u(x: FLOAT, y: INT) -> FLOAT {
|
fn pow_f_i_u(x: FLOAT, y: INT) -> FuncReturn<FLOAT> {
|
||||||
x.powi(y as i32)
|
Ok(x.powi(y as i32))
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! reg_unary_x { ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => {
|
macro_rules! reg_unary {
|
||||||
$(reg_unary($lib, $op, $func::<$par>, result);)* };
|
($lib:expr, $op:expr, $func:ident, $($par:ty),*) => {
|
||||||
|
$( $lib.set_fn_1($op, $func::<$par>); )*
|
||||||
|
};
|
||||||
}
|
}
|
||||||
macro_rules! reg_unary { ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => {
|
macro_rules! reg_op {
|
||||||
$(reg_unary($lib, $op, $func::<$par>, map);)* };
|
($lib:expr, $op:expr, $func:ident, $($par:ty),*) => {
|
||||||
}
|
$( $lib.set_fn_2($op, $func::<$par>); )*
|
||||||
macro_rules! reg_op_x { ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => {
|
};
|
||||||
$(reg_binary($lib, $op, $func::<$par>, result);)* };
|
|
||||||
}
|
|
||||||
macro_rules! reg_op { ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => {
|
|
||||||
$(reg_binary($lib, $op, $func::<$par>, map);)* };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def_package!(crate:ArithmeticPackage:"Basic arithmetic", lib, {
|
def_package!(crate:ArithmeticPackage:"Basic arithmetic", lib, {
|
||||||
// Checked basic arithmetic
|
// Checked basic arithmetic
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
{
|
{
|
||||||
reg_op_x!(lib, "+", add, INT);
|
reg_op!(lib, "+", add, INT);
|
||||||
reg_op_x!(lib, "-", sub, INT);
|
reg_op!(lib, "-", sub, INT);
|
||||||
reg_op_x!(lib, "*", mul, INT);
|
reg_op!(lib, "*", mul, INT);
|
||||||
reg_op_x!(lib, "/", div, INT);
|
reg_op!(lib, "/", div, INT);
|
||||||
|
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
#[cfg(not(feature = "only_i64"))]
|
#[cfg(not(feature = "only_i64"))]
|
||||||
{
|
{
|
||||||
reg_op_x!(lib, "+", add, i8, u8, i16, u16, i32, i64, u32, u64, i128, u128);
|
reg_op!(lib, "+", add, i8, u8, i16, u16, i32, i64, u32, u64, i128, u128);
|
||||||
reg_op_x!(lib, "-", sub, i8, u8, i16, u16, i32, i64, u32, u64, i128, u128);
|
reg_op!(lib, "-", sub, i8, u8, i16, u16, i32, i64, u32, u64, i128, u128);
|
||||||
reg_op_x!(lib, "*", mul, i8, u8, i16, u16, i32, i64, u32, u64, i128, u128);
|
reg_op!(lib, "*", mul, i8, u8, i16, u16, i32, i64, u32, u64, i128, u128);
|
||||||
reg_op_x!(lib, "/", div, i8, u8, i16, u16, i32, i64, u32, u64, i128, u128);
|
reg_op!(lib, "/", div, i8, u8, i16, u16, i32, i64, u32, u64, i128, u128);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,16 +330,16 @@ def_package!(crate:ArithmeticPackage:"Basic arithmetic", lib, {
|
|||||||
// Checked bit shifts
|
// Checked bit shifts
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
{
|
{
|
||||||
reg_op_x!(lib, "<<", shl, INT);
|
reg_op!(lib, "<<", shl, INT);
|
||||||
reg_op_x!(lib, ">>", shr, INT);
|
reg_op!(lib, ">>", shr, INT);
|
||||||
reg_op_x!(lib, "%", modulo, INT);
|
reg_op!(lib, "%", modulo, INT);
|
||||||
|
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
#[cfg(not(feature = "only_i64"))]
|
#[cfg(not(feature = "only_i64"))]
|
||||||
{
|
{
|
||||||
reg_op_x!(lib, "<<", shl, i8, u8, i16, u16, i32, i64, u32, u64, i128, u128);
|
reg_op!(lib, "<<", shl, i8, u8, i16, u16, i32, i64, u32, u64, i128, u128);
|
||||||
reg_op_x!(lib, ">>", shr, i8, u8, i16, u16, i32, i64, u32, u64, i128, u128);
|
reg_op!(lib, ">>", shr, i8, u8, i16, u16, i32, i64, u32, u64, i128, u128);
|
||||||
reg_op_x!(lib, "%", modulo, i8, u8, i16, u16, i32, i64, u32, u64, i128, u128);
|
reg_op!(lib, "%", modulo, i8, u8, i16, u16, i32, i64, u32, u64, i128, u128);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,39 +362,39 @@ def_package!(crate:ArithmeticPackage:"Basic arithmetic", lib, {
|
|||||||
// Checked power
|
// Checked power
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
{
|
{
|
||||||
reg_binary(lib, "~", pow_i_i, result);
|
lib.set_fn_2("~", pow_i_i);
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
reg_binary(lib, "~", pow_f_i, result);
|
lib.set_fn_2("~", pow_f_i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unchecked power
|
// Unchecked power
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
{
|
{
|
||||||
reg_binary(lib, "~", pow_i_i_u, map);
|
lib.set_fn_2("~", pow_i_i_u);
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
reg_binary(lib, "~", pow_f_i_u, map);
|
lib.set_fn_2("~", pow_f_i_u);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Floating-point modulo and power
|
// Floating-point modulo and power
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
{
|
{
|
||||||
reg_op!(lib, "%", modulo_u, f32, f64);
|
reg_op!(lib, "%", modulo_u, f32, f64);
|
||||||
reg_binary(lib, "~", pow_f_f, map);
|
lib.set_fn_2("~", pow_f_f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checked unary
|
// Checked unary
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
{
|
{
|
||||||
reg_unary_x!(lib, "-", neg, INT);
|
reg_unary!(lib, "-", neg, INT);
|
||||||
reg_unary_x!(lib, "abs", abs, INT);
|
reg_unary!(lib, "abs", abs, INT);
|
||||||
|
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
#[cfg(not(feature = "only_i64"))]
|
#[cfg(not(feature = "only_i64"))]
|
||||||
{
|
{
|
||||||
reg_unary_x!(lib, "-", neg, i8, i16, i32, i64, i128);
|
reg_unary!(lib, "-", neg, i8, i16, i32, i64, i128);
|
||||||
reg_unary_x!(lib, "abs", abs, i8, i16, i32, i64, i128);
|
reg_unary!(lib, "abs", abs, i8, i16, i32, i64, i128);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,20 +1,19 @@
|
|||||||
#![cfg(not(feature = "no_index"))]
|
#![cfg(not(feature = "no_index"))]
|
||||||
|
|
||||||
use super::{reg_binary, reg_binary_mut, reg_trinary_mut, reg_unary_mut};
|
|
||||||
|
|
||||||
use crate::any::{Dynamic, Variant};
|
use crate::any::{Dynamic, Variant};
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::engine::Array;
|
use crate::engine::Array;
|
||||||
use crate::fn_register::{map_dynamic as map, map_identity as pass};
|
use crate::module::FuncReturn;
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
|
|
||||||
use crate::stdlib::{any::TypeId, boxed::Box, string::String};
|
use crate::stdlib::{any::TypeId, boxed::Box, string::String};
|
||||||
|
|
||||||
// Register array utility functions
|
// Register array utility functions
|
||||||
fn push<T: Variant + Clone>(list: &mut Array, item: T) {
|
fn push<T: Variant + Clone>(list: &mut Array, item: T) -> FuncReturn<()> {
|
||||||
list.push(Dynamic::from(item));
|
list.push(Dynamic::from(item));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
fn ins<T: Variant + Clone>(list: &mut Array, position: INT, item: T) {
|
fn ins<T: Variant + Clone>(list: &mut Array, position: INT, item: T) -> FuncReturn<()> {
|
||||||
if position <= 0 {
|
if position <= 0 {
|
||||||
list.insert(0, Dynamic::from(item));
|
list.insert(0, Dynamic::from(item));
|
||||||
} else if (position as usize) >= list.len() - 1 {
|
} else if (position as usize) >= list.len() - 1 {
|
||||||
@ -22,20 +21,26 @@ fn ins<T: Variant + Clone>(list: &mut Array, position: INT, item: T) {
|
|||||||
} else {
|
} else {
|
||||||
list.insert(position as usize, Dynamic::from(item));
|
list.insert(position as usize, Dynamic::from(item));
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
fn pad<T: Variant + Clone>(list: &mut Array, len: INT, item: T) {
|
fn pad<T: Variant + Clone>(list: &mut Array, len: INT, item: T) -> FuncReturn<()> {
|
||||||
if len >= 0 {
|
if len >= 0 {
|
||||||
while list.len() < len as usize {
|
while list.len() < len as usize {
|
||||||
push(list, item.clone());
|
push(list, item.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! reg_op { ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => {
|
macro_rules! reg_op {
|
||||||
$(reg_binary_mut($lib, $op, $func::<$par>, map);)* };
|
($lib:expr, $op:expr, $func:ident, $($par:ty),*) => {
|
||||||
|
$( $lib.set_fn_2_mut($op, $func::<$par>); )*
|
||||||
|
};
|
||||||
}
|
}
|
||||||
macro_rules! reg_tri { ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => {
|
macro_rules! reg_tri {
|
||||||
$(reg_trinary_mut($lib, $op, $func::<$par>, map);)* };
|
($lib:expr, $op:expr, $func:ident, $($par:ty),*) => {
|
||||||
|
$( $lib.set_fn_3_mut($op, $func::<$par>); )*
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
@ -44,15 +49,16 @@ def_package!(crate:BasicArrayPackage:"Basic array utilities.", lib, {
|
|||||||
reg_tri!(lib, "pad", pad, INT, bool, char, String, Array, ());
|
reg_tri!(lib, "pad", pad, INT, bool, char, String, Array, ());
|
||||||
reg_tri!(lib, "insert", ins, INT, bool, char, String, Array, ());
|
reg_tri!(lib, "insert", ins, INT, bool, char, String, Array, ());
|
||||||
|
|
||||||
reg_binary_mut(lib, "append", |x: &mut Array, y: Array| x.extend(y), map);
|
lib.set_fn_2_mut("append", |x: &mut Array, y: Array| {
|
||||||
reg_binary(
|
x.extend(y);
|
||||||
lib,
|
Ok(())
|
||||||
|
});
|
||||||
|
lib.set_fn_2(
|
||||||
"+",
|
"+",
|
||||||
|mut x: Array, y: Array| {
|
|mut x: Array, y: Array| {
|
||||||
x.extend(y);
|
x.extend(y);
|
||||||
x
|
Ok(x)
|
||||||
},
|
},
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
@ -70,40 +76,36 @@ def_package!(crate:BasicArrayPackage:"Basic array utilities.", lib, {
|
|||||||
reg_tri!(lib, "insert", ins, f32, f64);
|
reg_tri!(lib, "insert", ins, f32, f64);
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_unary_mut(
|
lib.set_fn_1_mut(
|
||||||
lib,
|
|
||||||
"pop",
|
"pop",
|
||||||
|list: &mut Array| list.pop().unwrap_or_else(|| ().into()),
|
|list: &mut Array| Ok(list.pop().unwrap_or_else(|| ().into())),
|
||||||
pass,
|
|
||||||
);
|
);
|
||||||
reg_unary_mut(
|
lib.set_fn_1_mut(
|
||||||
lib,
|
|
||||||
"shift",
|
"shift",
|
||||||
|list: &mut Array| {
|
|list: &mut Array| {
|
||||||
if list.is_empty() {
|
Ok(if list.is_empty() {
|
||||||
().into()
|
().into()
|
||||||
} else {
|
} else {
|
||||||
list.remove(0)
|
list.remove(0)
|
||||||
}
|
})
|
||||||
},
|
},
|
||||||
pass,
|
|
||||||
);
|
);
|
||||||
reg_binary_mut(
|
lib.set_fn_2_mut(
|
||||||
lib,
|
|
||||||
"remove",
|
"remove",
|
||||||
|list: &mut Array, len: INT| {
|
|list: &mut Array, len: INT| {
|
||||||
if len < 0 || (len as usize) >= list.len() {
|
Ok(if len < 0 || (len as usize) >= list.len() {
|
||||||
().into()
|
().into()
|
||||||
} else {
|
} else {
|
||||||
list.remove(len as usize)
|
list.remove(len as usize)
|
||||||
}
|
})
|
||||||
},
|
},
|
||||||
pass,
|
|
||||||
);
|
);
|
||||||
reg_unary_mut(lib, "len", |list: &mut Array| list.len() as INT, map);
|
lib.set_fn_1_mut("len", |list: &mut Array| Ok(list.len() as INT));
|
||||||
reg_unary_mut(lib, "clear", |list: &mut Array| list.clear(), map);
|
lib.set_fn_1_mut("clear", |list: &mut Array| {
|
||||||
reg_binary_mut(
|
list.clear();
|
||||||
lib,
|
Ok(())
|
||||||
|
});
|
||||||
|
lib.set_fn_2_mut(
|
||||||
"truncate",
|
"truncate",
|
||||||
|list: &mut Array, len: INT| {
|
|list: &mut Array, len: INT| {
|
||||||
if len >= 0 {
|
if len >= 0 {
|
||||||
@ -111,12 +113,12 @@ def_package!(crate:BasicArrayPackage:"Basic array utilities.", lib, {
|
|||||||
} else {
|
} else {
|
||||||
list.clear();
|
list.clear();
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
},
|
},
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Register array iterator
|
// Register array iterator
|
||||||
lib.type_iterators.insert(
|
lib.set_iterator(
|
||||||
TypeId::of::<Array>(),
|
TypeId::of::<Array>(),
|
||||||
Box::new(|arr| Box::new(
|
Box::new(|arr| Box::new(
|
||||||
arr.cast::<Array>().into_iter()) as Box<dyn Iterator<Item = Dynamic>>
|
arr.cast::<Array>().into_iter()) as Box<dyn Iterator<Item = Dynamic>>
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
use super::{reg_binary, reg_trinary, PackageStore};
|
|
||||||
|
|
||||||
use crate::any::{Dynamic, Variant};
|
use crate::any::{Dynamic, Variant};
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::fn_register::map_dynamic as map;
|
use crate::module::{FuncReturn, Module};
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
@ -12,11 +10,11 @@ use crate::stdlib::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Register range function
|
// Register range function
|
||||||
fn reg_range<T: Variant + Clone>(lib: &mut PackageStore)
|
fn reg_range<T: Variant + Clone>(lib: &mut Module)
|
||||||
where
|
where
|
||||||
Range<T>: Iterator<Item = T>,
|
Range<T>: Iterator<Item = T>,
|
||||||
{
|
{
|
||||||
lib.type_iterators.insert(
|
lib.set_iterator(
|
||||||
TypeId::of::<Range<T>>(),
|
TypeId::of::<Range<T>>(),
|
||||||
Box::new(|source| {
|
Box::new(|source| {
|
||||||
Box::new(source.cast::<Range<T>>().map(|x| x.into_dynamic()))
|
Box::new(source.cast::<Range<T>>().map(|x| x.into_dynamic()))
|
||||||
@ -25,6 +23,10 @@ where
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_range<T: Variant + Clone>(from: T, to: T) -> FuncReturn<Range<T>> {
|
||||||
|
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)
|
||||||
@ -50,13 +52,13 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reg_step<T>(lib: &mut PackageStore)
|
fn reg_step<T>(lib: &mut Module)
|
||||||
where
|
where
|
||||||
for<'a> &'a T: Add<&'a T, Output = T>,
|
for<'a> &'a T: Add<&'a T, Output = T>,
|
||||||
T: Variant + Clone + PartialOrd,
|
T: Variant + Clone + PartialOrd,
|
||||||
StepRange<T>: Iterator<Item = T>,
|
StepRange<T>: Iterator<Item = T>,
|
||||||
{
|
{
|
||||||
lib.type_iterators.insert(
|
lib.set_iterator(
|
||||||
TypeId::of::<StepRange<T>>(),
|
TypeId::of::<StepRange<T>>(),
|
||||||
Box::new(|source| {
|
Box::new(|source| {
|
||||||
Box::new(source.cast::<StepRange<T>>().map(|x| x.into_dynamic()))
|
Box::new(source.cast::<StepRange<T>>().map(|x| x.into_dynamic()))
|
||||||
@ -65,22 +67,26 @@ where
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
|
fn get_step_range<T>(from: T, to: T, step: T) -> FuncReturn<StepRange<T>>
|
||||||
fn get_range<T>(from: T, to: T) -> Range<T> {
|
where
|
||||||
from..to
|
for<'a> &'a T: Add<&'a T, Output = T>,
|
||||||
}
|
T: Variant + Clone + PartialOrd,
|
||||||
|
{
|
||||||
|
Ok(StepRange::<T>(from, to, step))
|
||||||
|
}
|
||||||
|
|
||||||
|
def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
|
||||||
reg_range::<INT>(lib);
|
reg_range::<INT>(lib);
|
||||||
reg_binary(lib, "range", get_range::<INT>, map);
|
lib.set_fn_2("range", get_range::<INT>);
|
||||||
|
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
#[cfg(not(feature = "only_i64"))]
|
#[cfg(not(feature = "only_i64"))]
|
||||||
{
|
{
|
||||||
macro_rules! reg_range {
|
macro_rules! reg_range {
|
||||||
($self:expr, $x:expr, $( $y:ty ),*) => (
|
($lib:expr, $x:expr, $( $y:ty ),*) => (
|
||||||
$(
|
$(
|
||||||
reg_range::<$y>($self);
|
reg_range::<$y>($lib);
|
||||||
reg_binary($self, $x, get_range::<$y>, map);
|
$lib.set_fn_2($x, get_range::<$y>);
|
||||||
)*
|
)*
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -89,16 +95,16 @@ def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
reg_step::<INT>(lib);
|
reg_step::<INT>(lib);
|
||||||
reg_trinary(lib, "range", StepRange::<INT>, map);
|
lib.set_fn_3("range", get_step_range::<INT>);
|
||||||
|
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
#[cfg(not(feature = "only_i64"))]
|
#[cfg(not(feature = "only_i64"))]
|
||||||
{
|
{
|
||||||
macro_rules! reg_step {
|
macro_rules! reg_step {
|
||||||
($self:expr, $x:expr, $( $y:ty ),*) => (
|
($lib:expr, $x:expr, $( $y:ty ),*) => (
|
||||||
$(
|
$(
|
||||||
reg_step::<$y>($self);
|
reg_step::<$y>($lib);
|
||||||
reg_trinary($self, $x, StepRange::<$y>, map);
|
$lib.set_fn_3($x, get_step_range::<$y>);
|
||||||
)*
|
)*
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,44 +1,44 @@
|
|||||||
use super::{reg_binary, reg_binary_mut, reg_unary};
|
|
||||||
|
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::fn_register::map_dynamic as map;
|
use crate::module::FuncReturn;
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
|
|
||||||
use crate::stdlib::string::String;
|
use crate::stdlib::string::String;
|
||||||
|
|
||||||
// Comparison operators
|
// Comparison operators
|
||||||
pub fn lt<T: PartialOrd>(x: T, y: T) -> bool {
|
pub fn lt<T: PartialOrd>(x: T, y: T) -> FuncReturn<bool> {
|
||||||
x < y
|
Ok(x < y)
|
||||||
}
|
}
|
||||||
pub fn lte<T: PartialOrd>(x: T, y: T) -> bool {
|
pub fn lte<T: PartialOrd>(x: T, y: T) -> FuncReturn<bool> {
|
||||||
x <= y
|
Ok(x <= y)
|
||||||
}
|
}
|
||||||
pub fn gt<T: PartialOrd>(x: T, y: T) -> bool {
|
pub fn gt<T: PartialOrd>(x: T, y: T) -> FuncReturn<bool> {
|
||||||
x > y
|
Ok(x > y)
|
||||||
}
|
}
|
||||||
pub fn gte<T: PartialOrd>(x: T, y: T) -> bool {
|
pub fn gte<T: PartialOrd>(x: T, y: T) -> FuncReturn<bool> {
|
||||||
x >= y
|
Ok(x >= y)
|
||||||
}
|
}
|
||||||
pub fn eq<T: PartialEq>(x: T, y: T) -> bool {
|
pub fn eq<T: PartialEq>(x: T, y: T) -> FuncReturn<bool> {
|
||||||
x == y
|
Ok(x == y)
|
||||||
}
|
}
|
||||||
pub fn ne<T: PartialEq>(x: T, y: T) -> bool {
|
pub fn ne<T: PartialEq>(x: T, y: T) -> FuncReturn<bool> {
|
||||||
x != y
|
Ok(x != y)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logic operators
|
// Logic operators
|
||||||
fn and(x: bool, y: bool) -> bool {
|
fn and(x: bool, y: bool) -> FuncReturn<bool> {
|
||||||
x && y
|
Ok(x && y)
|
||||||
}
|
}
|
||||||
fn or(x: bool, y: bool) -> bool {
|
fn or(x: bool, y: bool) -> FuncReturn<bool> {
|
||||||
x || y
|
Ok(x || y)
|
||||||
}
|
}
|
||||||
fn not(x: bool) -> bool {
|
fn not(x: bool) -> FuncReturn<bool> {
|
||||||
!x
|
Ok(!x)
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! reg_op { ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => {
|
macro_rules! reg_op {
|
||||||
$(reg_binary($lib, $op, $func::<$par>, map);)* };
|
($lib:expr, $op:expr, $func:ident, $($par:ty),*) => {
|
||||||
|
$( $lib.set_fn_2($op, $func::<$par>); )*
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
def_package!(crate:LogicPackage:"Logical operators.", lib, {
|
def_package!(crate:LogicPackage:"Logical operators.", lib, {
|
||||||
@ -50,14 +50,12 @@ def_package!(crate:LogicPackage:"Logical operators.", lib, {
|
|||||||
reg_op!(lib, "!=", ne, INT, char, bool, ());
|
reg_op!(lib, "!=", ne, INT, char, bool, ());
|
||||||
|
|
||||||
// Special versions for strings - at least avoid copying the first string
|
// Special versions for strings - at least avoid copying the first string
|
||||||
// use super::utils::reg_test;
|
lib.set_fn_2_mut("<", |x: &mut String, y: String| Ok(*x < y));
|
||||||
// reg_test(lib, "<", |x: &mut String, y: String| *x < y, |v| v, map);
|
lib.set_fn_2_mut("<=", |x: &mut String, y: String| Ok(*x <= y));
|
||||||
reg_binary_mut(lib, "<", |x: &mut String, y: String| *x < y, map);
|
lib.set_fn_2_mut(">", |x: &mut String, y: String| Ok(*x > y));
|
||||||
reg_binary_mut(lib, "<=", |x: &mut String, y: String| *x <= y, map);
|
lib.set_fn_2_mut(">=", |x: &mut String, y: String| Ok(*x >= y));
|
||||||
reg_binary_mut(lib, ">", |x: &mut String, y: String| *x > y, map);
|
lib.set_fn_2_mut("==", |x: &mut String, y: String| Ok(*x == y));
|
||||||
reg_binary_mut(lib, ">=", |x: &mut String, y: String| *x >= y, map);
|
lib.set_fn_2_mut("!=", |x: &mut String, y: String| Ok(*x != y));
|
||||||
reg_binary_mut(lib, "==", |x: &mut String, y: String| *x == y, map);
|
|
||||||
reg_binary_mut(lib, "!=", |x: &mut String, y: String| *x != y, map);
|
|
||||||
|
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
#[cfg(not(feature = "only_i64"))]
|
#[cfg(not(feature = "only_i64"))]
|
||||||
@ -85,7 +83,7 @@ def_package!(crate:LogicPackage:"Logical operators.", lib, {
|
|||||||
//reg_op!(lib, "||", or, bool);
|
//reg_op!(lib, "||", or, bool);
|
||||||
//reg_op!(lib, "&&", and, bool);
|
//reg_op!(lib, "&&", and, bool);
|
||||||
|
|
||||||
reg_binary(lib, "|", or, map);
|
lib.set_fn_2("|", or);
|
||||||
reg_binary(lib, "&", and, map);
|
lib.set_fn_2("&", and);
|
||||||
reg_unary(lib, "!", not, map);
|
lib.set_fn_1("!", not);
|
||||||
});
|
});
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
#![cfg(not(feature = "no_object"))]
|
#![cfg(not(feature = "no_object"))]
|
||||||
|
|
||||||
use super::{reg_binary, reg_binary_mut, reg_unary_mut};
|
|
||||||
|
|
||||||
use crate::any::Dynamic;
|
use crate::any::Dynamic;
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::engine::Map;
|
use crate::engine::Map;
|
||||||
use crate::fn_register::map_dynamic as map;
|
use crate::module::FuncReturn;
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
@ -13,55 +11,51 @@ use crate::stdlib::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn map_get_keys(map: &mut Map) -> Vec<Dynamic> {
|
fn map_get_keys(map: &mut Map) -> FuncReturn<Vec<Dynamic>> {
|
||||||
map.iter().map(|(k, _)| k.to_string().into()).collect()
|
Ok(map.iter().map(|(k, _)| k.to_string().into()).collect())
|
||||||
}
|
}
|
||||||
fn map_get_values(map: &mut Map) -> Vec<Dynamic> {
|
fn map_get_values(map: &mut Map) -> FuncReturn<Vec<Dynamic>> {
|
||||||
map.iter().map(|(_, v)| v.clone()).collect()
|
Ok(map.iter().map(|(_, v)| v.clone()).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
def_package!(crate:BasicMapPackage:"Basic object map utilities.", lib, {
|
def_package!(crate:BasicMapPackage:"Basic object map utilities.", lib, {
|
||||||
reg_binary_mut(
|
lib.set_fn_2_mut(
|
||||||
lib,
|
|
||||||
"has",
|
"has",
|
||||||
|map: &mut Map, prop: String| map.contains_key(&prop),
|
|map: &mut Map, prop: String| Ok(map.contains_key(&prop)),
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
reg_unary_mut(lib, "len", |map: &mut Map| map.len() as INT, map);
|
lib.set_fn_1_mut("len", |map: &mut Map| Ok(map.len() as INT));
|
||||||
reg_unary_mut(lib, "clear", |map: &mut Map| map.clear(), map);
|
lib.set_fn_1_mut("clear", |map: &mut Map| {
|
||||||
reg_binary_mut(
|
map.clear();
|
||||||
lib,
|
Ok(())
|
||||||
|
});
|
||||||
|
lib.set_fn_2_mut(
|
||||||
"remove",
|
"remove",
|
||||||
|x: &mut Map, name: String| x.remove(&name).unwrap_or_else(|| ().into()),
|
|x: &mut Map, name: String| Ok(x.remove(&name).unwrap_or_else(|| ().into())),
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
reg_binary_mut(
|
lib.set_fn_2_mut(
|
||||||
lib,
|
|
||||||
"mixin",
|
"mixin",
|
||||||
|map1: &mut Map, map2: Map| {
|
|map1: &mut Map, map2: Map| {
|
||||||
map2.into_iter().for_each(|(key, value)| {
|
map2.into_iter().for_each(|(key, value)| {
|
||||||
map1.insert(key, value);
|
map1.insert(key, value);
|
||||||
});
|
});
|
||||||
|
Ok(())
|
||||||
},
|
},
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
reg_binary(
|
lib.set_fn_2(
|
||||||
lib,
|
|
||||||
"+",
|
"+",
|
||||||
|mut map1: Map, map2: Map| {
|
|mut map1: Map, map2: Map| {
|
||||||
map2.into_iter().for_each(|(key, value)| {
|
map2.into_iter().for_each(|(key, value)| {
|
||||||
map1.insert(key, value);
|
map1.insert(key, value);
|
||||||
});
|
});
|
||||||
map1
|
Ok(map1)
|
||||||
},
|
},
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Register map access functions
|
// Register map access functions
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
reg_unary_mut(lib, "keys", map_get_keys, map);
|
lib.set_fn_1_mut("keys", map_get_keys);
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
reg_unary_mut(lib, "values", map_get_values, map);
|
lib.set_fn_1_mut("values", map_get_values);
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
use super::{reg_binary, reg_unary};
|
|
||||||
|
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::fn_register::{map_dynamic as map, map_result as result};
|
use crate::module::FuncReturn;
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
@ -20,78 +18,77 @@ def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, {
|
|||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
{
|
{
|
||||||
// Advanced math functions
|
// Advanced math functions
|
||||||
reg_unary(lib, "sin", |x: FLOAT| x.to_radians().sin(), map);
|
lib.set_fn_1("sin", |x: FLOAT| Ok(x.to_radians().sin()));
|
||||||
reg_unary(lib, "cos", |x: FLOAT| x.to_radians().cos(), map);
|
lib.set_fn_1("cos", |x: FLOAT| Ok(x.to_radians().cos()));
|
||||||
reg_unary(lib, "tan", |x: FLOAT| x.to_radians().tan(), map);
|
lib.set_fn_1("tan", |x: FLOAT| Ok(x.to_radians().tan()));
|
||||||
reg_unary(lib, "sinh", |x: FLOAT| x.to_radians().sinh(), map);
|
lib.set_fn_1("sinh", |x: FLOAT| Ok(x.to_radians().sinh()));
|
||||||
reg_unary(lib, "cosh", |x: FLOAT| x.to_radians().cosh(), map);
|
lib.set_fn_1("cosh", |x: FLOAT| Ok(x.to_radians().cosh()));
|
||||||
reg_unary(lib, "tanh", |x: FLOAT| x.to_radians().tanh(), map);
|
lib.set_fn_1("tanh", |x: FLOAT| Ok(x.to_radians().tanh()));
|
||||||
reg_unary(lib, "asin", |x: FLOAT| x.asin().to_degrees(), map);
|
lib.set_fn_1("asin", |x: FLOAT| Ok(x.asin().to_degrees()));
|
||||||
reg_unary(lib, "acos", |x: FLOAT| x.acos().to_degrees(), map);
|
lib.set_fn_1("acos", |x: FLOAT| Ok(x.acos().to_degrees()));
|
||||||
reg_unary(lib, "atan", |x: FLOAT| x.atan().to_degrees(), map);
|
lib.set_fn_1("atan", |x: FLOAT| Ok(x.atan().to_degrees()));
|
||||||
reg_unary(lib, "asinh", |x: FLOAT| x.asinh().to_degrees(), map);
|
lib.set_fn_1("asinh", |x: FLOAT| Ok(x.asinh().to_degrees()));
|
||||||
reg_unary(lib, "acosh", |x: FLOAT| x.acosh().to_degrees(), map);
|
lib.set_fn_1("acosh", |x: FLOAT| Ok(x.acosh().to_degrees()));
|
||||||
reg_unary(lib, "atanh", |x: FLOAT| x.atanh().to_degrees(), map);
|
lib.set_fn_1("atanh", |x: FLOAT| Ok(x.atanh().to_degrees()));
|
||||||
reg_unary(lib, "sqrt", |x: FLOAT| x.sqrt(), map);
|
lib.set_fn_1("sqrt", |x: FLOAT| Ok(x.sqrt()));
|
||||||
reg_unary(lib, "exp", |x: FLOAT| x.exp(), map);
|
lib.set_fn_1("exp", |x: FLOAT| Ok(x.exp()));
|
||||||
reg_unary(lib, "ln", |x: FLOAT| x.ln(), map);
|
lib.set_fn_1("ln", |x: FLOAT| Ok(x.ln()));
|
||||||
reg_binary(lib, "log", |x: FLOAT, base: FLOAT| x.log(base), map);
|
lib.set_fn_2("log", |x: FLOAT, base: FLOAT| Ok(x.log(base)));
|
||||||
reg_unary(lib, "log10", |x: FLOAT| x.log10(), map);
|
lib.set_fn_1("log10", |x: FLOAT| Ok(x.log10()));
|
||||||
reg_unary(lib, "floor", |x: FLOAT| x.floor(), map);
|
lib.set_fn_1("floor", |x: FLOAT| Ok(x.floor()));
|
||||||
reg_unary(lib, "ceiling", |x: FLOAT| x.ceil(), map);
|
lib.set_fn_1("ceiling", |x: FLOAT| Ok(x.ceil()));
|
||||||
reg_unary(lib, "round", |x: FLOAT| x.ceil(), map);
|
lib.set_fn_1("round", |x: FLOAT| Ok(x.ceil()));
|
||||||
reg_unary(lib, "int", |x: FLOAT| x.trunc(), map);
|
lib.set_fn_1("int", |x: FLOAT| Ok(x.trunc()));
|
||||||
reg_unary(lib, "fraction", |x: FLOAT| x.fract(), map);
|
lib.set_fn_1("fraction", |x: FLOAT| Ok(x.fract()));
|
||||||
reg_unary(lib, "is_nan", |x: FLOAT| x.is_nan(), map);
|
lib.set_fn_1("is_nan", |x: FLOAT| Ok(x.is_nan()));
|
||||||
reg_unary(lib, "is_finite", |x: FLOAT| x.is_finite(), map);
|
lib.set_fn_1("is_finite", |x: FLOAT| Ok(x.is_finite()));
|
||||||
reg_unary(lib, "is_infinite", |x: FLOAT| x.is_infinite(), map);
|
lib.set_fn_1("is_infinite", |x: FLOAT| Ok(x.is_infinite()));
|
||||||
|
|
||||||
// Register conversion functions
|
// Register conversion functions
|
||||||
reg_unary(lib, "to_float", |x: INT| x as FLOAT, map);
|
lib.set_fn_1("to_float", |x: INT| Ok(x as FLOAT));
|
||||||
reg_unary(lib, "to_float", |x: f32| x as FLOAT, map);
|
lib.set_fn_1("to_float", |x: f32| Ok(x as FLOAT));
|
||||||
|
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
#[cfg(not(feature = "only_i64"))]
|
#[cfg(not(feature = "only_i64"))]
|
||||||
{
|
{
|
||||||
reg_unary(lib, "to_float", |x: i8| x as FLOAT, map);
|
lib.set_fn_1("to_float", |x: i8| Ok(x as FLOAT));
|
||||||
reg_unary(lib, "to_float", |x: u8| x as FLOAT, map);
|
lib.set_fn_1("to_float", |x: u8| Ok(x as FLOAT));
|
||||||
reg_unary(lib, "to_float", |x: i16| x as FLOAT, map);
|
lib.set_fn_1("to_float", |x: i16| Ok(x as FLOAT));
|
||||||
reg_unary(lib, "to_float", |x: u16| x as FLOAT, map);
|
lib.set_fn_1("to_float", |x: u16| Ok(x as FLOAT));
|
||||||
reg_unary(lib, "to_float", |x: i32| x as FLOAT, map);
|
lib.set_fn_1("to_float", |x: i32| Ok(x as FLOAT));
|
||||||
reg_unary(lib, "to_float", |x: u32| x as FLOAT, map);
|
lib.set_fn_1("to_float", |x: u32| Ok(x as FLOAT));
|
||||||
reg_unary(lib, "to_float", |x: i64| x as FLOAT, map);
|
lib.set_fn_1("to_float", |x: i64| Ok(x as FLOAT));
|
||||||
reg_unary(lib, "to_float", |x: u64| x as FLOAT, map);
|
lib.set_fn_1("to_float", |x: u64| Ok(x as FLOAT));
|
||||||
reg_unary(lib, "to_float", |x: i128| x as FLOAT, map);
|
lib.set_fn_1("to_float", |x: i128| Ok(x as FLOAT));
|
||||||
reg_unary(lib, "to_float", |x: u128| x as FLOAT, map);
|
lib.set_fn_1("to_float", |x: u128| Ok(x as FLOAT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_unary(lib, "to_int", |ch: char| ch as INT, map);
|
lib.set_fn_1("to_int", |ch: char| Ok(ch as INT));
|
||||||
|
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
#[cfg(not(feature = "only_i64"))]
|
#[cfg(not(feature = "only_i64"))]
|
||||||
{
|
{
|
||||||
reg_unary(lib, "to_int", |x: i8| x as INT, map);
|
lib.set_fn_1("to_int", |x: i8| Ok(x as INT));
|
||||||
reg_unary(lib, "to_int", |x: u8| x as INT, map);
|
lib.set_fn_1("to_int", |x: u8| Ok(x as INT));
|
||||||
reg_unary(lib, "to_int", |x: i16| x as INT, map);
|
lib.set_fn_1("to_int", |x: i16| Ok(x as INT));
|
||||||
reg_unary(lib, "to_int", |x: u16| x as INT, map);
|
lib.set_fn_1("to_int", |x: u16| Ok(x as INT));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
{
|
{
|
||||||
reg_unary(lib, "to_int", |x: i32| x as INT, map);
|
lib.set_fn_1("to_int", |x: i32| Ok(x as INT));
|
||||||
reg_unary(lib, "to_int", |x: u64| x as INT, map);
|
lib.set_fn_1("to_int", |x: u64| Ok(x as INT));
|
||||||
|
|
||||||
#[cfg(feature = "only_i64")]
|
#[cfg(feature = "only_i64")]
|
||||||
reg_unary(lib, "to_int", |x: u32| x as INT, map);
|
lib.set_fn_1("to_int", |x: u32| Ok(x as INT));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
{
|
{
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
{
|
{
|
||||||
reg_unary(
|
lib.set_fn_1(
|
||||||
lib,
|
|
||||||
"to_int",
|
"to_int",
|
||||||
|x: f32| {
|
|x: f32| {
|
||||||
if x > (MAX_INT as f32) {
|
if x > (MAX_INT as f32) {
|
||||||
@ -103,10 +100,8 @@ def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, {
|
|||||||
|
|
||||||
Ok(x.trunc() as INT)
|
Ok(x.trunc() as INT)
|
||||||
},
|
},
|
||||||
result,
|
|
||||||
);
|
);
|
||||||
reg_unary(
|
lib.set_fn_1(
|
||||||
lib,
|
|
||||||
"to_int",
|
"to_int",
|
||||||
|x: FLOAT| {
|
|x: FLOAT| {
|
||||||
if x > (MAX_INT as FLOAT) {
|
if x > (MAX_INT as FLOAT) {
|
||||||
@ -118,14 +113,13 @@ def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, {
|
|||||||
|
|
||||||
Ok(x.trunc() as INT)
|
Ok(x.trunc() as INT)
|
||||||
},
|
},
|
||||||
result,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
{
|
{
|
||||||
reg_unary(lib, "to_int", |x: f32| x as INT, map);
|
lib.set_fn_1("to_int", |x: f32| Ok(x as INT));
|
||||||
reg_unary(lib, "to_int", |x: f64| x as INT, map);
|
lib.set_fn_1("to_int", |x: f64| Ok(x as INT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! This module contains all built-in _packages_ available to Rhai, plus facilities to define custom packages.
|
//! This module contains all built-in _packages_ available to Rhai, plus facilities to define custom packages.
|
||||||
|
|
||||||
use crate::fn_native::{IteratorFn, NativeCallable};
|
use crate::fn_native::{NativeCallable, SharedIteratorFunction};
|
||||||
|
use crate::module::Module;
|
||||||
|
|
||||||
use crate::stdlib::{any::TypeId, boxed::Box, collections::HashMap, rc::Rc, sync::Arc, vec::Vec};
|
use crate::stdlib::{any::TypeId, boxed::Box, collections::HashMap, rc::Rc, sync::Arc, vec::Vec};
|
||||||
|
|
||||||
@ -15,7 +16,6 @@ mod pkg_std;
|
|||||||
mod string_basic;
|
mod string_basic;
|
||||||
mod string_more;
|
mod string_more;
|
||||||
mod time_basic;
|
mod time_basic;
|
||||||
mod utils;
|
|
||||||
|
|
||||||
pub use arithmetic::ArithmeticPackage;
|
pub use arithmetic::ArithmeticPackage;
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
@ -32,67 +32,22 @@ pub use string_more::MoreStringPackage;
|
|||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
pub use time_basic::BasicTimePackage;
|
pub use time_basic::BasicTimePackage;
|
||||||
|
|
||||||
pub use utils::*;
|
|
||||||
|
|
||||||
const NUM_NATIVE_FUNCTIONS: usize = 512;
|
|
||||||
|
|
||||||
/// Trait that all packages must implement.
|
/// Trait that all packages must implement.
|
||||||
pub trait Package {
|
pub trait Package {
|
||||||
/// Register all the functions in a package into a store.
|
/// Register all the functions in a package into a store.
|
||||||
fn init(lib: &mut PackageStore);
|
fn init(lib: &mut Module);
|
||||||
|
|
||||||
/// Retrieve the generic package library from this package.
|
/// Retrieve the generic package library from this package.
|
||||||
fn get(&self) -> PackageLibrary;
|
fn get(&self) -> PackageLibrary;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type to store all functions in the package.
|
/// Type which `Rc`-wraps a `Module` to facilitate sharing library instances.
|
||||||
pub struct PackageStore {
|
|
||||||
/// All functions, keyed by a hash created from the function name and parameter types.
|
|
||||||
pub functions: HashMap<u64, Box<dyn NativeCallable>>,
|
|
||||||
|
|
||||||
/// All iterator functions, keyed by the type producing the iterator.
|
|
||||||
pub type_iterators: HashMap<TypeId, Box<IteratorFn>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PackageStore {
|
|
||||||
/// Create a new `PackageStore`.
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
/// Does the specified function hash key exist in the `PackageStore`?
|
|
||||||
pub fn contains_function(&self, hash: u64) -> bool {
|
|
||||||
self.functions.contains_key(&hash)
|
|
||||||
}
|
|
||||||
/// Get specified function via its hash key.
|
|
||||||
pub fn get_function(&self, hash: u64) -> Option<&Box<dyn NativeCallable>> {
|
|
||||||
self.functions.get(&hash)
|
|
||||||
}
|
|
||||||
/// Does the specified TypeId iterator exist in the `PackageStore`?
|
|
||||||
pub fn contains_iterator(&self, id: TypeId) -> bool {
|
|
||||||
self.type_iterators.contains_key(&id)
|
|
||||||
}
|
|
||||||
/// Get the specified TypeId iterator.
|
|
||||||
pub fn get_iterator(&self, id: TypeId) -> Option<&Box<IteratorFn>> {
|
|
||||||
self.type_iterators.get(&id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for PackageStore {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
functions: HashMap::with_capacity(NUM_NATIVE_FUNCTIONS),
|
|
||||||
type_iterators: HashMap::with_capacity(4),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Type which `Rc`-wraps a `PackageStore` to facilitate sharing library instances.
|
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
pub type PackageLibrary = Rc<PackageStore>;
|
pub type PackageLibrary = Rc<Module>;
|
||||||
|
|
||||||
/// Type which `Arc`-wraps a `PackageStore` to facilitate sharing library instances.
|
/// Type which `Arc`-wraps a `Module` to facilitate sharing library instances.
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
pub type PackageLibrary = Arc<PackageStore>;
|
pub type PackageLibrary = Arc<Module>;
|
||||||
|
|
||||||
/// Type containing a collection of `PackageLibrary` instances.
|
/// Type containing a collection of `PackageLibrary` instances.
|
||||||
/// All function and type iterator keys in the loaded packages are indexed for fast access.
|
/// All function and type iterator keys in the loaded packages are indexed for fast access.
|
||||||
@ -110,13 +65,13 @@ impl PackagesCollection {
|
|||||||
}
|
}
|
||||||
/// Does the specified function hash key exist in the `PackagesCollection`?
|
/// Does the specified function hash key exist in the `PackagesCollection`?
|
||||||
pub fn contains_function(&self, hash: u64) -> bool {
|
pub fn contains_function(&self, hash: u64) -> bool {
|
||||||
self.packages.iter().any(|p| p.contains_function(hash))
|
self.packages.iter().any(|p| p.contains_fn(hash))
|
||||||
}
|
}
|
||||||
/// Get specified function via its hash key.
|
/// Get specified function via its hash key.
|
||||||
pub fn get_function(&self, hash: u64) -> Option<&Box<dyn NativeCallable>> {
|
pub fn get_function(&self, hash: u64) -> Option<&Box<dyn NativeCallable>> {
|
||||||
self.packages
|
self.packages
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| p.get_function(hash))
|
.map(|p| p.get_fn(hash))
|
||||||
.find(|f| f.is_some())
|
.find(|f| f.is_some())
|
||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
@ -125,7 +80,7 @@ impl PackagesCollection {
|
|||||||
self.packages.iter().any(|p| p.contains_iterator(id))
|
self.packages.iter().any(|p| p.contains_iterator(id))
|
||||||
}
|
}
|
||||||
/// Get the specified TypeId iterator.
|
/// Get the specified TypeId iterator.
|
||||||
pub fn get_iterator(&self, id: TypeId) -> Option<&Box<IteratorFn>> {
|
pub fn get_iterator(&self, id: TypeId) -> Option<&SharedIteratorFunction> {
|
||||||
self.packages
|
self.packages
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| p.get_iterator(id))
|
.map(|p| p.get_iterator(id))
|
||||||
@ -133,3 +88,51 @@ impl PackagesCollection {
|
|||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This macro makes it easy to define a _package_ (which is basically a shared module)
|
||||||
|
/// and register functions into it.
|
||||||
|
///
|
||||||
|
/// Functions can be added to the package using the standard module methods such as
|
||||||
|
/// `set_fn_2`, `set_fn_3_mut`, `set_fn_0` etc.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::{Dynamic, EvalAltResult};
|
||||||
|
/// use rhai::def_package;
|
||||||
|
///
|
||||||
|
/// fn add(x: i64, y: i64) -> Result<i64, Box<EvalAltResult>> { Ok(x + y) }
|
||||||
|
///
|
||||||
|
/// def_package!(rhai:MyPackage:"My super-duper package", lib,
|
||||||
|
/// {
|
||||||
|
/// // Load a binary function with all value parameters.
|
||||||
|
/// lib.set_fn_2("my_add", add);
|
||||||
|
/// });
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The above defines a package named 'MyPackage' with a single function named 'my_add'.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! def_package {
|
||||||
|
($root:ident : $package:ident : $comment:expr , $lib:ident , $block:stmt) => {
|
||||||
|
#[doc=$comment]
|
||||||
|
pub struct $package($root::packages::PackageLibrary);
|
||||||
|
|
||||||
|
impl $root::packages::Package for $package {
|
||||||
|
fn get(&self) -> $root::packages::PackageLibrary {
|
||||||
|
self.0.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init($lib: &mut $root::Module) {
|
||||||
|
$block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $package {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut module = $root::Module::new();
|
||||||
|
<Self as $root::packages::Package>::init(&mut module);
|
||||||
|
Self(module.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
use super::{reg_binary, reg_binary_mut, reg_none, reg_unary, reg_unary_mut};
|
|
||||||
|
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::engine::{FUNC_TO_STRING, KEYWORD_DEBUG, KEYWORD_PRINT};
|
use crate::engine::{FUNC_TO_STRING, KEYWORD_DEBUG, KEYWORD_PRINT};
|
||||||
use crate::fn_register::map_dynamic as map;
|
use crate::module::FuncReturn;
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
@ -18,31 +16,33 @@ use crate::stdlib::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Register print and debug
|
// Register print and debug
|
||||||
fn to_debug<T: Debug>(x: &mut T) -> String {
|
fn to_debug<T: Debug>(x: &mut T) -> FuncReturn<String> {
|
||||||
format!("{:?}", x)
|
Ok(format!("{:?}", x))
|
||||||
}
|
}
|
||||||
fn to_string<T: Display>(x: &mut T) -> String {
|
fn to_string<T: Display>(x: &mut T) -> FuncReturn<String> {
|
||||||
format!("{}", x)
|
Ok(format!("{}", x))
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
fn format_map(x: &mut Map) -> String {
|
fn format_map(x: &mut Map) -> FuncReturn<String> {
|
||||||
format!("#{:?}", x)
|
Ok(format!("#{:?}", x))
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! reg_op { ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => {
|
macro_rules! reg_op {
|
||||||
$(reg_unary_mut($lib, $op, $func::<$par>, map);)* };
|
($lib:expr, $op:expr, $func:ident, $($par:ty),*) => {
|
||||||
|
$( $lib.set_fn_1_mut($op, $func::<$par>); )*
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
def_package!(crate:BasicStringPackage:"Basic string utilities, including printing.", lib, {
|
def_package!(crate:BasicStringPackage:"Basic string utilities, including printing.", lib, {
|
||||||
reg_op!(lib, KEYWORD_PRINT, to_string, INT, bool, char);
|
reg_op!(lib, KEYWORD_PRINT, to_string, INT, bool, char);
|
||||||
reg_op!(lib, FUNC_TO_STRING, to_string, INT, bool, char);
|
reg_op!(lib, FUNC_TO_STRING, to_string, INT, bool, char);
|
||||||
|
|
||||||
reg_none(lib, KEYWORD_PRINT, || "".to_string(), map);
|
lib.set_fn_0(KEYWORD_PRINT, || Ok("".to_string()));
|
||||||
reg_unary(lib, KEYWORD_PRINT, |_: ()| "".to_string(), map);
|
lib.set_fn_1(KEYWORD_PRINT, |_: ()| Ok("".to_string()));
|
||||||
reg_unary(lib, FUNC_TO_STRING, |_: ()| "".to_string(), map);
|
lib.set_fn_1(FUNC_TO_STRING, |_: ()| Ok("".to_string()));
|
||||||
|
|
||||||
reg_unary_mut(lib, KEYWORD_PRINT, |s: &mut String| s.clone(), map);
|
lib.set_fn_1_mut(KEYWORD_PRINT, |s: &mut String| Ok(s.clone()));
|
||||||
reg_unary_mut(lib, FUNC_TO_STRING, |s: &mut String| s.clone(), map);
|
lib.set_fn_1_mut(FUNC_TO_STRING, |s: &mut String| Ok(s.clone()));
|
||||||
|
|
||||||
reg_op!(lib, KEYWORD_DEBUG, to_debug, INT, bool, (), char, String);
|
reg_op!(lib, KEYWORD_DEBUG, to_debug, INT, bool, (), char, String);
|
||||||
|
|
||||||
@ -73,34 +73,34 @@ def_package!(crate:BasicStringPackage:"Basic string utilities, including printin
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
{
|
{
|
||||||
reg_unary_mut(lib, KEYWORD_PRINT, format_map, map);
|
lib.set_fn_1_mut(KEYWORD_PRINT, format_map);
|
||||||
reg_unary_mut(lib, FUNC_TO_STRING, format_map, map);
|
lib.set_fn_1_mut(FUNC_TO_STRING, format_map);
|
||||||
reg_unary_mut(lib, KEYWORD_DEBUG, format_map, map);
|
lib.set_fn_1_mut(KEYWORD_DEBUG, format_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_binary(
|
lib.set_fn_2(
|
||||||
lib,
|
|
||||||
"+",
|
"+",
|
||||||
|mut s: String, ch: char| {
|
|mut s: String, ch: char| {
|
||||||
s.push(ch);
|
s.push(ch);
|
||||||
s
|
Ok(s)
|
||||||
},
|
},
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
reg_binary(
|
lib.set_fn_2(
|
||||||
lib,
|
|
||||||
"+",
|
"+",
|
||||||
|mut s: String, s2: String| {
|
|mut s: String, s2: String| {
|
||||||
s.push_str(&s2);
|
s.push_str(&s2);
|
||||||
s
|
Ok(s)
|
||||||
},
|
},
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
reg_binary_mut(lib, "append", |s: &mut String, ch: char| s.push(ch), map);
|
lib.set_fn_2_mut("append", |s: &mut String, ch: char| {
|
||||||
reg_binary_mut(
|
s.push(ch);
|
||||||
lib,
|
Ok(())
|
||||||
|
});
|
||||||
|
lib.set_fn_2_mut(
|
||||||
"append",
|
"append",
|
||||||
|s: &mut String, s2: String| s.push_str(&s2),
|
|s: &mut String, s2: String| {
|
||||||
map,
|
s.push_str(&s2);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
use super::{reg_binary, reg_binary_mut, reg_trinary_mut, reg_unary_mut};
|
|
||||||
|
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::fn_register::map_dynamic as map;
|
use crate::module::FuncReturn;
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
@ -14,19 +12,19 @@ use crate::stdlib::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn prepend<T: Display>(x: T, y: String) -> String {
|
fn prepend<T: Display>(x: T, y: String) -> FuncReturn<String> {
|
||||||
format!("{}{}", x, y)
|
Ok(format!("{}{}", x, y))
|
||||||
}
|
}
|
||||||
fn append<T: Display>(x: String, y: T) -> String {
|
fn append<T: Display>(x: String, y: T) -> FuncReturn<String> {
|
||||||
format!("{}{}", x, y)
|
Ok(format!("{}{}", x, y))
|
||||||
}
|
}
|
||||||
fn sub_string(s: &mut String, start: INT, len: INT) -> String {
|
fn sub_string(s: &mut String, start: INT, len: INT) -> FuncReturn<String> {
|
||||||
let offset = if s.is_empty() || len <= 0 {
|
let offset = if s.is_empty() || len <= 0 {
|
||||||
return "".to_string();
|
return Ok("".to_string());
|
||||||
} else if start < 0 {
|
} else if start < 0 {
|
||||||
0
|
0
|
||||||
} else if (start as usize) >= s.chars().count() {
|
} else if (start as usize) >= s.chars().count() {
|
||||||
return "".to_string();
|
return Ok("".to_string());
|
||||||
} else {
|
} else {
|
||||||
start as usize
|
start as usize
|
||||||
};
|
};
|
||||||
@ -39,17 +37,17 @@ fn sub_string(s: &mut String, start: INT, len: INT) -> String {
|
|||||||
len as usize
|
len as usize
|
||||||
};
|
};
|
||||||
|
|
||||||
chars[offset..][..len].into_iter().collect()
|
Ok(chars[offset..][..len].into_iter().collect())
|
||||||
}
|
}
|
||||||
fn crop_string(s: &mut String, start: INT, len: INT) {
|
fn crop_string(s: &mut String, start: INT, len: INT) -> FuncReturn<()> {
|
||||||
let offset = if s.is_empty() || len <= 0 {
|
let offset = if s.is_empty() || len <= 0 {
|
||||||
s.clear();
|
s.clear();
|
||||||
return;
|
return Ok(());
|
||||||
} else if start < 0 {
|
} else if start < 0 {
|
||||||
0
|
0
|
||||||
} else if (start as usize) >= s.chars().count() {
|
} else if (start as usize) >= s.chars().count() {
|
||||||
s.clear();
|
s.clear();
|
||||||
return;
|
return Ok(());
|
||||||
} else {
|
} else {
|
||||||
start as usize
|
start as usize
|
||||||
};
|
};
|
||||||
@ -67,18 +65,22 @@ fn crop_string(s: &mut String, start: INT, len: INT) {
|
|||||||
chars[offset..][..len]
|
chars[offset..][..len]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|&ch| s.push(ch));
|
.for_each(|&ch| s.push(ch));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! reg_op { ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => {
|
macro_rules! reg_op {
|
||||||
$(reg_binary($lib, $op, $func::<$par>, map);)* };
|
($lib:expr, $op:expr, $func:ident, $($par:ty),*) => {
|
||||||
|
$( $lib.set_fn_2($op, $func::<$par>); )*
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
def_package!(crate:MoreStringPackage:"Additional string utilities, including string building.", lib, {
|
def_package!(crate:MoreStringPackage:"Additional string utilities, including string building.", lib, {
|
||||||
reg_op!(lib, "+", append, INT, bool, char);
|
reg_op!(lib, "+", append, INT, bool, char);
|
||||||
reg_binary_mut(lib, "+", |x: &mut String, _: ()| x.clone(), map);
|
lib.set_fn_2_mut( "+", |x: &mut String, _: ()| Ok(x.clone()));
|
||||||
|
|
||||||
reg_op!(lib, "+", prepend, INT, bool, char);
|
reg_op!(lib, "+", prepend, INT, bool, char);
|
||||||
reg_binary(lib, "+", |_: (), y: String| y, map);
|
lib.set_fn_2("+", |_: (), y: String| Ok(y));
|
||||||
|
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
#[cfg(not(feature = "only_i64"))]
|
#[cfg(not(feature = "only_i64"))]
|
||||||
@ -95,105 +97,95 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
{
|
{
|
||||||
reg_binary(lib, "+", |x: String, y: Array| format!("{}{:?}", x, y), map);
|
lib.set_fn_2("+", |x: String, y: Array| Ok(format!("{}{:?}", x, y)));
|
||||||
reg_binary(lib, "+", |x: Array, y: String| format!("{:?}{}", x, y), map);
|
lib.set_fn_2("+", |x: Array, y: String| Ok(format!("{:?}{}", x, y)));
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_unary_mut(lib, "len", |s: &mut String| s.chars().count() as INT, map);
|
lib.set_fn_1_mut("len", |s: &mut String| Ok(s.chars().count() as INT));
|
||||||
reg_binary_mut(
|
lib.set_fn_2_mut(
|
||||||
lib,
|
|
||||||
"contains",
|
"contains",
|
||||||
|s: &mut String, ch: char| s.contains(ch),
|
|s: &mut String, ch: char| Ok(s.contains(ch)),
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
reg_binary_mut(
|
lib.set_fn_2_mut(
|
||||||
lib,
|
|
||||||
"contains",
|
"contains",
|
||||||
|s: &mut String, find: String| s.contains(&find),
|
|s: &mut String, find: String| Ok(s.contains(&find)),
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
reg_trinary_mut(
|
lib.set_fn_3_mut(
|
||||||
lib,
|
|
||||||
"index_of",
|
"index_of",
|
||||||
|s: &mut String, ch: char, start: INT| {
|
|s: &mut String, ch: char, start: INT| {
|
||||||
let start = if start < 0 {
|
let start = if start < 0 {
|
||||||
0
|
0
|
||||||
} else if (start as usize) >= s.chars().count() {
|
} else if (start as usize) >= s.chars().count() {
|
||||||
return -1 as INT;
|
return Ok(-1 as INT);
|
||||||
} else {
|
} else {
|
||||||
s.chars().take(start as usize).collect::<String>().len()
|
s.chars().take(start as usize).collect::<String>().len()
|
||||||
};
|
};
|
||||||
|
|
||||||
s[start..]
|
Ok(s[start..]
|
||||||
.find(ch)
|
.find(ch)
|
||||||
.map(|index| s[0..start + index].chars().count() as INT)
|
.map(|index| s[0..start + index].chars().count() as INT)
|
||||||
.unwrap_or(-1 as INT)
|
.unwrap_or(-1 as INT))
|
||||||
},
|
},
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
reg_binary_mut(
|
lib.set_fn_2_mut(
|
||||||
lib,
|
|
||||||
"index_of",
|
"index_of",
|
||||||
|s: &mut String, ch: char| {
|
|s: &mut String, ch: char| {
|
||||||
s.find(ch)
|
Ok(s.find(ch)
|
||||||
.map(|index| s[0..index].chars().count() as INT)
|
.map(|index| s[0..index].chars().count() as INT)
|
||||||
.unwrap_or(-1 as INT)
|
.unwrap_or(-1 as INT))
|
||||||
},
|
},
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
reg_trinary_mut(
|
lib.set_fn_3_mut(
|
||||||
lib,
|
|
||||||
"index_of",
|
"index_of",
|
||||||
|s: &mut String, find: String, start: INT| {
|
|s: &mut String, find: String, start: INT| {
|
||||||
let start = if start < 0 {
|
let start = if start < 0 {
|
||||||
0
|
0
|
||||||
} else if (start as usize) >= s.chars().count() {
|
} else if (start as usize) >= s.chars().count() {
|
||||||
return -1 as INT;
|
return Ok(-1 as INT);
|
||||||
} else {
|
} else {
|
||||||
s.chars().take(start as usize).collect::<String>().len()
|
s.chars().take(start as usize).collect::<String>().len()
|
||||||
};
|
};
|
||||||
|
|
||||||
s[start..]
|
Ok(s[start..]
|
||||||
.find(&find)
|
.find(&find)
|
||||||
.map(|index| s[0..start + index].chars().count() as INT)
|
.map(|index| s[0..start + index].chars().count() as INT)
|
||||||
.unwrap_or(-1 as INT)
|
.unwrap_or(-1 as INT))
|
||||||
},
|
},
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
reg_binary_mut(
|
lib.set_fn_2_mut(
|
||||||
lib,
|
|
||||||
"index_of",
|
"index_of",
|
||||||
|s: &mut String, find: String| {
|
|s: &mut String, find: String| {
|
||||||
s.find(&find)
|
Ok(s.find(&find)
|
||||||
.map(|index| s[0..index].chars().count() as INT)
|
.map(|index| s[0..index].chars().count() as INT)
|
||||||
.unwrap_or(-1 as INT)
|
.unwrap_or(-1 as INT))
|
||||||
},
|
},
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
reg_unary_mut(lib, "clear", |s: &mut String| s.clear(), map);
|
lib.set_fn_1_mut("clear", |s: &mut String| {
|
||||||
reg_binary_mut(lib, "append", |s: &mut String, ch: char| s.push(ch), map);
|
s.clear();
|
||||||
reg_binary_mut(
|
Ok(())
|
||||||
lib,
|
});
|
||||||
|
lib.set_fn_2_mut( "append", |s: &mut String, ch: char| {
|
||||||
|
s.push(ch);
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
lib.set_fn_2_mut(
|
||||||
"append",
|
"append",
|
||||||
|s: &mut String, add: String| s.push_str(&add),
|
|s: &mut String, add: String| {
|
||||||
map,
|
s.push_str(&add);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
);
|
);
|
||||||
reg_trinary_mut(lib, "sub_string", sub_string, map);
|
lib.set_fn_3_mut( "sub_string", sub_string);
|
||||||
reg_binary_mut(
|
lib.set_fn_2_mut(
|
||||||
lib,
|
|
||||||
"sub_string",
|
"sub_string",
|
||||||
|s: &mut String, start: INT| sub_string(s, start, s.len() as INT),
|
|s: &mut String, start: INT| sub_string(s, start, s.len() as INT),
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
reg_trinary_mut(lib, "crop", crop_string, map);
|
lib.set_fn_3_mut( "crop", crop_string);
|
||||||
reg_binary_mut(
|
lib.set_fn_2_mut(
|
||||||
lib,
|
|
||||||
"crop",
|
"crop",
|
||||||
|s: &mut String, start: INT| crop_string(s, start, s.len() as INT),
|
|s: &mut String, start: INT| crop_string(s, start, s.len() as INT),
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
reg_binary_mut(
|
lib.set_fn_2_mut(
|
||||||
lib,
|
|
||||||
"truncate",
|
"truncate",
|
||||||
|s: &mut String, len: INT| {
|
|s: &mut String, len: INT| {
|
||||||
if len >= 0 {
|
if len >= 0 {
|
||||||
@ -203,61 +195,55 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str
|
|||||||
} else {
|
} else {
|
||||||
s.clear();
|
s.clear();
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
},
|
},
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
reg_trinary_mut(
|
lib.set_fn_3_mut(
|
||||||
lib,
|
|
||||||
"pad",
|
"pad",
|
||||||
|s: &mut String, len: INT, ch: char| {
|
|s: &mut String, len: INT, ch: char| {
|
||||||
for _ in 0..s.chars().count() - len as usize {
|
for _ in 0..s.chars().count() - len as usize {
|
||||||
s.push(ch);
|
s.push(ch);
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
},
|
},
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
reg_trinary_mut(
|
lib.set_fn_3_mut(
|
||||||
lib,
|
|
||||||
"replace",
|
"replace",
|
||||||
|s: &mut String, find: String, sub: String| {
|
|s: &mut String, find: String, sub: String| {
|
||||||
let new_str = s.replace(&find, &sub);
|
let new_str = s.replace(&find, &sub);
|
||||||
s.clear();
|
s.clear();
|
||||||
s.push_str(&new_str);
|
s.push_str(&new_str);
|
||||||
|
Ok(())
|
||||||
},
|
},
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
reg_trinary_mut(
|
lib.set_fn_3_mut(
|
||||||
lib,
|
|
||||||
"replace",
|
"replace",
|
||||||
|s: &mut String, find: String, sub: char| {
|
|s: &mut String, find: String, sub: char| {
|
||||||
let new_str = s.replace(&find, &sub.to_string());
|
let new_str = s.replace(&find, &sub.to_string());
|
||||||
s.clear();
|
s.clear();
|
||||||
s.push_str(&new_str);
|
s.push_str(&new_str);
|
||||||
|
Ok(())
|
||||||
},
|
},
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
reg_trinary_mut(
|
lib.set_fn_3_mut(
|
||||||
lib,
|
|
||||||
"replace",
|
"replace",
|
||||||
|s: &mut String, find: char, sub: String| {
|
|s: &mut String, find: char, sub: String| {
|
||||||
let new_str = s.replace(&find.to_string(), &sub);
|
let new_str = s.replace(&find.to_string(), &sub);
|
||||||
s.clear();
|
s.clear();
|
||||||
s.push_str(&new_str);
|
s.push_str(&new_str);
|
||||||
|
Ok(())
|
||||||
},
|
},
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
reg_trinary_mut(
|
lib.set_fn_3_mut(
|
||||||
lib,
|
|
||||||
"replace",
|
"replace",
|
||||||
|s: &mut String, find: char, sub: char| {
|
|s: &mut String, find: char, sub: char| {
|
||||||
let new_str = s.replace(&find.to_string(), &sub.to_string());
|
let new_str = s.replace(&find.to_string(), &sub.to_string());
|
||||||
s.clear();
|
s.clear();
|
||||||
s.push_str(&new_str);
|
s.push_str(&new_str);
|
||||||
|
Ok(())
|
||||||
},
|
},
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
reg_unary_mut(
|
lib.set_fn_1_mut(
|
||||||
lib,
|
|
||||||
"trim",
|
"trim",
|
||||||
|s: &mut String| {
|
|s: &mut String| {
|
||||||
let trimmed = s.trim();
|
let trimmed = s.trim();
|
||||||
@ -265,7 +251,7 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str
|
|||||||
if trimmed.len() < s.len() {
|
if trimmed.len() < s.len() {
|
||||||
*s = trimmed.to_string();
|
*s = trimmed.to_string();
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
},
|
},
|
||||||
map,
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
use super::logic::{eq, gt, gte, lt, lte, ne};
|
use super::logic::{eq, gt, gte, lt, lte, ne};
|
||||||
use super::math_basic::MAX_INT;
|
use super::math_basic::MAX_INT;
|
||||||
use super::{reg_binary, reg_none, reg_unary};
|
|
||||||
|
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::fn_register::{map_dynamic as map, map_result as result};
|
use crate::module::FuncReturn;
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
@ -14,10 +13,9 @@ use crate::stdlib::time::Instant;
|
|||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, {
|
def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, {
|
||||||
// Register date/time functions
|
// Register date/time functions
|
||||||
reg_none(lib, "timestamp", || Instant::now(), map);
|
lib.set_fn_0("timestamp", || Ok(Instant::now()));
|
||||||
|
|
||||||
reg_binary(
|
lib.set_fn_2(
|
||||||
lib,
|
|
||||||
"-",
|
"-",
|
||||||
|ts1: Instant, ts2: Instant| {
|
|ts1: Instant, ts2: Instant| {
|
||||||
if ts2 > ts1 {
|
if ts2 > ts1 {
|
||||||
@ -63,18 +61,16 @@ def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
result,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
reg_binary(lib, "<", lt::<Instant>, map);
|
lib.set_fn_2("<", lt::<Instant>);
|
||||||
reg_binary(lib, "<=", lte::<Instant>, map);
|
lib.set_fn_2("<=", lte::<Instant>);
|
||||||
reg_binary(lib, ">", gt::<Instant>, map);
|
lib.set_fn_2(">", gt::<Instant>);
|
||||||
reg_binary(lib, ">=", gte::<Instant>, map);
|
lib.set_fn_2(">=", gte::<Instant>);
|
||||||
reg_binary(lib, "==", eq::<Instant>, map);
|
lib.set_fn_2("==", eq::<Instant>);
|
||||||
reg_binary(lib, "!=", ne::<Instant>, map);
|
lib.set_fn_2("!=", ne::<Instant>);
|
||||||
|
|
||||||
reg_unary(
|
lib.set_fn_1(
|
||||||
lib,
|
|
||||||
"elapsed",
|
"elapsed",
|
||||||
|timestamp: Instant| {
|
|timestamp: Instant| {
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
@ -96,6 +92,5 @@ def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, {
|
|||||||
return Ok(seconds as INT);
|
return Ok(seconds as INT);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
result,
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,425 +0,0 @@
|
|||||||
use super::PackageStore;
|
|
||||||
|
|
||||||
use crate::any::{Dynamic, Variant};
|
|
||||||
use crate::calc_fn_hash;
|
|
||||||
use crate::fn_native::{FnCallArgs, NativeFunction, NativeFunctionABI::*};
|
|
||||||
use crate::result::EvalAltResult;
|
|
||||||
use crate::token::Position;
|
|
||||||
|
|
||||||
use crate::stdlib::{
|
|
||||||
any::TypeId,
|
|
||||||
boxed::Box,
|
|
||||||
iter::empty,
|
|
||||||
mem,
|
|
||||||
string::{String, ToString},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// This macro makes it easy to define a _package_ and register functions into it.
|
|
||||||
///
|
|
||||||
/// Functions can be added to the package using a number of helper functions under the `packages` module,
|
|
||||||
/// such as `reg_unary`, `reg_binary_mut`, `reg_trinary_mut` etc.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use rhai::Dynamic;
|
|
||||||
/// use rhai::def_package;
|
|
||||||
/// use rhai::packages::reg_binary;
|
|
||||||
///
|
|
||||||
/// fn add(x: i64, y: i64) -> i64 { x + y }
|
|
||||||
///
|
|
||||||
/// def_package!(rhai:MyPackage:"My super-duper package", lib,
|
|
||||||
/// {
|
|
||||||
/// reg_binary(lib, "my_add", add, |v, _| Ok(v.into()));
|
|
||||||
/// // ^^^^^^^^^^^^^^^^^^^
|
|
||||||
/// // map into Result<Dynamic, Box<EvalAltResult>>
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// The above defines a package named 'MyPackage' with a single function named 'my_add'.
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! def_package {
|
|
||||||
($root:ident : $package:ident : $comment:expr , $lib:ident , $block:stmt) => {
|
|
||||||
#[doc=$comment]
|
|
||||||
pub struct $package($root::packages::PackageLibrary);
|
|
||||||
|
|
||||||
impl $root::packages::Package for $package {
|
|
||||||
fn get(&self) -> $root::packages::PackageLibrary {
|
|
||||||
self.0.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init($lib: &mut $root::packages::PackageStore) {
|
|
||||||
$block
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl $package {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
let mut pkg = $root::packages::PackageStore::new();
|
|
||||||
<Self as $root::packages::Package>::init(&mut pkg);
|
|
||||||
Self(pkg.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a function with no parameters to the package.
|
|
||||||
///
|
|
||||||
/// `map_result` is a function that maps the return type of the function to `Result<Dynamic, EvalAltResult>`.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use rhai::Dynamic;
|
|
||||||
/// use rhai::def_package;
|
|
||||||
/// use rhai::packages::reg_none;
|
|
||||||
///
|
|
||||||
/// fn get_answer() -> i64 { 42 }
|
|
||||||
///
|
|
||||||
/// def_package!(rhai:MyPackage:"My super-duper package", lib,
|
|
||||||
/// {
|
|
||||||
/// reg_none(lib, "my_answer", get_answer, |v, _| Ok(v.into()));
|
|
||||||
/// // ^^^^^^^^^^^^^^^^^^^
|
|
||||||
/// // map into Result<Dynamic, Box<EvalAltResult>>
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// The above defines a package named 'MyPackage' with a single function named 'my_add_1'.
|
|
||||||
pub fn reg_none<R>(
|
|
||||||
lib: &mut PackageStore,
|
|
||||||
fn_name: &'static str,
|
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn() -> R + 'static,
|
|
||||||
#[cfg(feature = "sync")] func: impl Fn() -> R + Send + Sync + 'static,
|
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))] map_result: impl Fn(R, Position) -> Result<Dynamic, Box<EvalAltResult>>
|
|
||||||
+ 'static,
|
|
||||||
#[cfg(feature = "sync")] map_result: impl Fn(R, Position) -> Result<Dynamic, Box<EvalAltResult>>
|
|
||||||
+ Send
|
|
||||||
+ Sync
|
|
||||||
+ 'static,
|
|
||||||
) {
|
|
||||||
let hash_fn_native = calc_fn_hash(empty(), fn_name, ([] as [TypeId; 0]).iter().cloned());
|
|
||||||
|
|
||||||
let f = Box::new(move |_: &mut FnCallArgs, pos| {
|
|
||||||
let r = func();
|
|
||||||
map_result(r, pos)
|
|
||||||
});
|
|
||||||
|
|
||||||
lib.functions
|
|
||||||
.insert(hash_fn_native, Box::new(NativeFunction::new(f, Pure)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a function with one parameter to the package.
|
|
||||||
///
|
|
||||||
/// `map_result` is a function that maps the return type of the function to `Result<Dynamic, EvalAltResult>`.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use rhai::Dynamic;
|
|
||||||
/// use rhai::def_package;
|
|
||||||
/// use rhai::packages::reg_unary;
|
|
||||||
///
|
|
||||||
/// fn add_1(x: i64) -> i64 { x + 1 }
|
|
||||||
///
|
|
||||||
/// def_package!(rhai:MyPackage:"My super-duper package", lib,
|
|
||||||
/// {
|
|
||||||
/// reg_unary(lib, "my_add_1", add_1, |v, _| Ok(v.into()));
|
|
||||||
/// // ^^^^^^^^^^^^^^^^^^^
|
|
||||||
/// // map into Result<Dynamic, Box<EvalAltResult>>
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// The above defines a package named 'MyPackage' with a single function named 'my_add_1'.
|
|
||||||
pub fn reg_unary<T: Variant + Clone, R>(
|
|
||||||
lib: &mut PackageStore,
|
|
||||||
fn_name: &'static str,
|
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(T) -> R + 'static,
|
|
||||||
#[cfg(feature = "sync")] func: impl Fn(T) -> R + Send + Sync + 'static,
|
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))] map_result: impl Fn(R, Position) -> Result<Dynamic, Box<EvalAltResult>>
|
|
||||||
+ 'static,
|
|
||||||
#[cfg(feature = "sync")] map_result: impl Fn(R, Position) -> Result<Dynamic, Box<EvalAltResult>>
|
|
||||||
+ Send
|
|
||||||
+ Sync
|
|
||||||
+ 'static,
|
|
||||||
) {
|
|
||||||
//println!("register {}({})", fn_name, crate::std::any::type_name::<T>());
|
|
||||||
|
|
||||||
let hash_fn_native = calc_fn_hash(empty(), fn_name, [TypeId::of::<T>()].iter().cloned());
|
|
||||||
|
|
||||||
let f = Box::new(move |args: &mut FnCallArgs, pos| {
|
|
||||||
let mut drain = args.iter_mut();
|
|
||||||
let x = mem::take(*drain.next().unwrap()).cast::<T>();
|
|
||||||
|
|
||||||
let r = func(x);
|
|
||||||
map_result(r, pos)
|
|
||||||
});
|
|
||||||
|
|
||||||
lib.functions
|
|
||||||
.insert(hash_fn_native, Box::new(NativeFunction::new(f, Pure)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a function with one mutable reference parameter to the package.
|
|
||||||
///
|
|
||||||
/// `map_result` is a function that maps the return type of the function to `Result<Dynamic, EvalAltResult>`.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use rhai::{Dynamic, EvalAltResult};
|
|
||||||
/// use rhai::def_package;
|
|
||||||
/// use rhai::packages::reg_unary_mut;
|
|
||||||
///
|
|
||||||
/// fn inc(x: &mut i64) -> Result<Dynamic, Box<EvalAltResult>> {
|
|
||||||
/// if *x == 0 {
|
|
||||||
/// return Err("boo! zero cannot be incremented!".into())
|
|
||||||
/// }
|
|
||||||
/// *x += 1;
|
|
||||||
/// Ok(().into())
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// def_package!(rhai:MyPackage:"My super-duper package", lib,
|
|
||||||
/// {
|
|
||||||
/// reg_unary_mut(lib, "try_inc", inc, |r, _| r);
|
|
||||||
/// // ^^^^^^^^
|
|
||||||
/// // map into Result<Dynamic, Box<EvalAltResult>>
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// The above defines a package named 'MyPackage' with a single fallible function named 'try_inc'
|
|
||||||
/// which takes a first argument of `&mut`, return a `Result<Dynamic, Box<EvalAltResult>>`.
|
|
||||||
pub fn reg_unary_mut<T: Variant + Clone, R>(
|
|
||||||
lib: &mut PackageStore,
|
|
||||||
fn_name: &'static str,
|
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(&mut T) -> R + 'static,
|
|
||||||
#[cfg(feature = "sync")] func: impl Fn(&mut T) -> R + Send + Sync + 'static,
|
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))] map_result: impl Fn(R, Position) -> Result<Dynamic, Box<EvalAltResult>>
|
|
||||||
+ 'static,
|
|
||||||
#[cfg(feature = "sync")] map_result: impl Fn(R, Position) -> Result<Dynamic, Box<EvalAltResult>>
|
|
||||||
+ Send
|
|
||||||
+ Sync
|
|
||||||
+ 'static,
|
|
||||||
) {
|
|
||||||
//println!("register {}(&mut {})", fn_name, crate::std::any::type_name::<T>());
|
|
||||||
|
|
||||||
let hash_fn_native = calc_fn_hash(empty(), fn_name, [TypeId::of::<T>()].iter().cloned());
|
|
||||||
|
|
||||||
let f = Box::new(move |args: &mut FnCallArgs, pos| {
|
|
||||||
let mut drain = args.iter_mut();
|
|
||||||
let x: &mut T = drain.next().unwrap().downcast_mut().unwrap();
|
|
||||||
|
|
||||||
let r = func(x);
|
|
||||||
map_result(r, pos)
|
|
||||||
});
|
|
||||||
|
|
||||||
lib.functions
|
|
||||||
.insert(hash_fn_native, Box::new(NativeFunction::new(f, Method)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a function with two parameters to the package.
|
|
||||||
///
|
|
||||||
/// `map_result` is a function that maps the return type of the function to `Result<Dynamic, EvalAltResult>`.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use rhai::Dynamic;
|
|
||||||
/// use rhai::def_package;
|
|
||||||
/// use rhai::packages::reg_binary;
|
|
||||||
///
|
|
||||||
/// fn add(x: i64, y: i64) -> i64 { x + y }
|
|
||||||
///
|
|
||||||
/// def_package!(rhai:MyPackage:"My super-duper package", lib,
|
|
||||||
/// {
|
|
||||||
/// reg_binary(lib, "my_add", add, |v, _| Ok(v.into()));
|
|
||||||
/// // ^^^^^^^^^^^^^^^^^^^
|
|
||||||
/// // map into Result<Dynamic, Box<EvalAltResult>>
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// The above defines a package named 'MyPackage' with a single function named 'my_add'.
|
|
||||||
pub fn reg_binary<A: Variant + Clone, B: Variant + Clone, R>(
|
|
||||||
lib: &mut PackageStore,
|
|
||||||
fn_name: &'static str,
|
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(A, B) -> R + 'static,
|
|
||||||
#[cfg(feature = "sync")] func: impl Fn(A, B) -> R + Send + Sync + 'static,
|
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))] map_result: impl Fn(R, Position) -> Result<Dynamic, Box<EvalAltResult>>
|
|
||||||
+ 'static,
|
|
||||||
#[cfg(feature = "sync")] map_result: impl Fn(R, Position) -> Result<Dynamic, Box<EvalAltResult>>
|
|
||||||
+ Send
|
|
||||||
+ Sync
|
|
||||||
+ 'static,
|
|
||||||
) {
|
|
||||||
//println!("register {}({}, {})", fn_name, crate::std::any::type_name::<A>(), crate::std::any::type_name::<B>());
|
|
||||||
|
|
||||||
let hash_fn_native = calc_fn_hash(
|
|
||||||
empty(),
|
|
||||||
fn_name,
|
|
||||||
[TypeId::of::<A>(), TypeId::of::<B>()].iter().cloned(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let f = Box::new(move |args: &mut FnCallArgs, pos| {
|
|
||||||
let mut drain = args.iter_mut();
|
|
||||||
let x = mem::take(*drain.next().unwrap()).cast::<A>();
|
|
||||||
let y = mem::take(*drain.next().unwrap()).cast::<B>();
|
|
||||||
|
|
||||||
let r = func(x, y);
|
|
||||||
map_result(r, pos)
|
|
||||||
});
|
|
||||||
|
|
||||||
lib.functions
|
|
||||||
.insert(hash_fn_native, Box::new(NativeFunction::new(f, Pure)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a function with two parameters (the first one being a mutable reference) to the package.
|
|
||||||
///
|
|
||||||
/// `map_result` is a function that maps the return type of the function to `Result<Dynamic, EvalAltResult>`.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use rhai::{Dynamic, EvalAltResult};
|
|
||||||
/// use rhai::def_package;
|
|
||||||
/// use rhai::packages::reg_binary_mut;
|
|
||||||
///
|
|
||||||
/// fn add(x: &mut i64, y: i64) -> Result<Dynamic, Box<EvalAltResult>> {
|
|
||||||
/// if y == 0 {
|
|
||||||
/// return Err("boo! cannot add zero!".into())
|
|
||||||
/// }
|
|
||||||
/// *x += y;
|
|
||||||
/// Ok(().into())
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// def_package!(rhai:MyPackage:"My super-duper package", lib,
|
|
||||||
/// {
|
|
||||||
/// reg_binary_mut(lib, "try_add", add, |r, _| r);
|
|
||||||
/// // ^^^^^^^^
|
|
||||||
/// // map into Result<Dynamic, Box<EvalAltResult>>
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// The above defines a package named 'MyPackage' with a single fallible function named 'try_add'
|
|
||||||
/// which takes a first argument of `&mut`, return a `Result<Dynamic, Box<EvalAltResult>>`.
|
|
||||||
pub fn reg_binary_mut<A: Variant + Clone, B: Variant + Clone, R>(
|
|
||||||
lib: &mut PackageStore,
|
|
||||||
fn_name: &'static str,
|
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B) -> R + 'static,
|
|
||||||
#[cfg(feature = "sync")] func: impl Fn(&mut A, B) -> R + Send + Sync + 'static,
|
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))] map_result: impl Fn(R, Position) -> Result<Dynamic, Box<EvalAltResult>>
|
|
||||||
+ 'static,
|
|
||||||
#[cfg(feature = "sync")] map_result: impl Fn(R, Position) -> Result<Dynamic, Box<EvalAltResult>>
|
|
||||||
+ Send
|
|
||||||
+ Sync
|
|
||||||
+ 'static,
|
|
||||||
) {
|
|
||||||
//println!("register {}(&mut {}, {})", fn_name, crate::std::any::type_name::<A>(), crate::std::any::type_name::<B>());
|
|
||||||
|
|
||||||
let hash_fn_native = calc_fn_hash(
|
|
||||||
empty(),
|
|
||||||
fn_name,
|
|
||||||
[TypeId::of::<A>(), TypeId::of::<B>()].iter().cloned(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let f = Box::new(move |args: &mut FnCallArgs, pos| {
|
|
||||||
let mut drain = args.iter_mut();
|
|
||||||
let x: &mut A = drain.next().unwrap().downcast_mut().unwrap();
|
|
||||||
let y = mem::take(*drain.next().unwrap()).cast::<B>();
|
|
||||||
|
|
||||||
let r = func(x, y);
|
|
||||||
map_result(r, pos)
|
|
||||||
});
|
|
||||||
|
|
||||||
lib.functions
|
|
||||||
.insert(hash_fn_native, Box::new(NativeFunction::new(f, Method)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a function with three parameters to the package.
|
|
||||||
///
|
|
||||||
/// `map_result` is a function that maps the return type of the function to `Result<Dynamic, EvalAltResult>`.
|
|
||||||
pub fn reg_trinary<A: Variant + Clone, B: Variant + Clone, C: Variant + Clone, R>(
|
|
||||||
lib: &mut PackageStore,
|
|
||||||
fn_name: &'static str,
|
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(A, B, C) -> R + 'static,
|
|
||||||
#[cfg(feature = "sync")] func: impl Fn(A, B, C) -> R + Send + Sync + 'static,
|
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))] map_result: impl Fn(R, Position) -> Result<Dynamic, Box<EvalAltResult>>
|
|
||||||
+ 'static,
|
|
||||||
#[cfg(feature = "sync")] map_result: impl Fn(R, Position) -> Result<Dynamic, Box<EvalAltResult>>
|
|
||||||
+ Send
|
|
||||||
+ Sync
|
|
||||||
+ 'static,
|
|
||||||
) {
|
|
||||||
//println!("register {}({}, {}, {})", fn_name, crate::std::any::type_name::<A>(), crate::std::any::type_name::<B>(), crate::std::any::type_name::<C>());
|
|
||||||
|
|
||||||
let hash_fn_native = calc_fn_hash(
|
|
||||||
empty(),
|
|
||||||
fn_name,
|
|
||||||
[TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()]
|
|
||||||
.iter()
|
|
||||||
.cloned(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let f = Box::new(move |args: &mut FnCallArgs, pos| {
|
|
||||||
let mut drain = args.iter_mut();
|
|
||||||
let x = mem::take(*drain.next().unwrap()).cast::<A>();
|
|
||||||
let y = mem::take(*drain.next().unwrap()).cast::<B>();
|
|
||||||
let z = mem::take(*drain.next().unwrap()).cast::<C>();
|
|
||||||
|
|
||||||
let r = func(x, y, z);
|
|
||||||
map_result(r, pos)
|
|
||||||
});
|
|
||||||
|
|
||||||
lib.functions
|
|
||||||
.insert(hash_fn_native, Box::new(NativeFunction::new(f, Pure)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a function with three parameters (the first one is a mutable reference) to the package.
|
|
||||||
///
|
|
||||||
/// `map_result` is a function that maps the return type of the function to `Result<Dynamic, EvalAltResult>`.
|
|
||||||
pub fn reg_trinary_mut<A: Variant + Clone, B: Variant + Clone, C: Variant + Clone, R>(
|
|
||||||
lib: &mut PackageStore,
|
|
||||||
fn_name: &'static str,
|
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B, C) -> R + 'static,
|
|
||||||
#[cfg(feature = "sync")] func: impl Fn(&mut A, B, C) -> R + Send + Sync + 'static,
|
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))] map_result: impl Fn(R, Position) -> Result<Dynamic, Box<EvalAltResult>>
|
|
||||||
+ 'static,
|
|
||||||
#[cfg(feature = "sync")] map_result: impl Fn(R, Position) -> Result<Dynamic, Box<EvalAltResult>>
|
|
||||||
+ Send
|
|
||||||
+ Sync
|
|
||||||
+ 'static,
|
|
||||||
) {
|
|
||||||
//println!("register {}(&mut {}, {}, {})", fn_name, crate::std::any::type_name::<A>(), crate::std::any::type_name::<B>(), crate::std::any::type_name::<C>());
|
|
||||||
|
|
||||||
let hash_fn_native = calc_fn_hash(
|
|
||||||
empty(),
|
|
||||||
fn_name,
|
|
||||||
[TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()]
|
|
||||||
.iter()
|
|
||||||
.cloned(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let f = Box::new(move |args: &mut FnCallArgs, pos| {
|
|
||||||
let mut drain = args.iter_mut();
|
|
||||||
let x: &mut A = drain.next().unwrap().downcast_mut().unwrap();
|
|
||||||
let y = mem::take(*drain.next().unwrap()).cast::<B>();
|
|
||||||
let z = mem::take(*drain.next().unwrap()).cast::<C>();
|
|
||||||
|
|
||||||
let r = func(x, y, z);
|
|
||||||
map_result(r, pos)
|
|
||||||
});
|
|
||||||
|
|
||||||
lib.functions
|
|
||||||
.insert(hash_fn_native, Box::new(NativeFunction::new(f, Method)));
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user