Reduce Rc/Arc wrapping for functions.

This commit is contained in:
Stephen Chung 2020-05-19 22:25:57 +08:00
parent ab76a69b12
commit 4a1fd66b9f
6 changed files with 97 additions and 138 deletions

View File

@ -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())?;

View File

@ -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<dyn Iterator<Item = Dynamic>> + '
#[cfg(not(feature = "sync"))]
impl<F: Fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>> + 'static> IteratorCallback for F {}
#[cfg(not(feature = "sync"))]
pub type SharedNativeFunction = Rc<FnAny>;
#[cfg(feature = "sync")]
pub type SharedNativeFunction = Arc<FnAny>;
#[cfg(not(feature = "sync"))]
pub type SharedIteratorFn = Rc<IteratorFn>;
#[cfg(feature = "sync")]
pub type SharedIteratorFn = Arc<IteratorFn>;
#[cfg(feature = "sync")]
pub type SharedFnDef = Arc<FnDef>;
#[cfg(not(feature = "sync"))]
pub type SharedFnDef = Rc<FnDef>;
/// 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<FnAny>),
Pure(SharedNativeFunction),
/// A native Rust object method with the first argument passed by reference,
/// and the rest passed by value.
Method(Box<FnAny>),
Method(SharedNativeFunction),
/// An iterator function.
Iterator(Box<IteratorFn>),
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<FnAny> {
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<IteratorFn> {
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<FnAny>) -> Self {
Self::Pure(func.into())
}
/// Create a new `CallableFunction::Method`.
pub fn from_method(func: Box<FnAny>) -> Self {
Self::Method(func.into())
}
}
/// A callable function.
#[cfg(not(feature = "sync"))]
pub type SharedFunction = Rc<CallableFunction>;
/// A callable function.
#[cfg(feature = "sync")]
pub type SharedFunction = Arc<CallableFunction>;

View File

@ -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<FnAny>
};
}
@ -184,7 +181,7 @@ pub fn map_result<T: Variant + Clone>(
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

View File

@ -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<u64, Dynamic>,
/// External Rust functions.
functions: HashMap<u64, (String, FnAccess, StaticVec<TypeId>, SharedFunction)>,
functions: HashMap<u64, (String, FnAccess, StaticVec<TypeId>, CF)>,
/// Script-defined functions.
fn_lib: FunctionsLib,
/// Iterator functions, keyed by the type producing the iterator.
type_iterators: HashMap<TypeId, SharedFunction>,
type_iterators: HashMap<TypeId, SharedIteratorFn>,
/// Flattened collection of all external Rust functions, native or scripted,
/// including those in sub-modules.
all_functions: HashMap<u64, SharedFunction>,
all_functions: HashMap<u64, CF>,
}
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<T> + 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::<A>()).map(Dynamic::from);
let arg_types = [TypeId::of::<A>()];
self.set_fn(name.into(), Public, &arg_types, Pure(Box::new(f)))
let args = [TypeId::of::<A>()];
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::<A>().unwrap()).map(Dynamic::from)
};
let arg_types = [TypeId::of::<A>()];
self.set_fn(name.into(), Public, &arg_types, Method(Box::new(f)))
let args = [TypeId::of::<A>()];
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::<A>(), TypeId::of::<B>()];
self.set_fn(name.into(), Public, &arg_types, Pure(Box::new(f)))
let args = [TypeId::of::<A>(), TypeId::of::<B>()];
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::<A>(), TypeId::of::<B>()];
self.set_fn(name.into(), Public, &arg_types, Method(Box::new(f)))
let args = [TypeId::of::<A>(), TypeId::of::<B>()];
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::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
self.set_fn(name.into(), Public, &arg_types, Pure(Box::new(f)))
let args = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
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::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
self.set_fn(name.into(), Public, &arg_types, Method(Box::new(f)))
let args = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
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<EvalAltResult>> {
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<EvalAltResult>> {
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<IteratorFn>) {
#[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())
}
}

View File

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

View File

@ -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<Stmt>,
/// Script-defined functions, wrapped in an `Arc` for shared access.
#[cfg(feature = "sync")]
Arc<FunctionsLib>,
/// Script-defined functions, wrapped in an `Rc` for shared access.
#[cfg(not(feature = "sync"))]
Rc<FunctionsLib>,
/// Script-defined functions.
FunctionsLib,
);
impl AST {
/// Create a new `AST`.
pub fn new(statements: Vec<Stmt>, 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<FnDef>;
/// A sharable script-defined function.
#[cfg(not(feature = "sync"))]
pub type SharedFnDef = Rc<FnDef>;
/// `return`/`throw` statement.
#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)]
pub enum ReturnType {