From 30e5e2f034c641709d226d034dae8d5e6093c9cb Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 13 May 2020 19:21:42 +0800 Subject: [PATCH] Use modules to implement packages. --- src/api.rs | 7 +- src/engine.rs | 27 +-- src/fn_native.rs | 7 + src/fn_register.rs | 38 ++-- src/lib.rs | 3 +- src/module.rs | 269 ++++++++++++---------- src/optimize.rs | 11 +- src/packages/arithmetic.rs | 152 ++++++------- src/packages/array_basic.rs | 72 +++--- src/packages/iter_basic.rs | 44 ++-- src/packages/logic.rs | 66 +++--- src/packages/map_basic.rs | 46 ++-- src/packages/math_basic.rs | 106 +++++---- src/packages/mod.rs | 113 +++++----- src/packages/string_basic.rs | 64 +++--- src/packages/string_more.rs | 158 ++++++------- src/packages/time_basic.rs | 25 +-- src/packages/utils.rs | 425 ----------------------------------- 18 files changed, 610 insertions(+), 1023 deletions(-) delete mode 100644 src/packages/utils.rs diff --git a/src/api.rs b/src/api.rs index acb353d9..d69933e9 100644 --- a/src/api.rs +++ b/src/api.rs @@ -125,9 +125,8 @@ impl Engine { /// Register an iterator adapter for a type with the `Engine`. /// This is an advanced feature. pub fn register_iterator(&mut self, f: F) { - self.base_package - .type_iterators - .insert(TypeId::of::(), Box::new(f)); + self.global_module + .set_iterator(TypeId::of::(), Box::new(f)); } /// 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. /// let ast = engine.compile_scripts_with_scope(&mut scope, &[ /// "if x > 40", // all 'x' are replaced with 42 - /// "{ x } el" + /// "{ x } el", /// "se { 0 }" // segments do not need to be valid scripts! /// ])?; /// diff --git a/src/engine.rs b/src/engine.rs index e92d538b..2acb7fad 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -4,10 +4,9 @@ use crate::any::{Dynamic, Union}; use crate::calc_fn_hash; use crate::error::ParseErrorType; use crate::fn_native::{FnCallArgs, NativeFunctionABI, PrintCallback}; +use crate::module::Module; use crate::optimize::OptimizationLevel; -use crate::packages::{ - CorePackage, Package, PackageLibrary, PackageStore, PackagesCollection, StandardPackage, -}; +use crate::packages::{CorePackage, Package, PackageLibrary, PackagesCollection, StandardPackage}; use crate::parser::{Expr, FnAccess, FnDef, ReturnType, SharedFnDef, Stmt, AST}; use crate::result::EvalAltResult; use crate::scope::{EntryType as ScopeEntryType, Scope}; @@ -15,7 +14,7 @@ use crate::token::Position; use crate::utils::{StaticVec, EMPTY_TYPE_ID}; #[cfg(not(feature = "no_module"))] -use crate::module::{resolvers, Module, ModuleRef, ModuleResolver}; +use crate::module::{resolvers, ModuleRef, ModuleResolver}; #[cfg(feature = "no_module")] 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`. 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, - /// A collection of all library packages loaded into the engine. - pub(crate) base_package: PackageStore, + /// A module resolution service. #[cfg(not(feature = "no_module"))] pub(crate) module_resolver: Option>, + /// A hashmap mapping type names to pretty-print names. pub(crate) type_names: HashMap, @@ -305,7 +306,7 @@ impl Default for Engine { // Create the new scripting Engine let mut engine = Self { packages: Default::default(), - base_package: Default::default(), + global_module: Default::default(), #[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_std"))] @@ -450,7 +451,7 @@ impl Engine { pub fn new_raw() -> Self { Self { packages: Default::default(), - base_package: Default::default(), + global_module: Default::default(), #[cfg(not(feature = "no_module"))] module_resolver: None, @@ -549,8 +550,8 @@ impl Engine { // Search built-in's and external functions if let Some(func) = self - .base_package - .get_function(hashes.0) + .global_module + .get_fn(hashes.0) .or_else(|| self.packages.get_function(hashes.0)) { let mut backup: Dynamic = Default::default(); @@ -725,7 +726,7 @@ impl Engine { // Has a system function an override? fn has_override(&self, state: &State, hashes: (u64, u64)) -> bool { // First check registered functions - self.base_package.contains_function(hashes.0) + self.global_module.contains_fn(hashes.0) // Then check packages || self.packages.contains_function(hashes.0) // Then check script-defined functions @@ -1571,7 +1572,7 @@ impl Engine { let tid = iter_type.type_id(); if let Some(iter_fn) = self - .base_package + .global_module .get_iterator(tid) .or_else(|| self.packages.get_iterator(tid)) { diff --git a/src/fn_native.rs b/src/fn_native.rs index 12134550..b56d2644 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -127,3 +127,10 @@ pub type SharedNativeFunction = Rc>; /// An external native Rust function. #[cfg(feature = "sync")] pub type SharedNativeFunction = Arc>; + +/// A type iterator function. +#[cfg(not(feature = "sync"))] +pub type SharedIteratorFunction = Rc>; +/// An external native Rust function. +#[cfg(feature = "sync")] +pub type SharedIteratorFunction = Arc>; diff --git a/src/fn_register.rs b/src/fn_register.rs index 55271ae1..80e09cd5 100644 --- a/src/fn_register.rs +++ b/src/fn_register.rs @@ -4,10 +4,10 @@ use crate::any::{Dynamic, Variant}; 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::token::Position; -use crate::utils::calc_fn_spec; use crate::stdlib::{any::TypeId, boxed::Box, iter::empty, mem, string::ToString}; @@ -134,14 +134,13 @@ pub fn by_value(data: &mut Dynamic) -> T { /// This macro creates a closure wrapping a registered function. 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 ABI type -// ^ result mapping function -// ^ function parameter generic type name (A, B, C etc.) -// ^ dereferencing function +// ^ result mapping function +// ^ function parameter generic type name (A, B, C etc.) +// ^ 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! #[allow(unused_variables, unused_mut)] @@ -157,7 +156,7 @@ macro_rules! make_func { // Map the result $map(r, pos) - }), $abi); + }) }; } @@ -209,9 +208,10 @@ macro_rules! def_register { > RegisterFn for Engine { fn register_fn(&mut self, name: &str, f: FN) { - let func = make_func!(f : $abi ; map_dynamic ; $($par => $clone),*); - let hash = calc_fn_spec(empty(), name, [$(TypeId::of::<$par>()),*].iter().cloned()); - self.base_package.functions.insert(hash, Box::new(func)); + self.global_module.set_fn(name.to_string(), $abi, FnAccess::Public, + &[$(TypeId::of::<$par>()),*], + make_func!(f : map_dynamic ; $($par => $clone),*) + ); } } @@ -226,9 +226,10 @@ macro_rules! def_register { > RegisterDynamicFn for Engine { fn register_dynamic_fn(&mut self, name: &str, f: FN) { - let func = make_func!(f : $abi ; map_identity ; $($par => $clone),*); - let hash = calc_fn_spec(empty(), name, [$(TypeId::of::<$par>()),*].iter().cloned()); - self.base_package.functions.insert(hash, Box::new(func)); + self.global_module.set_fn(name.to_string(), $abi, FnAccess::Public, + &[$(TypeId::of::<$par>()),*], + make_func!(f : map_identity ; $($par => $clone),*) + ); } } @@ -244,9 +245,10 @@ macro_rules! def_register { > RegisterResultFn for Engine { fn register_result_fn(&mut self, name: &str, f: FN) { - let func = make_func!(f : $abi ; map_result ; $($par => $clone),*); - let hash = calc_fn_spec(empty(), name, [$(TypeId::of::<$par>()),*].iter().cloned()); - self.base_package.functions.insert(hash, Box::new(func)); + self.global_module.set_fn(name.to_string(), $abi, FnAccess::Public, + &[$(TypeId::of::<$par>()),*], + make_func!(f : map_result ; $($par => $clone),*) + ); } } diff --git a/src/lib.rs b/src/lib.rs index a912bdab..f82bc6d3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -93,6 +93,7 @@ pub use error::{ParseError, ParseErrorType}; pub use fn_call::FuncArgs; pub use fn_native::NativeCallable; pub use fn_register::{RegisterDynamicFn, RegisterFn, RegisterResultFn}; +pub use module::Module; pub use parser::{AST, INT}; pub use result::EvalAltResult; pub use scope::Scope; @@ -112,7 +113,7 @@ pub use engine::Map; pub use parser::FLOAT; #[cfg(not(feature = "no_module"))] -pub use module::{Module, ModuleResolver}; +pub use module::ModuleResolver; #[cfg(not(feature = "no_module"))] pub mod module_resolvers { diff --git a/src/module.rs b/src/module.rs index f86b2dca..d1bcabb1 100644 --- a/src/module.rs +++ b/src/module.rs @@ -1,12 +1,11 @@ //! Module defining external-loaded modules for Rhai. -#![cfg(not(feature = "no_module"))] use crate::any::{Dynamic, Variant}; use crate::calc_fn_hash; use crate::engine::{Engine, FunctionsLib}; use crate::fn_native::{ - FnAny, FnCallArgs, NativeCallable, NativeFunction, NativeFunctionABI, NativeFunctionABI::*, - SharedNativeFunction, + FnAny, FnCallArgs, IteratorFn, NativeCallable, NativeFunction, NativeFunctionABI, + NativeFunctionABI::*, SharedIteratorFunction, SharedNativeFunction, }; use crate::parser::{FnAccess, FnDef, SharedFnDef, AST}; use crate::result::EvalAltResult; @@ -30,43 +29,17 @@ use crate::stdlib::{ 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>; -} - -/// 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>; -} - /// Default function access mode. const DEF_ACCESS: FnAccess = FnAccess::Public; /// Return type of module-level Rust function. -type FuncReturn = Result>; +pub type FuncReturn = Result>; /// An imported module, which may contain variables, sub-modules, /// external Rust functions, and script-defined functions. /// /// Not available under the `no_module` feature. -#[derive(Default, Clone)] +#[derive(Clone, Default)] pub struct Module { /// Sub-modules. modules: HashMap, @@ -88,6 +61,9 @@ pub struct Module { /// Flattened collection of all script-defined functions, including those in sub-modules. all_fn_lib: FunctionsLib, + + /// Iterator functions, keyed by the type producing the iterator. + type_iterators: HashMap, } impl fmt::Debug for Module { @@ -176,8 +152,8 @@ impl Module { /// module.set_var("answer", 42_i64); /// assert_eq!(module.get_var_value::("answer").unwrap(), 42); /// ``` - pub fn set_var, T: Into>(&mut self, name: K, value: T) { - self.variables.insert(name.into(), value.into()); + pub fn set_var, T: Variant + Clone>(&mut self, name: K, value: T) { + self.variables.insert(name.into(), Dynamic::from(value)); } /// Get a mutable reference to a modules-qualified variable. @@ -286,7 +262,7 @@ impl Module { name: String, abi: NativeFunctionABI, access: FnAccess, - params: Vec, + params: &[TypeId], func: Box, ) -> u64 { let hash_fn = calc_fn_hash(empty(), &name, params.iter().cloned()); @@ -298,7 +274,8 @@ impl Module { #[cfg(feature = "sync")] 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 } @@ -316,7 +293,7 @@ impl Module { /// let hash = module.set_fn_0("calc", || Ok(42_i64)); /// assert!(module.get_fn(hash).is_some()); /// ``` - pub fn set_fn_0, T: Into>( + pub fn set_fn_0, T: Variant + Clone>( &mut self, name: K, #[cfg(not(feature = "sync"))] func: impl Fn() -> FuncReturn + 'static, @@ -324,11 +301,11 @@ impl Module { ) -> u64 { let f = move |_: &mut FnCallArgs, pos| { func() - .map(Into::::into) + .map(Dynamic::from) .map_err(|err| EvalAltResult::set_position(err, pos)) }; - let arg_types = vec![]; - self.set_fn(name.into(), Pure, DEF_ACCESS, arg_types, Box::new(f)) + let arg_types = []; + 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. @@ -344,7 +321,7 @@ impl Module { /// let hash = module.set_fn_1("calc", |x: i64| Ok(x + 1)); /// assert!(module.get_fn(hash).is_some()); /// ``` - pub fn set_fn_1, A: Variant + Clone, T: Into>( + pub fn set_fn_1, A: Variant + Clone, T: Variant + Clone>( &mut self, name: K, #[cfg(not(feature = "sync"))] func: impl Fn(A) -> FuncReturn + 'static, @@ -352,11 +329,11 @@ impl Module { ) -> u64 { let f = move |args: &mut FnCallArgs, pos| { func(mem::take(args[0]).cast::()) - .map(Into::::into) + .map(Dynamic::from) .map_err(|err| EvalAltResult::set_position(err, pos)) }; - let arg_types = vec![TypeId::of::()]; - self.set_fn(name.into(), Pure, DEF_ACCESS, arg_types, Box::new(f)) + let arg_types = [TypeId::of::()]; + 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. @@ -372,7 +349,7 @@ impl Module { /// let hash = module.set_fn_1_mut("calc", |x: &mut i64| { *x += 1; Ok(*x) }); /// assert!(module.get_fn(hash).is_some()); /// ``` - pub fn set_fn_1_mut, A: Variant + Clone, T: Into>( + pub fn set_fn_1_mut, A: Variant + Clone, T: Variant + Clone>( &mut self, name: K, #[cfg(not(feature = "sync"))] func: impl Fn(&mut A) -> FuncReturn + 'static, @@ -380,11 +357,11 @@ impl Module { ) -> u64 { let f = move |args: &mut FnCallArgs, pos| { func(args[0].downcast_mut::().unwrap()) - .map(Into::::into) + .map(Dynamic::from) .map_err(|err| EvalAltResult::set_position(err, pos)) }; - let arg_types = vec![TypeId::of::()]; - self.set_fn(name.into(), Method, DEF_ACCESS, arg_types, Box::new(f)) + let arg_types = [TypeId::of::()]; + 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. @@ -402,7 +379,7 @@ impl Module { /// }); /// assert!(module.get_fn(hash).is_some()); /// ``` - pub fn set_fn_2, A: Variant + Clone, B: Variant + Clone, T: Into>( + pub fn set_fn_2, A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>( &mut self, name: K, #[cfg(not(feature = "sync"))] func: impl Fn(A, B) -> FuncReturn + 'static, @@ -413,11 +390,11 @@ impl Module { let b = mem::take(args[1]).cast::(); func(a, b) - .map(Into::::into) + .map(Dynamic::from) .map_err(|err| EvalAltResult::set_position(err, pos)) }; - let arg_types = vec![TypeId::of::(), TypeId::of::()]; - self.set_fn(name.into(), Pure, DEF_ACCESS, arg_types, Box::new(f)) + let arg_types = [TypeId::of::(), TypeId::of::()]; + 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, @@ -438,7 +415,7 @@ impl Module { K: Into, A: Variant + Clone, B: Variant + Clone, - T: Into, + T: Variant + Clone, >( &mut self, name: K, @@ -450,11 +427,11 @@ impl Module { let a = args[0].downcast_mut::().unwrap(); func(a, b) - .map(Into::::into) + .map(Dynamic::from) .map_err(|err| EvalAltResult::set_position(err, pos)) }; - let arg_types = vec![TypeId::of::(), TypeId::of::()]; - self.set_fn(name.into(), Method, DEF_ACCESS, arg_types, Box::new(f)) + let arg_types = [TypeId::of::(), TypeId::of::()]; + 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. @@ -477,7 +454,7 @@ impl Module { A: Variant + Clone, B: Variant + Clone, C: Variant + Clone, - T: Into, + T: Variant + Clone, >( &mut self, name: K, @@ -490,11 +467,11 @@ impl Module { let c = mem::take(args[2]).cast::(); func(a, b, c) - .map(Into::::into) + .map(Dynamic::from) .map_err(|err| EvalAltResult::set_position(err, pos)) }; - let arg_types = vec![TypeId::of::(), TypeId::of::(), TypeId::of::()]; - self.set_fn(name.into(), Pure, DEF_ACCESS, arg_types, Box::new(f)) + let arg_types = [TypeId::of::(), TypeId::of::(), TypeId::of::()]; + 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, @@ -518,7 +495,7 @@ impl Module { A: Variant + Clone, B: Variant + Clone, C: Variant + Clone, - T: Into, + T: Variant + Clone, >( &mut self, name: K, @@ -531,11 +508,11 @@ impl Module { let a = args[0].downcast_mut::().unwrap(); func(a, b, c) - .map(Into::::into) + .map(Dynamic::from) .map_err(|err| EvalAltResult::set_position(err, pos)) }; - let arg_types = vec![TypeId::of::(), TypeId::of::(), TypeId::of::()]; - self.set_fn(name.into(), Method, DEF_ACCESS, arg_types, Box::new(f)) + let arg_types = [TypeId::of::(), TypeId::of::(), TypeId::of::()]; + self.set_fn(name.into(), Method, DEF_ACCESS, &arg_types, Box::new(f)) } /// Get a Rust function. @@ -609,6 +586,7 @@ impl Module { /// # Ok(()) /// # } /// ``` + #[cfg(not(feature = "no_module"))] pub fn eval_ast_as_new(mut scope: Scope, ast: &AST, engine: &Engine) -> FuncReturn { // Run the script engine.eval_ast_with_scope_raw(&mut scope, &ast)?; @@ -722,9 +700,114 @@ impl Module { self.all_functions = functions.into_iter().collect(); 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) { + #[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); + +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> for ModuleRef { + fn from(modules: StaticVec<(String, Position)>) -> Self { + Self(modules, None) + } +} + +impl ModuleRef { + pub(crate) fn index(&self) -> Option { + self.1 + } + pub(crate) fn set_index(&mut self, index: Option) { + 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>; +} + +/// 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>; } /// Re-export module resolvers. +#[cfg(not(feature = "no_module"))] pub mod resolvers { #[cfg(not(feature = "no_std"))] pub use super::file::FileModuleResolver; @@ -732,6 +815,7 @@ pub mod resolvers { } /// Script file-based module resolver. +#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_std"))] mod file { 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); - -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> for ModuleRef { - fn from(modules: StaticVec<(String, Position)>) -> Self { - Self(modules, None) - } -} - -impl ModuleRef { - pub(crate) fn index(&self) -> Option { - self.1 - } - pub(crate) fn set_index(&mut self, index: Option) { - self.1 = index - } -} - /// Static module resolver. +#[cfg(not(feature = "no_module"))] mod stat { use super::*; diff --git a/src/optimize.rs b/src/optimize.rs index 9670f288..babb58c0 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -4,7 +4,8 @@ use crate::engine::{ Engine, FunctionsLib, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT, KEYWORD_TYPE_OF, }; 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::result::EvalAltResult; use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope}; @@ -112,7 +113,7 @@ impl<'a> State<'a> { /// Call a registered function fn call_fn( packages: &PackagesCollection, - base_package: &PackageStore, + global_module: &Module, fn_name: &str, args: &mut FnCallArgs, pos: Position, @@ -120,8 +121,8 @@ fn call_fn( // Search built-in's and external functions let hash = calc_fn_hash(empty(), fn_name, args.iter().map(|a| a.type_id())); - base_package - .get_function(hash) + global_module + .get_fn(hash) .or_else(|| packages.get_function(hash)) .map(|func| func.call(args, pos)) .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| result.or_else(|| { if !arg_for_type_of.is_empty() { diff --git a/src/packages/arithmetic.rs b/src/packages/arithmetic.rs index c788fbb2..e4a26844 100644 --- a/src/packages/arithmetic.rs +++ b/src/packages/arithmetic.rs @@ -1,7 +1,5 @@ -use super::{reg_binary, reg_unary}; - 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::result::EvalAltResult; use crate::token::Position; @@ -22,7 +20,7 @@ use crate::stdlib::{ }; // Checked add -fn add(x: T, y: T) -> Result> { +fn add(x: T, y: T) -> FuncReturn { x.checked_add(&y).ok_or_else(|| { Box::new(EvalAltResult::ErrorArithmetic( format!("Addition overflow: {} + {}", x, y), @@ -31,7 +29,7 @@ fn add(x: T, y: T) -> Result> { }) } // Checked subtract -fn sub(x: T, y: T) -> Result> { +fn sub(x: T, y: T) -> FuncReturn { x.checked_sub(&y).ok_or_else(|| { Box::new(EvalAltResult::ErrorArithmetic( format!("Subtraction underflow: {} - {}", x, y), @@ -40,7 +38,7 @@ fn sub(x: T, y: T) -> Result> { }) } // Checked multiply -fn mul(x: T, y: T) -> Result> { +fn mul(x: T, y: T) -> FuncReturn { x.checked_mul(&y).ok_or_else(|| { Box::new(EvalAltResult::ErrorArithmetic( format!("Multiplication overflow: {} * {}", x, y), @@ -49,7 +47,7 @@ fn mul(x: T, y: T) -> Result> { }) } // Checked divide -fn div(x: T, y: T) -> Result> +fn div(x: T, y: T) -> FuncReturn where T: Display + CheckedDiv + PartialEq + Zero, { @@ -69,7 +67,7 @@ where }) } // Checked negative - e.g. -(i32::MIN) will overflow i32::MAX -fn neg(x: T) -> Result> { +fn neg(x: T) -> FuncReturn { x.checked_neg().ok_or_else(|| { Box::new(EvalAltResult::ErrorArithmetic( format!("Negation overflow: -{}", x), @@ -78,7 +76,7 @@ fn neg(x: T) -> Result> { }) } // Checked absolute -fn abs(x: T) -> Result> { +fn abs(x: T) -> FuncReturn { // FIX - We don't use Signed::abs() here because, contrary to documentation, it panics // when the number is ::MIN instead of returning ::MIN itself. if x >= ::zero() { @@ -93,49 +91,49 @@ fn abs(x: T) -> Result(x: T, y: T) -> ::Output { - x + y +fn add_u(x: T, y: T) -> FuncReturn<::Output> { + Ok(x + y) } // Unchecked subtract - may panic on underflow -fn sub_u(x: T, y: T) -> ::Output { - x - y +fn sub_u(x: T, y: T) -> FuncReturn<::Output> { + Ok(x - y) } // Unchecked multiply - may panic on overflow -fn mul_u(x: T, y: T) -> ::Output { - x * y +fn mul_u(x: T, y: T) -> FuncReturn<::Output> { + Ok(x * y) } // Unchecked divide - may panic when dividing by zero -fn div_u(x: T, y: T) -> ::Output { - x / y +fn div_u(x: T, y: T) -> FuncReturn<::Output> { + Ok(x / y) } // Unchecked negative - may panic on overflow -fn neg_u(x: T) -> ::Output { - -x +fn neg_u(x: T) -> FuncReturn<::Output> { + Ok(-x) } // Unchecked absolute - may panic on overflow -fn abs_u(x: T) -> ::Output +fn abs_u(x: T) -> FuncReturn<::Output> where T: Neg + PartialOrd + Default + Into<::Output>, { // Numbers should default to zero if x < Default::default() { - -x + Ok(-x) } else { - x.into() + Ok(x.into()) } } // Bit operators -fn binary_and(x: T, y: T) -> ::Output { - x & y +fn binary_and(x: T, y: T) -> FuncReturn<::Output> { + Ok(x & y) } -fn binary_or(x: T, y: T) -> ::Output { - x | y +fn binary_or(x: T, y: T) -> FuncReturn<::Output> { + Ok(x | y) } -fn binary_xor(x: T, y: T) -> ::Output { - x ^ y +fn binary_xor(x: T, y: T) -> FuncReturn<::Output> { + Ok(x ^ y) } // Checked left-shift -fn shl(x: T, y: INT) -> Result> { +fn shl(x: T, y: INT) -> FuncReturn { // Cannot shift by a negative number of bits if y < 0 { return Err(Box::new(EvalAltResult::ErrorArithmetic( @@ -152,7 +150,7 @@ fn shl(x: T, y: INT) -> Result> { }) } // Checked right-shift -fn shr(x: T, y: INT) -> Result> { +fn shr(x: T, y: INT) -> FuncReturn { // Cannot shift by a negative number of bits if y < 0 { return Err(Box::new(EvalAltResult::ErrorArithmetic( @@ -169,15 +167,15 @@ fn shr(x: T, y: INT) -> Result> { }) } // Unchecked left-shift - may panic if shifting by a negative number of bits -fn shl_u>(x: T, y: T) -> >::Output { - x.shl(y) +fn shl_u>(x: T, y: T) -> FuncReturn<>::Output> { + Ok(x.shl(y)) } // Unchecked right-shift - may panic if shifting by a negative number of bits -fn shr_u>(x: T, y: T) -> >::Output { - x.shr(y) +fn shr_u>(x: T, y: T) -> FuncReturn<>::Output> { + Ok(x.shr(y)) } // Checked modulo -fn modulo(x: T, y: T) -> Result> { +fn modulo(x: T, y: T) -> FuncReturn { x.checked_rem(&y).ok_or_else(|| { Box::new(EvalAltResult::ErrorArithmetic( format!("Modulo division by zero or overflow: {} % {}", x, y), @@ -186,11 +184,11 @@ fn modulo(x: T, y: T) -> Result> }) } // Unchecked modulo - may panic if dividing by zero -fn modulo_u(x: T, y: T) -> ::Output { - x % y +fn modulo_u(x: T, y: T) -> FuncReturn<::Output> { + Ok(x % y) } // Checked power -fn pow_i_i(x: INT, y: INT) -> Result> { +fn pow_i_i(x: INT, y: INT) -> FuncReturn { #[cfg(not(feature = "only_i32"))] { if y > (u32::MAX as INT) { @@ -231,17 +229,17 @@ fn pow_i_i(x: INT, y: INT) -> Result> { } } // 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 { - x.pow(y as u32) +fn pow_i_i_u(x: INT, y: INT) -> FuncReturn { + Ok(x.pow(y as u32)) } // Floating-point power - always well-defined #[cfg(not(feature = "no_float"))] -fn pow_f_f(x: FLOAT, y: FLOAT) -> FLOAT { - x.powf(y) +fn pow_f_f(x: FLOAT, y: FLOAT) -> FuncReturn { + Ok(x.powf(y)) } // Checked power #[cfg(not(feature = "no_float"))] -fn pow_f_i(x: FLOAT, y: INT) -> Result> { +fn pow_f_i(x: FLOAT, y: INT) -> FuncReturn { // Raise to power that is larger than an i32 if y > (i32::MAX as INT) { return Err(Box::new(EvalAltResult::ErrorArithmetic( @@ -255,39 +253,37 @@ fn pow_f_i(x: FLOAT, y: INT) -> Result> { // Unchecked power - may be incorrect if the power index is too high (> i32::MAX) #[cfg(feature = "unchecked")] #[cfg(not(feature = "no_float"))] -fn pow_f_i_u(x: FLOAT, y: INT) -> FLOAT { - x.powi(y as i32) +fn pow_f_i_u(x: FLOAT, y: INT) -> FuncReturn { + Ok(x.powi(y as i32)) } -macro_rules! reg_unary_x { ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => { - $(reg_unary($lib, $op, $func::<$par>, result);)* }; +macro_rules! reg_unary { + ($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),*) => { - $(reg_unary($lib, $op, $func::<$par>, map);)* }; -} -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);)* }; +macro_rules! reg_op { + ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => { + $( $lib.set_fn_2($op, $func::<$par>); )* + }; } def_package!(crate:ArithmeticPackage:"Basic arithmetic", lib, { // Checked basic arithmetic #[cfg(not(feature = "unchecked"))] { - reg_op_x!(lib, "+", add, INT); - reg_op_x!(lib, "-", sub, INT); - reg_op_x!(lib, "*", mul, INT); - reg_op_x!(lib, "/", div, INT); + reg_op!(lib, "+", add, INT); + reg_op!(lib, "-", sub, INT); + reg_op!(lib, "*", mul, INT); + reg_op!(lib, "/", div, INT); #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] { - reg_op_x!(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_x!(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, "+", add, 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!(lib, "*", mul, 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 #[cfg(not(feature = "unchecked"))] { - reg_op_x!(lib, "<<", shl, INT); - reg_op_x!(lib, ">>", shr, INT); - reg_op_x!(lib, "%", modulo, INT); + reg_op!(lib, "<<", shl, INT); + reg_op!(lib, ">>", shr, INT); + reg_op!(lib, "%", modulo, INT); #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] { - reg_op_x!(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_x!(lib, "%", modulo, 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!(lib, ">>", shr, 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 #[cfg(not(feature = "unchecked"))] { - reg_binary(lib, "~", pow_i_i, result); + lib.set_fn_2("~", pow_i_i); #[cfg(not(feature = "no_float"))] - reg_binary(lib, "~", pow_f_i, result); + lib.set_fn_2("~", pow_f_i); } // Unchecked power #[cfg(feature = "unchecked")] { - reg_binary(lib, "~", pow_i_i_u, map); + lib.set_fn_2("~", pow_i_i_u); #[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 #[cfg(not(feature = "no_float"))] { reg_op!(lib, "%", modulo_u, f32, f64); - reg_binary(lib, "~", pow_f_f, map); + lib.set_fn_2("~", pow_f_f); } // Checked unary #[cfg(not(feature = "unchecked"))] { - reg_unary_x!(lib, "-", neg, INT); - reg_unary_x!(lib, "abs", abs, INT); + reg_unary!(lib, "-", neg, INT); + reg_unary!(lib, "abs", abs, INT); #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] { - reg_unary_x!(lib, "-", neg, i8, i16, i32, i64, i128); - reg_unary_x!(lib, "abs", abs, i8, i16, i32, i64, i128); + reg_unary!(lib, "-", neg, i8, i16, i32, i64, i128); + reg_unary!(lib, "abs", abs, i8, i16, i32, i64, i128); } } diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index c7938e74..6ff90f39 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -1,20 +1,19 @@ #![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::def_package; 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::stdlib::{any::TypeId, boxed::Box, string::String}; // Register array utility functions -fn push(list: &mut Array, item: T) { +fn push(list: &mut Array, item: T) -> FuncReturn<()> { list.push(Dynamic::from(item)); + Ok(()) } -fn ins(list: &mut Array, position: INT, item: T) { +fn ins(list: &mut Array, position: INT, item: T) -> FuncReturn<()> { if position <= 0 { list.insert(0, Dynamic::from(item)); } else if (position as usize) >= list.len() - 1 { @@ -22,20 +21,26 @@ fn ins(list: &mut Array, position: INT, item: T) { } else { list.insert(position as usize, Dynamic::from(item)); } + Ok(()) } -fn pad(list: &mut Array, len: INT, item: T) { +fn pad(list: &mut Array, len: INT, item: T) -> FuncReturn<()> { if len >= 0 { while list.len() < len as usize { push(list, item.clone()); } } + Ok(()) } -macro_rules! reg_op { ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => { - $(reg_binary_mut($lib, $op, $func::<$par>, map);)* }; +macro_rules! reg_op { + ($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),*) => { - $(reg_trinary_mut($lib, $op, $func::<$par>, map);)* }; +macro_rules! reg_tri { + ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => { + $( $lib.set_fn_3_mut($op, $func::<$par>); )* + }; } #[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, "insert", ins, INT, bool, char, String, Array, ()); - reg_binary_mut(lib, "append", |x: &mut Array, y: Array| x.extend(y), map); - reg_binary( - lib, + lib.set_fn_2_mut("append", |x: &mut Array, y: Array| { + x.extend(y); + Ok(()) + }); + lib.set_fn_2( "+", |mut x: Array, y: Array| { x.extend(y); - x + Ok(x) }, - map, ); #[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_unary_mut( - lib, + lib.set_fn_1_mut( "pop", - |list: &mut Array| list.pop().unwrap_or_else(|| ().into()), - pass, + |list: &mut Array| Ok(list.pop().unwrap_or_else(|| ().into())), ); - reg_unary_mut( - lib, + lib.set_fn_1_mut( "shift", |list: &mut Array| { - if list.is_empty() { + Ok(if list.is_empty() { ().into() } else { list.remove(0) - } + }) }, - pass, ); - reg_binary_mut( - lib, + lib.set_fn_2_mut( "remove", |list: &mut Array, len: INT| { - if len < 0 || (len as usize) >= list.len() { + Ok(if len < 0 || (len as usize) >= list.len() { ().into() } else { list.remove(len as usize) - } + }) }, - pass, ); - reg_unary_mut(lib, "len", |list: &mut Array| list.len() as INT, map); - reg_unary_mut(lib, "clear", |list: &mut Array| list.clear(), map); - reg_binary_mut( - lib, + lib.set_fn_1_mut("len", |list: &mut Array| Ok(list.len() as INT)); + lib.set_fn_1_mut("clear", |list: &mut Array| { + list.clear(); + Ok(()) + }); + lib.set_fn_2_mut( "truncate", |list: &mut Array, len: INT| { if len >= 0 { @@ -111,12 +113,12 @@ def_package!(crate:BasicArrayPackage:"Basic array utilities.", lib, { } else { list.clear(); } + Ok(()) }, - map, ); // Register array iterator - lib.type_iterators.insert( + lib.set_iterator( TypeId::of::(), Box::new(|arr| Box::new( arr.cast::().into_iter()) as Box> diff --git a/src/packages/iter_basic.rs b/src/packages/iter_basic.rs index d50ad72a..daf57c44 100644 --- a/src/packages/iter_basic.rs +++ b/src/packages/iter_basic.rs @@ -1,8 +1,6 @@ -use super::{reg_binary, reg_trinary, PackageStore}; - use crate::any::{Dynamic, Variant}; use crate::def_package; -use crate::fn_register::map_dynamic as map; +use crate::module::{FuncReturn, Module}; use crate::parser::INT; use crate::stdlib::{ @@ -12,11 +10,11 @@ use crate::stdlib::{ }; // Register range function -fn reg_range(lib: &mut PackageStore) +fn reg_range(lib: &mut Module) where Range: Iterator, { - lib.type_iterators.insert( + lib.set_iterator( TypeId::of::>(), Box::new(|source| { Box::new(source.cast::>().map(|x| x.into_dynamic())) @@ -25,6 +23,10 @@ where ); } +fn get_range(from: T, to: T) -> FuncReturn> { + Ok(from..to) +} + // Register range function with step #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] struct StepRange(T, T, T) @@ -50,13 +52,13 @@ where } } -fn reg_step(lib: &mut PackageStore) +fn reg_step(lib: &mut Module) where for<'a> &'a T: Add<&'a T, Output = T>, T: Variant + Clone + PartialOrd, StepRange: Iterator, { - lib.type_iterators.insert( + lib.set_iterator( TypeId::of::>(), Box::new(|source| { Box::new(source.cast::>().map(|x| x.into_dynamic())) @@ -65,22 +67,26 @@ where ); } -def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, { - fn get_range(from: T, to: T) -> Range { - from..to - } +fn get_step_range(from: T, to: T, step: T) -> FuncReturn> +where + for<'a> &'a T: Add<&'a T, Output = T>, + T: Variant + Clone + PartialOrd, +{ + Ok(StepRange::(from, to, step)) +} +def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, { reg_range::(lib); - reg_binary(lib, "range", get_range::, map); + lib.set_fn_2("range", get_range::); #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] { macro_rules! reg_range { - ($self:expr, $x:expr, $( $y:ty ),*) => ( + ($lib:expr, $x:expr, $( $y:ty ),*) => ( $( - reg_range::<$y>($self); - reg_binary($self, $x, get_range::<$y>, map); + reg_range::<$y>($lib); + $lib.set_fn_2($x, get_range::<$y>); )* ) } @@ -89,16 +95,16 @@ def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, { } reg_step::(lib); - reg_trinary(lib, "range", StepRange::, map); + lib.set_fn_3("range", get_step_range::); #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] { macro_rules! reg_step { - ($self:expr, $x:expr, $( $y:ty ),*) => ( + ($lib:expr, $x:expr, $( $y:ty ),*) => ( $( - reg_step::<$y>($self); - reg_trinary($self, $x, StepRange::<$y>, map); + reg_step::<$y>($lib); + $lib.set_fn_3($x, get_step_range::<$y>); )* ) } diff --git a/src/packages/logic.rs b/src/packages/logic.rs index f993044a..ef771688 100644 --- a/src/packages/logic.rs +++ b/src/packages/logic.rs @@ -1,44 +1,44 @@ -use super::{reg_binary, reg_binary_mut, reg_unary}; - use crate::def_package; -use crate::fn_register::map_dynamic as map; +use crate::module::FuncReturn; use crate::parser::INT; use crate::stdlib::string::String; // Comparison operators -pub fn lt(x: T, y: T) -> bool { - x < y +pub fn lt(x: T, y: T) -> FuncReturn { + Ok(x < y) } -pub fn lte(x: T, y: T) -> bool { - x <= y +pub fn lte(x: T, y: T) -> FuncReturn { + Ok(x <= y) } -pub fn gt(x: T, y: T) -> bool { - x > y +pub fn gt(x: T, y: T) -> FuncReturn { + Ok(x > y) } -pub fn gte(x: T, y: T) -> bool { - x >= y +pub fn gte(x: T, y: T) -> FuncReturn { + Ok(x >= y) } -pub fn eq(x: T, y: T) -> bool { - x == y +pub fn eq(x: T, y: T) -> FuncReturn { + Ok(x == y) } -pub fn ne(x: T, y: T) -> bool { - x != y +pub fn ne(x: T, y: T) -> FuncReturn { + Ok(x != y) } // Logic operators -fn and(x: bool, y: bool) -> bool { - x && y +fn and(x: bool, y: bool) -> FuncReturn { + Ok(x && y) } -fn or(x: bool, y: bool) -> bool { - x || y +fn or(x: bool, y: bool) -> FuncReturn { + Ok(x || y) } -fn not(x: bool) -> bool { - !x +fn not(x: bool) -> FuncReturn { + Ok(!x) } -macro_rules! reg_op { ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => { - $(reg_binary($lib, $op, $func::<$par>, map);)* }; +macro_rules! reg_op { + ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => { + $( $lib.set_fn_2($op, $func::<$par>); )* + }; } 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, ()); // Special versions for strings - at least avoid copying the first string - // use super::utils::reg_test; - // reg_test(lib, "<", |x: &mut String, y: String| *x < y, |v| v, map); - reg_binary_mut(lib, "<", |x: &mut String, y: String| *x < y, map); - reg_binary_mut(lib, "<=", |x: &mut String, y: String| *x <= y, map); - reg_binary_mut(lib, ">", |x: &mut String, y: String| *x > y, map); - reg_binary_mut(lib, ">=", |x: &mut String, y: String| *x >= y, map); - reg_binary_mut(lib, "==", |x: &mut String, y: String| *x == y, map); - 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)); + lib.set_fn_2_mut("<=", |x: &mut String, y: String| Ok(*x <= y)); + lib.set_fn_2_mut(">", |x: &mut String, y: String| Ok(*x > y)); + lib.set_fn_2_mut(">=", |x: &mut String, y: String| Ok(*x >= y)); + lib.set_fn_2_mut("==", |x: &mut String, y: String| Ok(*x == y)); + lib.set_fn_2_mut("!=", |x: &mut String, y: String| Ok(*x != y)); #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] @@ -85,7 +83,7 @@ def_package!(crate:LogicPackage:"Logical operators.", lib, { //reg_op!(lib, "||", or, bool); //reg_op!(lib, "&&", and, bool); - reg_binary(lib, "|", or, map); - reg_binary(lib, "&", and, map); - reg_unary(lib, "!", not, map); + lib.set_fn_2("|", or); + lib.set_fn_2("&", and); + lib.set_fn_1("!", not); }); diff --git a/src/packages/map_basic.rs b/src/packages/map_basic.rs index 451897bf..c9f4e894 100644 --- a/src/packages/map_basic.rs +++ b/src/packages/map_basic.rs @@ -1,11 +1,9 @@ #![cfg(not(feature = "no_object"))] -use super::{reg_binary, reg_binary_mut, reg_unary_mut}; - use crate::any::Dynamic; use crate::def_package; use crate::engine::Map; -use crate::fn_register::map_dynamic as map; +use crate::module::FuncReturn; use crate::parser::INT; use crate::stdlib::{ @@ -13,55 +11,51 @@ use crate::stdlib::{ vec::Vec, }; -fn map_get_keys(map: &mut Map) -> Vec { - map.iter().map(|(k, _)| k.to_string().into()).collect() +fn map_get_keys(map: &mut Map) -> FuncReturn> { + Ok(map.iter().map(|(k, _)| k.to_string().into()).collect()) } -fn map_get_values(map: &mut Map) -> Vec { - map.iter().map(|(_, v)| v.clone()).collect() +fn map_get_values(map: &mut Map) -> FuncReturn> { + Ok(map.iter().map(|(_, v)| v.clone()).collect()) } #[cfg(not(feature = "no_object"))] def_package!(crate:BasicMapPackage:"Basic object map utilities.", lib, { - reg_binary_mut( - lib, + lib.set_fn_2_mut( "has", - |map: &mut Map, prop: String| map.contains_key(&prop), - map, + |map: &mut Map, prop: String| Ok(map.contains_key(&prop)), ); - reg_unary_mut(lib, "len", |map: &mut Map| map.len() as INT, map); - reg_unary_mut(lib, "clear", |map: &mut Map| map.clear(), map); - reg_binary_mut( - lib, + lib.set_fn_1_mut("len", |map: &mut Map| Ok(map.len() as INT)); + lib.set_fn_1_mut("clear", |map: &mut Map| { + map.clear(); + Ok(()) + }); + lib.set_fn_2_mut( "remove", - |x: &mut Map, name: String| x.remove(&name).unwrap_or_else(|| ().into()), - map, + |x: &mut Map, name: String| Ok(x.remove(&name).unwrap_or_else(|| ().into())), ); - reg_binary_mut( - lib, + lib.set_fn_2_mut( "mixin", |map1: &mut Map, map2: Map| { map2.into_iter().for_each(|(key, value)| { map1.insert(key, value); }); + Ok(()) }, - map, ); - reg_binary( - lib, + lib.set_fn_2( "+", |mut map1: Map, map2: Map| { map2.into_iter().for_each(|(key, value)| { map1.insert(key, value); }); - map1 + Ok(map1) }, - map, ); // Register map access functions #[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"))] - reg_unary_mut(lib, "values", map_get_values, map); + lib.set_fn_1_mut("values", map_get_values); }); diff --git a/src/packages/math_basic.rs b/src/packages/math_basic.rs index a39f477c..0698befb 100644 --- a/src/packages/math_basic.rs +++ b/src/packages/math_basic.rs @@ -1,7 +1,5 @@ -use super::{reg_binary, reg_unary}; - 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::result::EvalAltResult; use crate::token::Position; @@ -20,78 +18,77 @@ def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, { #[cfg(not(feature = "no_float"))] { // Advanced math functions - reg_unary(lib, "sin", |x: FLOAT| x.to_radians().sin(), map); - reg_unary(lib, "cos", |x: FLOAT| x.to_radians().cos(), map); - reg_unary(lib, "tan", |x: FLOAT| x.to_radians().tan(), map); - reg_unary(lib, "sinh", |x: FLOAT| x.to_radians().sinh(), map); - reg_unary(lib, "cosh", |x: FLOAT| x.to_radians().cosh(), map); - reg_unary(lib, "tanh", |x: FLOAT| x.to_radians().tanh(), map); - reg_unary(lib, "asin", |x: FLOAT| x.asin().to_degrees(), map); - reg_unary(lib, "acos", |x: FLOAT| x.acos().to_degrees(), map); - reg_unary(lib, "atan", |x: FLOAT| x.atan().to_degrees(), map); - reg_unary(lib, "asinh", |x: FLOAT| x.asinh().to_degrees(), map); - reg_unary(lib, "acosh", |x: FLOAT| x.acosh().to_degrees(), map); - reg_unary(lib, "atanh", |x: FLOAT| x.atanh().to_degrees(), map); - reg_unary(lib, "sqrt", |x: FLOAT| x.sqrt(), map); - reg_unary(lib, "exp", |x: FLOAT| x.exp(), map); - reg_unary(lib, "ln", |x: FLOAT| x.ln(), map); - reg_binary(lib, "log", |x: FLOAT, base: FLOAT| x.log(base), map); - reg_unary(lib, "log10", |x: FLOAT| x.log10(), map); - reg_unary(lib, "floor", |x: FLOAT| x.floor(), map); - reg_unary(lib, "ceiling", |x: FLOAT| x.ceil(), map); - reg_unary(lib, "round", |x: FLOAT| x.ceil(), map); - reg_unary(lib, "int", |x: FLOAT| x.trunc(), map); - reg_unary(lib, "fraction", |x: FLOAT| x.fract(), map); - reg_unary(lib, "is_nan", |x: FLOAT| x.is_nan(), map); - reg_unary(lib, "is_finite", |x: FLOAT| x.is_finite(), map); - reg_unary(lib, "is_infinite", |x: FLOAT| x.is_infinite(), map); + lib.set_fn_1("sin", |x: FLOAT| Ok(x.to_radians().sin())); + lib.set_fn_1("cos", |x: FLOAT| Ok(x.to_radians().cos())); + lib.set_fn_1("tan", |x: FLOAT| Ok(x.to_radians().tan())); + lib.set_fn_1("sinh", |x: FLOAT| Ok(x.to_radians().sinh())); + lib.set_fn_1("cosh", |x: FLOAT| Ok(x.to_radians().cosh())); + lib.set_fn_1("tanh", |x: FLOAT| Ok(x.to_radians().tanh())); + lib.set_fn_1("asin", |x: FLOAT| Ok(x.asin().to_degrees())); + lib.set_fn_1("acos", |x: FLOAT| Ok(x.acos().to_degrees())); + lib.set_fn_1("atan", |x: FLOAT| Ok(x.atan().to_degrees())); + lib.set_fn_1("asinh", |x: FLOAT| Ok(x.asinh().to_degrees())); + lib.set_fn_1("acosh", |x: FLOAT| Ok(x.acosh().to_degrees())); + lib.set_fn_1("atanh", |x: FLOAT| Ok(x.atanh().to_degrees())); + lib.set_fn_1("sqrt", |x: FLOAT| Ok(x.sqrt())); + lib.set_fn_1("exp", |x: FLOAT| Ok(x.exp())); + lib.set_fn_1("ln", |x: FLOAT| Ok(x.ln())); + lib.set_fn_2("log", |x: FLOAT, base: FLOAT| Ok(x.log(base))); + lib.set_fn_1("log10", |x: FLOAT| Ok(x.log10())); + lib.set_fn_1("floor", |x: FLOAT| Ok(x.floor())); + lib.set_fn_1("ceiling", |x: FLOAT| Ok(x.ceil())); + lib.set_fn_1("round", |x: FLOAT| Ok(x.ceil())); + lib.set_fn_1("int", |x: FLOAT| Ok(x.trunc())); + lib.set_fn_1("fraction", |x: FLOAT| Ok(x.fract())); + lib.set_fn_1("is_nan", |x: FLOAT| Ok(x.is_nan())); + lib.set_fn_1("is_finite", |x: FLOAT| Ok(x.is_finite())); + lib.set_fn_1("is_infinite", |x: FLOAT| Ok(x.is_infinite())); // Register conversion functions - reg_unary(lib, "to_float", |x: INT| x as FLOAT, map); - reg_unary(lib, "to_float", |x: f32| x as FLOAT, map); + lib.set_fn_1("to_float", |x: INT| Ok(x as FLOAT)); + lib.set_fn_1("to_float", |x: f32| Ok(x as FLOAT)); #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] { - reg_unary(lib, "to_float", |x: i8| x as FLOAT, map); - reg_unary(lib, "to_float", |x: u8| x as FLOAT, map); - reg_unary(lib, "to_float", |x: i16| x as FLOAT, map); - reg_unary(lib, "to_float", |x: u16| x as FLOAT, map); - reg_unary(lib, "to_float", |x: i32| x as FLOAT, map); - reg_unary(lib, "to_float", |x: u32| x as FLOAT, map); - reg_unary(lib, "to_float", |x: i64| x as FLOAT, map); - reg_unary(lib, "to_float", |x: u64| x as FLOAT, map); - reg_unary(lib, "to_float", |x: i128| x as FLOAT, map); - reg_unary(lib, "to_float", |x: u128| x as FLOAT, map); + lib.set_fn_1("to_float", |x: i8| Ok(x as FLOAT)); + lib.set_fn_1("to_float", |x: u8| Ok(x as FLOAT)); + lib.set_fn_1("to_float", |x: i16| Ok(x as FLOAT)); + lib.set_fn_1("to_float", |x: u16| Ok(x as FLOAT)); + lib.set_fn_1("to_float", |x: i32| Ok(x as FLOAT)); + lib.set_fn_1("to_float", |x: u32| Ok(x as FLOAT)); + lib.set_fn_1("to_float", |x: i64| Ok(x as FLOAT)); + lib.set_fn_1("to_float", |x: u64| Ok(x as FLOAT)); + lib.set_fn_1("to_float", |x: i128| Ok(x as FLOAT)); + 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_i64"))] { - reg_unary(lib, "to_int", |x: i8| x as INT, map); - reg_unary(lib, "to_int", |x: u8| x as INT, map); - reg_unary(lib, "to_int", |x: i16| x as INT, map); - reg_unary(lib, "to_int", |x: u16| x as INT, map); + lib.set_fn_1("to_int", |x: i8| Ok(x as INT)); + lib.set_fn_1("to_int", |x: u8| Ok(x as INT)); + lib.set_fn_1("to_int", |x: i16| Ok(x as INT)); + lib.set_fn_1("to_int", |x: u16| Ok(x as INT)); } #[cfg(not(feature = "only_i32"))] { - reg_unary(lib, "to_int", |x: i32| x as INT, map); - reg_unary(lib, "to_int", |x: u64| x as INT, map); + lib.set_fn_1("to_int", |x: i32| Ok(x as INT)); + lib.set_fn_1("to_int", |x: u64| Ok(x as INT)); #[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 = "unchecked"))] { - reg_unary( - lib, + lib.set_fn_1( "to_int", |x: f32| { if x > (MAX_INT as f32) { @@ -103,10 +100,8 @@ def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, { Ok(x.trunc() as INT) }, - result, ); - reg_unary( - lib, + lib.set_fn_1( "to_int", |x: FLOAT| { if x > (MAX_INT as FLOAT) { @@ -118,14 +113,13 @@ def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, { Ok(x.trunc() as INT) }, - result, ); } #[cfg(feature = "unchecked")] { - reg_unary(lib, "to_int", |x: f32| x as INT, map); - reg_unary(lib, "to_int", |x: f64| x as INT, map); + lib.set_fn_1("to_int", |x: f32| Ok(x as INT)); + lib.set_fn_1("to_int", |x: f64| Ok(x as INT)); } } }); diff --git a/src/packages/mod.rs b/src/packages/mod.rs index f9b50d90..a8599417 100644 --- a/src/packages/mod.rs +++ b/src/packages/mod.rs @@ -1,6 +1,7 @@ //! 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}; @@ -15,7 +16,6 @@ mod pkg_std; mod string_basic; mod string_more; mod time_basic; -mod utils; pub use arithmetic::ArithmeticPackage; #[cfg(not(feature = "no_index"))] @@ -32,67 +32,22 @@ pub use string_more::MoreStringPackage; #[cfg(not(feature = "no_std"))] pub use time_basic::BasicTimePackage; -pub use utils::*; - -const NUM_NATIVE_FUNCTIONS: usize = 512; - /// Trait that all packages must implement. pub trait Package { /// 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. fn get(&self) -> PackageLibrary; } -/// Type to store all functions in the package. -pub struct PackageStore { - /// All functions, keyed by a hash created from the function name and parameter types. - pub functions: HashMap>, - - /// All iterator functions, keyed by the type producing the iterator. - pub type_iterators: HashMap>, -} - -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> { - 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> { - 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. +/// Type which `Rc`-wraps a `Module` to facilitate sharing library instances. #[cfg(not(feature = "sync"))] -pub type PackageLibrary = Rc; +pub type PackageLibrary = Rc; -/// 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")] -pub type PackageLibrary = Arc; +pub type PackageLibrary = Arc; /// Type containing a collection of `PackageLibrary` instances. /// 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`? 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. pub fn get_function(&self, hash: u64) -> Option<&Box> { self.packages .iter() - .map(|p| p.get_function(hash)) + .map(|p| p.get_fn(hash)) .find(|f| f.is_some()) .flatten() } @@ -125,7 +80,7 @@ impl PackagesCollection { self.packages.iter().any(|p| p.contains_iterator(id)) } /// Get the specified TypeId iterator. - pub fn get_iterator(&self, id: TypeId) -> Option<&Box> { + pub fn get_iterator(&self, id: TypeId) -> Option<&SharedIteratorFunction> { self.packages .iter() .map(|p| p.get_iterator(id)) @@ -133,3 +88,51 @@ impl PackagesCollection { .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> { 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(); + ::init(&mut module); + Self(module.into()) + } + } + }; +} diff --git a/src/packages/string_basic.rs b/src/packages/string_basic.rs index e58890d1..3b1689cf 100644 --- a/src/packages/string_basic.rs +++ b/src/packages/string_basic.rs @@ -1,8 +1,6 @@ -use super::{reg_binary, reg_binary_mut, reg_none, reg_unary, reg_unary_mut}; - use crate::def_package; 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; #[cfg(not(feature = "no_index"))] @@ -18,31 +16,33 @@ use crate::stdlib::{ }; // Register print and debug -fn to_debug(x: &mut T) -> String { - format!("{:?}", x) +fn to_debug(x: &mut T) -> FuncReturn { + Ok(format!("{:?}", x)) } -fn to_string(x: &mut T) -> String { - format!("{}", x) +fn to_string(x: &mut T) -> FuncReturn { + Ok(format!("{}", x)) } #[cfg(not(feature = "no_object"))] -fn format_map(x: &mut Map) -> String { - format!("#{:?}", x) +fn format_map(x: &mut Map) -> FuncReturn { + Ok(format!("#{:?}", x)) } -macro_rules! reg_op { ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => { - $(reg_unary_mut($lib, $op, $func::<$par>, map);)* }; +macro_rules! reg_op { + ($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, { reg_op!(lib, KEYWORD_PRINT, to_string, INT, bool, char); reg_op!(lib, FUNC_TO_STRING, to_string, INT, bool, char); - reg_none(lib, KEYWORD_PRINT, || "".to_string(), map); - reg_unary(lib, KEYWORD_PRINT, |_: ()| "".to_string(), map); - reg_unary(lib, FUNC_TO_STRING, |_: ()| "".to_string(), map); + lib.set_fn_0(KEYWORD_PRINT, || Ok("".to_string())); + lib.set_fn_1(KEYWORD_PRINT, |_: ()| Ok("".to_string())); + lib.set_fn_1(FUNC_TO_STRING, |_: ()| Ok("".to_string())); - reg_unary_mut(lib, KEYWORD_PRINT, |s: &mut String| s.clone(), map); - reg_unary_mut(lib, FUNC_TO_STRING, |s: &mut String| s.clone(), map); + lib.set_fn_1_mut(KEYWORD_PRINT, |s: &mut String| Ok(s.clone())); + 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); @@ -73,34 +73,34 @@ def_package!(crate:BasicStringPackage:"Basic string utilities, including printin #[cfg(not(feature = "no_object"))] { - reg_unary_mut(lib, KEYWORD_PRINT, format_map, map); - reg_unary_mut(lib, FUNC_TO_STRING, format_map, map); - reg_unary_mut(lib, KEYWORD_DEBUG, format_map, map); + lib.set_fn_1_mut(KEYWORD_PRINT, format_map); + lib.set_fn_1_mut(FUNC_TO_STRING, format_map); + lib.set_fn_1_mut(KEYWORD_DEBUG, format_map); } - reg_binary( - lib, + lib.set_fn_2( "+", |mut s: String, ch: char| { s.push(ch); - s + Ok(s) }, - map, ); - reg_binary( - lib, + lib.set_fn_2( "+", |mut s: String, s2: String| { s.push_str(&s2); - s + Ok(s) }, - map, ); - reg_binary_mut(lib, "append", |s: &mut String, ch: char| s.push(ch), map); - reg_binary_mut( - lib, + lib.set_fn_2_mut("append", |s: &mut String, ch: char| { + s.push(ch); + Ok(()) + }); + lib.set_fn_2_mut( "append", - |s: &mut String, s2: String| s.push_str(&s2), - map, + |s: &mut String, s2: String| { + s.push_str(&s2); + Ok(()) + } ); }); diff --git a/src/packages/string_more.rs b/src/packages/string_more.rs index 697a6eb0..eb6208f1 100644 --- a/src/packages/string_more.rs +++ b/src/packages/string_more.rs @@ -1,7 +1,5 @@ -use super::{reg_binary, reg_binary_mut, reg_trinary_mut, reg_unary_mut}; - use crate::def_package; -use crate::fn_register::map_dynamic as map; +use crate::module::FuncReturn; use crate::parser::INT; #[cfg(not(feature = "no_index"))] @@ -14,19 +12,19 @@ use crate::stdlib::{ vec::Vec, }; -fn prepend(x: T, y: String) -> String { - format!("{}{}", x, y) +fn prepend(x: T, y: String) -> FuncReturn { + Ok(format!("{}{}", x, y)) } -fn append(x: String, y: T) -> String { - format!("{}{}", x, y) +fn append(x: String, y: T) -> FuncReturn { + 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 { let offset = if s.is_empty() || len <= 0 { - return "".to_string(); + return Ok("".to_string()); } else if start < 0 { 0 } else if (start as usize) >= s.chars().count() { - return "".to_string(); + return Ok("".to_string()); } else { start as usize }; @@ -39,17 +37,17 @@ fn sub_string(s: &mut String, start: INT, len: INT) -> String { 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 { s.clear(); - return; + return Ok(()); } else if start < 0 { 0 } else if (start as usize) >= s.chars().count() { s.clear(); - return; + return Ok(()); } else { start as usize }; @@ -67,18 +65,22 @@ fn crop_string(s: &mut String, start: INT, len: INT) { chars[offset..][..len] .into_iter() .for_each(|&ch| s.push(ch)); + + Ok(()) } -macro_rules! reg_op { ($lib:expr, $op:expr, $func:ident, $($par:ty),*) => { - $(reg_binary($lib, $op, $func::<$par>, map);)* }; +macro_rules! reg_op { + ($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, { 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_binary(lib, "+", |_: (), y: String| y, map); + lib.set_fn_2("+", |_: (), y: String| Ok(y)); #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] @@ -95,105 +97,95 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str #[cfg(not(feature = "no_index"))] { - reg_binary(lib, "+", |x: String, y: Array| format!("{}{:?}", x, y), map); - reg_binary(lib, "+", |x: Array, y: String| format!("{:?}{}", x, y), map); + lib.set_fn_2("+", |x: String, y: Array| Ok(format!("{}{:?}", x, y))); + 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); - reg_binary_mut( - lib, + lib.set_fn_1_mut("len", |s: &mut String| Ok(s.chars().count() as INT)); + lib.set_fn_2_mut( "contains", - |s: &mut String, ch: char| s.contains(ch), - map, + |s: &mut String, ch: char| Ok(s.contains(ch)), ); - reg_binary_mut( - lib, + lib.set_fn_2_mut( "contains", - |s: &mut String, find: String| s.contains(&find), - map, + |s: &mut String, find: String| Ok(s.contains(&find)), ); - reg_trinary_mut( - lib, + lib.set_fn_3_mut( "index_of", |s: &mut String, ch: char, start: INT| { let start = if start < 0 { 0 } else if (start as usize) >= s.chars().count() { - return -1 as INT; + return Ok(-1 as INT); } else { s.chars().take(start as usize).collect::().len() }; - s[start..] + Ok(s[start..] .find(ch) .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, + lib.set_fn_2_mut( "index_of", |s: &mut String, ch: char| { - s.find(ch) + Ok(s.find(ch) .map(|index| s[0..index].chars().count() as INT) - .unwrap_or(-1 as INT) + .unwrap_or(-1 as INT)) }, - map, ); - reg_trinary_mut( - lib, + lib.set_fn_3_mut( "index_of", |s: &mut String, find: String, start: INT| { let start = if start < 0 { 0 } else if (start as usize) >= s.chars().count() { - return -1 as INT; + return Ok(-1 as INT); } else { s.chars().take(start as usize).collect::().len() }; - s[start..] + Ok(s[start..] .find(&find) .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, + lib.set_fn_2_mut( "index_of", |s: &mut String, find: String| { - s.find(&find) + Ok(s.find(&find) .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); - reg_binary_mut(lib, "append", |s: &mut String, ch: char| s.push(ch), map); - reg_binary_mut( - lib, + lib.set_fn_1_mut("clear", |s: &mut String| { + s.clear(); + Ok(()) + }); + lib.set_fn_2_mut( "append", |s: &mut String, ch: char| { + s.push(ch); + Ok(()) + }); + lib.set_fn_2_mut( "append", - |s: &mut String, add: String| s.push_str(&add), - map, + |s: &mut String, add: String| { + s.push_str(&add); + Ok(()) + } ); - reg_trinary_mut(lib, "sub_string", sub_string, map); - reg_binary_mut( - lib, + lib.set_fn_3_mut( "sub_string", sub_string); + lib.set_fn_2_mut( "sub_string", |s: &mut String, start: INT| sub_string(s, start, s.len() as INT), - map, ); - reg_trinary_mut(lib, "crop", crop_string, map); - reg_binary_mut( - lib, + lib.set_fn_3_mut( "crop", crop_string); + lib.set_fn_2_mut( "crop", |s: &mut String, start: INT| crop_string(s, start, s.len() as INT), - map, ); - reg_binary_mut( - lib, + lib.set_fn_2_mut( "truncate", |s: &mut String, len: INT| { if len >= 0 { @@ -203,61 +195,55 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str } else { s.clear(); } + Ok(()) }, - map, ); - reg_trinary_mut( - lib, + lib.set_fn_3_mut( "pad", |s: &mut String, len: INT, ch: char| { for _ in 0..s.chars().count() - len as usize { s.push(ch); } + Ok(()) }, - map, ); - reg_trinary_mut( - lib, + lib.set_fn_3_mut( "replace", |s: &mut String, find: String, sub: String| { let new_str = s.replace(&find, &sub); s.clear(); s.push_str(&new_str); + Ok(()) }, - map, ); - reg_trinary_mut( - lib, + lib.set_fn_3_mut( "replace", |s: &mut String, find: String, sub: char| { let new_str = s.replace(&find, &sub.to_string()); s.clear(); s.push_str(&new_str); + Ok(()) }, - map, ); - reg_trinary_mut( - lib, + lib.set_fn_3_mut( "replace", |s: &mut String, find: char, sub: String| { let new_str = s.replace(&find.to_string(), &sub); s.clear(); s.push_str(&new_str); + Ok(()) }, - map, ); - reg_trinary_mut( - lib, + lib.set_fn_3_mut( "replace", |s: &mut String, find: char, sub: char| { let new_str = s.replace(&find.to_string(), &sub.to_string()); s.clear(); s.push_str(&new_str); + Ok(()) }, - map, ); - reg_unary_mut( - lib, + lib.set_fn_1_mut( "trim", |s: &mut String| { let trimmed = s.trim(); @@ -265,7 +251,7 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str if trimmed.len() < s.len() { *s = trimmed.to_string(); } + Ok(()) }, - map, ); }); diff --git a/src/packages/time_basic.rs b/src/packages/time_basic.rs index 173c3e22..7d80344c 100644 --- a/src/packages/time_basic.rs +++ b/src/packages/time_basic.rs @@ -1,9 +1,8 @@ use super::logic::{eq, gt, gte, lt, lte, ne}; use super::math_basic::MAX_INT; -use super::{reg_binary, reg_none, reg_unary}; 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::result::EvalAltResult; use crate::token::Position; @@ -14,10 +13,9 @@ use crate::stdlib::time::Instant; #[cfg(not(feature = "no_std"))] def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, { // Register date/time functions - reg_none(lib, "timestamp", || Instant::now(), map); + lib.set_fn_0("timestamp", || Ok(Instant::now())); - reg_binary( - lib, + lib.set_fn_2( "-", |ts1: Instant, ts2: Instant| { if ts2 > ts1 { @@ -63,18 +61,16 @@ def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, { } } }, - result, ); - reg_binary(lib, "<", lt::, map); - reg_binary(lib, "<=", lte::, map); - reg_binary(lib, ">", gt::, map); - reg_binary(lib, ">=", gte::, map); - reg_binary(lib, "==", eq::, map); - reg_binary(lib, "!=", ne::, map); + lib.set_fn_2("<", lt::); + lib.set_fn_2("<=", lte::); + lib.set_fn_2(">", gt::); + lib.set_fn_2(">=", gte::); + lib.set_fn_2("==", eq::); + lib.set_fn_2("!=", ne::); - reg_unary( - lib, + lib.set_fn_1( "elapsed", |timestamp: Instant| { #[cfg(not(feature = "no_float"))] @@ -96,6 +92,5 @@ def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, { return Ok(seconds as INT); } }, - result, ); }); diff --git a/src/packages/utils.rs b/src/packages/utils.rs deleted file mode 100644 index 233218db..00000000 --- a/src/packages/utils.rs +++ /dev/null @@ -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> -/// }); -/// ``` -/// -/// 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(); - ::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`. -/// -/// # 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> -/// }); -/// ``` -/// -/// The above defines a package named 'MyPackage' with a single function named 'my_add_1'. -pub fn reg_none( - 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> - + 'static, - #[cfg(feature = "sync")] map_result: impl Fn(R, Position) -> Result> - + 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`. -/// -/// # 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> -/// }); -/// ``` -/// -/// The above defines a package named 'MyPackage' with a single function named 'my_add_1'. -pub fn reg_unary( - 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> - + 'static, - #[cfg(feature = "sync")] map_result: impl Fn(R, Position) -> Result> - + Send - + Sync - + 'static, -) { - //println!("register {}({})", fn_name, crate::std::any::type_name::()); - - let hash_fn_native = calc_fn_hash(empty(), fn_name, [TypeId::of::()].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::(); - - 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`. -/// -/// # Examples -/// -/// ``` -/// use rhai::{Dynamic, EvalAltResult}; -/// use rhai::def_package; -/// use rhai::packages::reg_unary_mut; -/// -/// fn inc(x: &mut i64) -> Result> { -/// 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> -/// }); -/// ``` -/// -/// 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>`. -pub fn reg_unary_mut( - 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> - + 'static, - #[cfg(feature = "sync")] map_result: impl Fn(R, Position) -> Result> - + Send - + Sync - + 'static, -) { - //println!("register {}(&mut {})", fn_name, crate::std::any::type_name::()); - - let hash_fn_native = calc_fn_hash(empty(), fn_name, [TypeId::of::()].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`. -/// -/// # 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> -/// }); -/// ``` -/// -/// The above defines a package named 'MyPackage' with a single function named 'my_add'. -pub fn reg_binary( - 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> - + 'static, - #[cfg(feature = "sync")] map_result: impl Fn(R, Position) -> Result> - + Send - + Sync - + 'static, -) { - //println!("register {}({}, {})", fn_name, crate::std::any::type_name::(), crate::std::any::type_name::()); - - let hash_fn_native = calc_fn_hash( - empty(), - fn_name, - [TypeId::of::(), TypeId::of::()].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::(); - let y = mem::take(*drain.next().unwrap()).cast::(); - - 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`. -/// -/// # Examples -/// -/// ``` -/// use rhai::{Dynamic, EvalAltResult}; -/// use rhai::def_package; -/// use rhai::packages::reg_binary_mut; -/// -/// fn add(x: &mut i64, y: i64) -> Result> { -/// 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> -/// }); -/// ``` -/// -/// 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>`. -pub fn reg_binary_mut( - 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> - + 'static, - #[cfg(feature = "sync")] map_result: impl Fn(R, Position) -> Result> - + Send - + Sync - + 'static, -) { - //println!("register {}(&mut {}, {})", fn_name, crate::std::any::type_name::(), crate::std::any::type_name::()); - - let hash_fn_native = calc_fn_hash( - empty(), - fn_name, - [TypeId::of::(), TypeId::of::()].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::(); - - 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`. -pub fn reg_trinary( - 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> - + 'static, - #[cfg(feature = "sync")] map_result: impl Fn(R, Position) -> Result> - + Send - + Sync - + 'static, -) { - //println!("register {}({}, {}, {})", fn_name, crate::std::any::type_name::(), crate::std::any::type_name::(), crate::std::any::type_name::()); - - let hash_fn_native = calc_fn_hash( - empty(), - fn_name, - [TypeId::of::(), TypeId::of::(), TypeId::of::()] - .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::(); - let y = mem::take(*drain.next().unwrap()).cast::(); - let z = mem::take(*drain.next().unwrap()).cast::(); - - 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`. -pub fn reg_trinary_mut( - 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> - + 'static, - #[cfg(feature = "sync")] map_result: impl Fn(R, Position) -> Result> - + Send - + Sync - + 'static, -) { - //println!("register {}(&mut {}, {}, {})", fn_name, crate::std::any::type_name::(), crate::std::any::type_name::(), crate::std::any::type_name::()); - - let hash_fn_native = calc_fn_hash( - empty(), - fn_name, - [TypeId::of::(), TypeId::of::(), TypeId::of::()] - .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::(); - let z = mem::take(*drain.next().unwrap()).cast::(); - - let r = func(x, y, z); - map_result(r, pos) - }); - - lib.functions - .insert(hash_fn_native, Box::new(NativeFunction::new(f, Method))); -}