From 4a1fd66b9f1d5d1e2f357aba56748b10095a9cbf Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Tue, 19 May 2020 22:25:57 +0800 Subject: [PATCH] Reduce Rc/Arc wrapping for functions. --- src/engine.rs | 6 ++-- src/fn_native.rs | 83 +++++++++++++++++++++++--------------------- src/fn_register.rs | 23 ++++++------- src/module.rs | 84 +++++++++++++++++---------------------------- src/packages/mod.rs | 4 +-- src/parser.rs | 35 ++++--------------- 6 files changed, 97 insertions(+), 138 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index d45d1099..cb3b0e8c 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -3,11 +3,11 @@ use crate::any::{Dynamic, Union}; use crate::calc_fn_hash; use crate::error::ParseErrorType; -use crate::fn_native::{FnCallArgs, PrintCallback, ProgressCallback}; +use crate::fn_native::{FnCallArgs, PrintCallback, ProgressCallback, SharedFnDef}; use crate::module::Module; use crate::optimize::OptimizationLevel; use crate::packages::{CorePackage, Package, PackageLibrary, PackagesCollection, StandardPackage}; -use crate::parser::{Expr, FnAccess, FnDef, ReturnType, SharedFnDef, Stmt, AST}; +use crate::parser::{Expr, FnAccess, FnDef, ReturnType, Stmt, AST}; use crate::r#unsafe::unsafe_cast_var_name_to_lifetime; use crate::result::EvalAltResult; use crate::scope::{EntryType as ScopeEntryType, Scope}; @@ -1741,7 +1741,7 @@ impl Engine { let index = scope.len() - 1; state.scope_level += 1; - for loop_var in func.get_iter_fn()(iter_type) { + for loop_var in func(iter_type) { *scope.get_mut(index).0 = loop_var; self.inc_operations(state, stmt.position())?; diff --git a/src/fn_native.rs b/src/fn_native.rs index 328372b9..619fb102 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -1,5 +1,5 @@ use crate::any::Dynamic; -use crate::parser::{FnDef, SharedFnDef}; +use crate::parser::FnDef; use crate::result::EvalAltResult; use crate::stdlib::{boxed::Box, rc::Rc, sync::Arc}; @@ -73,15 +73,31 @@ pub trait IteratorCallback: Fn(Dynamic) -> Box> + ' #[cfg(not(feature = "sync"))] impl Box> + 'static> IteratorCallback for F {} +#[cfg(not(feature = "sync"))] +pub type SharedNativeFunction = Rc; +#[cfg(feature = "sync")] +pub type SharedNativeFunction = Arc; + +#[cfg(not(feature = "sync"))] +pub type SharedIteratorFn = Rc; +#[cfg(feature = "sync")] +pub type SharedIteratorFn = Arc; + +#[cfg(feature = "sync")] +pub type SharedFnDef = Arc; +#[cfg(not(feature = "sync"))] +pub type SharedFnDef = Rc; + /// A type encapsulating a function callable by Rhai. +#[derive(Clone)] pub enum CallableFunction { /// A pure native Rust function with all arguments passed by value. - Pure(Box), + Pure(SharedNativeFunction), /// A native Rust object method with the first argument passed by reference, /// and the rest passed by value. - Method(Box), + Method(SharedNativeFunction), /// An iterator function. - Iterator(Box), + Iterator(SharedIteratorFn), /// A script-defined function. Script(SharedFnDef), } @@ -90,37 +106,29 @@ impl CallableFunction { /// Is this a pure native Rust function? pub fn is_pure(&self) -> bool { match self { - CallableFunction::Pure(_) => true, - CallableFunction::Method(_) - | CallableFunction::Iterator(_) - | CallableFunction::Script(_) => false, + Self::Pure(_) => true, + Self::Method(_) | Self::Iterator(_) | Self::Script(_) => false, } } /// Is this a pure native Rust method-call? pub fn is_method(&self) -> bool { match self { - CallableFunction::Method(_) => true, - CallableFunction::Pure(_) - | CallableFunction::Iterator(_) - | CallableFunction::Script(_) => false, + Self::Method(_) => true, + Self::Pure(_) | Self::Iterator(_) | Self::Script(_) => false, } } /// Is this an iterator function? pub fn is_iter(&self) -> bool { match self { - CallableFunction::Iterator(_) => true, - CallableFunction::Pure(_) - | CallableFunction::Method(_) - | CallableFunction::Script(_) => false, + Self::Iterator(_) => true, + Self::Pure(_) | Self::Method(_) | Self::Script(_) => false, } } /// Is this a Rhai-scripted function? pub fn is_script(&self) -> bool { match self { - CallableFunction::Script(_) => true, - CallableFunction::Pure(_) - | CallableFunction::Method(_) - | CallableFunction::Iterator(_) => false, + Self::Script(_) => true, + Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => false, } } /// Get a reference to a native Rust function. @@ -128,10 +136,10 @@ impl CallableFunction { /// # Panics /// /// Panics if the `CallableFunction` is not `Pure` or `Method`. - pub fn get_native_fn(&self) -> &Box { + pub fn get_native_fn(&self) -> &FnAny { match self { - CallableFunction::Pure(f) | CallableFunction::Method(f) => f, - CallableFunction::Iterator(_) | CallableFunction::Script(_) => panic!(), + Self::Pure(f) | Self::Method(f) => f.as_ref(), + Self::Iterator(_) | Self::Script(_) => panic!(), } } /// Get a reference to a script-defined function definition. @@ -141,10 +149,8 @@ impl CallableFunction { /// Panics if the `CallableFunction` is not `Script`. pub fn get_fn_def(&self) -> &FnDef { match self { - CallableFunction::Pure(_) - | CallableFunction::Method(_) - | CallableFunction::Iterator(_) => panic!(), - CallableFunction::Script(f) => f, + Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => panic!(), + Self::Script(f) => f, } } /// Get a reference to an iterator function. @@ -152,19 +158,18 @@ impl CallableFunction { /// # Panics /// /// Panics if the `CallableFunction` is not `Iterator`. - pub fn get_iter_fn(&self) -> &Box { + pub fn get_iter_fn(&self) -> &IteratorFn { match self { - CallableFunction::Pure(_) - | CallableFunction::Method(_) - | CallableFunction::Script(_) => panic!(), - CallableFunction::Iterator(f) => f, + Self::Iterator(f) => f.as_ref(), + Self::Pure(_) | Self::Method(_) | Self::Script(_) => panic!(), } } + /// Create a new `CallableFunction::Pure`. + pub fn from_pure(func: Box) -> Self { + Self::Pure(func.into()) + } + /// Create a new `CallableFunction::Method`. + pub fn from_method(func: Box) -> Self { + Self::Method(func.into()) + } } - -/// A callable function. -#[cfg(not(feature = "sync"))] -pub type SharedFunction = Rc; -/// A callable function. -#[cfg(feature = "sync")] -pub type SharedFunction = Arc; diff --git a/src/fn_register.rs b/src/fn_register.rs index 9636e557..46dbd166 100644 --- a/src/fn_register.rs +++ b/src/fn_register.rs @@ -4,10 +4,7 @@ use crate::any::{Dynamic, Variant}; use crate::engine::Engine; -use crate::fn_native::{ - CallableFunction::{Method, Pure}, - FnCallArgs, -}; +use crate::fn_native::{CallableFunction, FnAny, FnCallArgs}; use crate::parser::FnAccess; use crate::result::EvalAltResult; @@ -158,7 +155,7 @@ macro_rules! make_func { // Map the result $map(r) - }) + }) as Box }; } @@ -184,7 +181,7 @@ pub fn map_result( macro_rules! def_register { () => { - def_register!(imp Pure :); + def_register!(imp from_pure :); }; (imp $abi:ident : $($par:ident => $mark:ty => $param:ty => $clone:expr),*) => { // ^ function ABI type @@ -207,7 +204,7 @@ macro_rules! def_register { fn register_fn(&mut self, name: &str, f: FN) { self.global_module.set_fn(name.to_string(), FnAccess::Public, &[$(TypeId::of::<$par>()),*], - $abi(make_func!(f : map_dynamic ; $($par => $clone),*)) + CallableFunction::$abi(make_func!(f : map_dynamic ; $($par => $clone),*)) ); } } @@ -225,7 +222,7 @@ macro_rules! def_register { fn register_dynamic_fn(&mut self, name: &str, f: FN) { self.global_module.set_fn(name.to_string(), FnAccess::Public, &[$(TypeId::of::<$par>()),*], - $abi(make_func!(f : map_identity ; $($par => $clone),*)) + CallableFunction::$abi(make_func!(f : map_identity ; $($par => $clone),*)) ); } } @@ -244,7 +241,7 @@ macro_rules! def_register { fn register_result_fn(&mut self, name: &str, f: FN) { self.global_module.set_fn(name.to_string(), FnAccess::Public, &[$(TypeId::of::<$par>()),*], - $abi(make_func!(f : map_result ; $($par => $clone),*)) + CallableFunction::$abi(make_func!(f : map_result ; $($par => $clone),*)) ); } } @@ -252,11 +249,11 @@ macro_rules! def_register { //def_register!(imp_pop $($par => $mark => $param),*); }; ($p0:ident $(, $p:ident)*) => { - def_register!(imp Pure : $p0 => $p0 => $p0 => by_value $(, $p => $p => $p => by_value)*); - def_register!(imp Method : $p0 => Mut<$p0> => &mut $p0 => by_ref $(, $p => $p => $p => by_value)*); + def_register!(imp from_pure : $p0 => $p0 => $p0 => by_value $(, $p => $p => $p => by_value)*); + def_register!(imp from_method : $p0 => Mut<$p0> => &mut $p0 => by_ref $(, $p => $p => $p => by_value)*); // ^ CallableFunction - // handle the first parameter ^ first parameter passed through - // ^ others passed by value (by_value) + // handle the first parameter ^ first parameter passed through + // ^ others passed by value (by_value) // Currently does not support first argument which is a reference, as there will be // conflicting implementations since &T: Any and T: Any cannot be distinguished diff --git a/src/module.rs b/src/module.rs index 59a0d0f1..5e751df8 100644 --- a/src/module.rs +++ b/src/module.rs @@ -3,11 +3,7 @@ use crate::any::{Dynamic, Variant}; use crate::calc_fn_hash; use crate::engine::{Engine, FunctionsLib}; -use crate::fn_native::{ - CallableFunction, - CallableFunction::{Method, Pure}, - FnCallArgs, IteratorFn, SharedFunction, -}; +use crate::fn_native::{CallableFunction as CF, FnCallArgs, IteratorFn, SharedIteratorFn}; use crate::parser::{ FnAccess, FnAccess::{Private, Public}, @@ -27,9 +23,7 @@ use crate::stdlib::{ mem, num::NonZeroUsize, ops::{Deref, DerefMut}, - rc::Rc, string::{String, ToString}, - sync::Arc, vec, vec::Vec, }; @@ -53,17 +47,17 @@ pub struct Module { all_variables: HashMap, /// External Rust functions. - functions: HashMap, SharedFunction)>, + functions: HashMap, CF)>, /// Script-defined functions. fn_lib: FunctionsLib, /// Iterator functions, keyed by the type producing the iterator. - type_iterators: HashMap, + type_iterators: HashMap, /// Flattened collection of all external Rust functions, native or scripted, /// including those in sub-modules. - all_functions: HashMap, + all_functions: HashMap, } impl fmt::Debug for Module { @@ -275,13 +269,7 @@ impl Module { /// Set a Rust function into the module, returning a hash key. /// /// If there is an existing Rust function of the same hash, it is replaced. - pub fn set_fn( - &mut self, - name: String, - access: FnAccess, - params: &[TypeId], - func: CallableFunction, - ) -> u64 { + pub fn set_fn(&mut self, name: String, access: FnAccess, params: &[TypeId], func: CF) -> u64 { let hash_fn = calc_fn_hash(empty(), &name, params.len(), params.iter().cloned()); let params = params.into_iter().cloned().collect(); @@ -312,8 +300,8 @@ impl Module { #[cfg(feature = "sync")] func: impl Fn() -> FuncReturn + Send + Sync + 'static, ) -> u64 { let f = move |_: &mut FnCallArgs| func().map(Dynamic::from); - let arg_types = []; - self.set_fn(name.into(), Public, &arg_types, Pure(Box::new(f))) + let args = []; + self.set_fn(name.into(), Public, &args, CF::from_pure(Box::new(f))) } /// Set a Rust function taking one parameter into the module, returning a hash key. @@ -337,8 +325,8 @@ impl Module { ) -> u64 { let f = move |args: &mut FnCallArgs| func(mem::take(args[0]).cast::()).map(Dynamic::from); - let arg_types = [TypeId::of::()]; - self.set_fn(name.into(), Public, &arg_types, Pure(Box::new(f))) + let args = [TypeId::of::()]; + self.set_fn(name.into(), Public, &args, CF::from_pure(Box::new(f))) } /// Set a Rust function taking one mutable parameter into the module, returning a hash key. @@ -363,8 +351,8 @@ impl Module { let f = move |args: &mut FnCallArgs| { func(args[0].downcast_mut::().unwrap()).map(Dynamic::from) }; - let arg_types = [TypeId::of::()]; - self.set_fn(name.into(), Public, &arg_types, Method(Box::new(f))) + let args = [TypeId::of::()]; + self.set_fn(name.into(), Public, &args, CF::from_method(Box::new(f))) } /// Set a Rust function taking two parameters into the module, returning a hash key. @@ -394,8 +382,8 @@ impl Module { func(a, b).map(Dynamic::from) }; - let arg_types = [TypeId::of::(), TypeId::of::()]; - self.set_fn(name.into(), Public, &arg_types, Pure(Box::new(f))) + let args = [TypeId::of::(), TypeId::of::()]; + self.set_fn(name.into(), Public, &args, CF::from_pure(Box::new(f))) } /// Set a Rust function taking two parameters (the first one mutable) into the module, @@ -429,8 +417,8 @@ impl Module { func(a, b).map(Dynamic::from) }; - let arg_types = [TypeId::of::(), TypeId::of::()]; - self.set_fn(name.into(), Public, &arg_types, Method(Box::new(f))) + let args = [TypeId::of::(), TypeId::of::()]; + self.set_fn(name.into(), Public, &args, CF::from_method(Box::new(f))) } /// Set a Rust function taking three parameters into the module, returning a hash key. @@ -467,8 +455,8 @@ impl Module { func(a, b, c).map(Dynamic::from) }; - let arg_types = [TypeId::of::(), TypeId::of::(), TypeId::of::()]; - self.set_fn(name.into(), Public, &arg_types, Pure(Box::new(f))) + let args = [TypeId::of::(), TypeId::of::(), TypeId::of::()]; + self.set_fn(name.into(), Public, &args, CF::from_pure(Box::new(f))) } /// Set a Rust function taking three parameters (the first one mutable) into the module, @@ -506,8 +494,8 @@ impl Module { func(a, b, c).map(Dynamic::from) }; - let arg_types = [TypeId::of::(), TypeId::of::(), TypeId::of::()]; - self.set_fn(name.into(), Public, &arg_types, Method(Box::new(f))) + let args = [TypeId::of::(), TypeId::of::(), TypeId::of::()]; + self.set_fn(name.into(), Public, &args, CF::from_method(Box::new(f))) } /// Get a Rust function. @@ -524,8 +512,8 @@ impl Module { /// let hash = module.set_fn_1("calc", |x: i64| Ok(x + 1)); /// assert!(module.get_fn(hash).is_some()); /// ``` - pub fn get_fn(&self, hash_fn: u64) -> Option<&CallableFunction> { - self.functions.get(&hash_fn).map(|(_, _, _, v)| v.as_ref()) + pub fn get_fn(&self, hash_fn: u64) -> Option<&CF> { + self.functions.get(&hash_fn).map(|(_, _, _, v)| v) } /// Get a modules-qualified function. @@ -536,16 +524,13 @@ impl Module { &mut self, name: &str, hash_fn_native: u64, - ) -> Result<&CallableFunction, Box> { - self.all_functions - .get(&hash_fn_native) - .map(|f| f.as_ref()) - .ok_or_else(|| { - Box::new(EvalAltResult::ErrorFunctionNotFound( - name.to_string(), - Position::none(), - )) - }) + ) -> Result<&CF, Box> { + self.all_functions.get(&hash_fn_native).ok_or_else(|| { + Box::new(EvalAltResult::ErrorFunctionNotFound( + name.to_string(), + Position::none(), + )) + }) } /// Create a new `Module` by evaluating an `AST`. @@ -606,7 +591,7 @@ impl Module { module: &'a Module, qualifiers: &mut Vec<&'a str>, variables: &mut Vec<(u64, Dynamic)>, - functions: &mut Vec<(u64, SharedFunction)>, + functions: &mut Vec<(u64, CF)>, ) { for (name, m) in &module.modules { // Index all the sub-modules first. @@ -655,7 +640,7 @@ impl Module { fn_def.params.len(), empty(), ); - functions.push((hash_fn_def, CallableFunction::Script(fn_def.clone()).into())); + functions.push((hash_fn_def, CF::Script(fn_def.clone()).into())); } } @@ -675,16 +660,11 @@ impl Module { /// Set a type iterator into the module. pub fn set_iter(&mut self, typ: TypeId, func: Box) { - #[cfg(not(feature = "sync"))] - self.type_iterators - .insert(typ, Rc::new(CallableFunction::Iterator(func))); - #[cfg(feature = "sync")] - self.type_iterators - .insert(typ, Arc::new(CallableFunction::Iterator(func))); + self.type_iterators.insert(typ, func.into()); } /// Get the specified type iterator. - pub fn get_iter(&self, id: TypeId) -> Option<&CallableFunction> { + pub fn get_iter(&self, id: TypeId) -> Option<&IteratorFn> { self.type_iterators.get(&id).map(|v| v.as_ref()) } } diff --git a/src/packages/mod.rs b/src/packages/mod.rs index 39ce601c..3e8a4f04 100644 --- a/src/packages/mod.rs +++ b/src/packages/mod.rs @@ -1,6 +1,6 @@ //! Module containing all built-in _packages_ available to Rhai, plus facilities to define custom packages. -use crate::fn_native::CallableFunction; +use crate::fn_native::{CallableFunction, IteratorFn}; use crate::module::Module; use crate::utils::StaticVec; @@ -81,7 +81,7 @@ impl PackagesCollection { self.packages.iter().any(|p| p.contains_iter(id)) } /// Get the specified TypeId iterator. - pub fn get_iter(&self, id: TypeId) -> Option<&CallableFunction> { + pub fn get_iter(&self, id: TypeId) -> Option<&IteratorFn> { self.packages .iter() .map(|p| p.get_iter(id)) diff --git a/src/parser.rs b/src/parser.rs index 1c013666..e03f3686 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -25,9 +25,7 @@ use crate::stdlib::{ iter::{empty, Peekable}, num::NonZeroUsize, ops::{Add, Deref, DerefMut}, - rc::Rc, string::{String, ToString}, - sync::Arc, vec, vec::Vec, }; @@ -59,21 +57,14 @@ type PERR = ParseErrorType; pub struct AST( /// Global statements. Vec, - /// Script-defined functions, wrapped in an `Arc` for shared access. - #[cfg(feature = "sync")] - Arc, - /// Script-defined functions, wrapped in an `Rc` for shared access. - #[cfg(not(feature = "sync"))] - Rc, + /// Script-defined functions. + FunctionsLib, ); impl AST { /// Create a new `AST`. pub fn new(statements: Vec, fn_lib: FunctionsLib) -> Self { - #[cfg(feature = "sync")] - return Self(statements, Arc::new(fn_lib)); - #[cfg(not(feature = "sync"))] - return Self(statements, Rc::new(fn_lib)); + Self(statements, fn_lib) } /// Get the statements. @@ -88,7 +79,7 @@ impl AST { /// Get the script-defined functions. pub(crate) fn fn_lib(&self) -> &FunctionsLib { - self.1.as_ref() + &self.1 } /// Merge two `AST` into one. Both `AST`'s are untouched and a new, merged, version @@ -147,20 +138,13 @@ impl AST { (true, true) => vec![], }; - Self::new(ast, functions.merge(other.1.as_ref())) + Self::new(ast, functions.merge(&other.1)) } /// Clear all function definitions in the `AST`. #[cfg(not(feature = "no_function"))] pub fn clear_functions(&mut self) { - #[cfg(feature = "sync")] - { - self.1 = Arc::new(Default::default()); - } - #[cfg(not(feature = "sync"))] - { - self.1 = Rc::new(Default::default()); - } + self.1 = Default::default(); } /// Clear all statements in the `AST`, leaving only function definitions. @@ -202,13 +186,6 @@ pub struct FnDef { pub pos: Position, } -/// A sharable script-defined function. -#[cfg(feature = "sync")] -pub type SharedFnDef = Arc; -/// A sharable script-defined function. -#[cfg(not(feature = "sync"))] -pub type SharedFnDef = Rc; - /// `return`/`throw` statement. #[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)] pub enum ReturnType {