Unify all functions under CallableFunction type.

This commit is contained in:
Stephen Chung 2020-05-19 19:03:06 +08:00
parent a22f338b03
commit 3295060dba
8 changed files with 199 additions and 220 deletions

View File

@ -3,7 +3,7 @@
use crate::any::{Dynamic, Union};
use crate::calc_fn_hash;
use crate::error::ParseErrorType;
use crate::fn_native::{FnCallArgs, NativeFunctionABI, PrintCallback, ProgressCallback};
use crate::fn_native::{FnCallArgs, PrintCallback, ProgressCallback};
use crate::module::Module;
use crate::optimize::OptimizationLevel;
use crate::packages::{CorePackage, Package, PackageLibrary, PackagesCollection, StandardPackage};
@ -229,15 +229,7 @@ impl FunctionsLib {
// Qualifiers (none) + function name + placeholders (one for each parameter).
let args_iter = repeat(EMPTY_TYPE_ID()).take(fn_def.params.len());
let hash = calc_fn_hash(empty(), &fn_def.name, args_iter);
#[cfg(feature = "sync")]
{
(hash, Arc::new(fn_def))
}
#[cfg(not(feature = "sync"))]
{
(hash, Rc::new(fn_def))
}
(hash, fn_def.into())
})
.collect(),
)
@ -268,8 +260,7 @@ impl FunctionsLib {
match fn_def.as_ref().map(|f| f.access) {
None => None,
Some(FnAccess::Private) if public_only => None,
Some(FnAccess::Private) => fn_def,
Some(FnAccess::Public) => fn_def,
Some(FnAccess::Private) | Some(FnAccess::Public) => fn_def,
}
}
/// Merge another `FunctionsLib` into this `FunctionsLib`.
@ -659,25 +650,20 @@ impl Engine {
.get_fn(hashes.0)
.or_else(|| self.packages.get_fn(hashes.0))
{
let mut backup: Dynamic = Default::default();
let (updated, restore) = match func.abi() {
// Calling pure function in method-call
NativeFunctionABI::Pure if is_ref && args.len() > 0 => {
// Backup the original value. It'll be consumed because the function
// is pure and doesn't know that the first value is a reference (i.e. `is_ref`)
backup = args[0].clone();
(false, true)
}
NativeFunctionABI::Pure => (false, false),
NativeFunctionABI::Method => (true, false),
// Calling pure function in method-call?
let backup: Option<Dynamic> = if func.is_pure() && is_ref && args.len() > 0 {
// Backup the original value. It'll be consumed because the function
// is pure and doesn't know that the first value is a reference (i.e. `is_ref`)
Some(args[0].clone())
} else {
None
};
// Run external function
let result = match func.call(args) {
let result = match func.get_native_fn()(args) {
Ok(r) => {
// Restore the backup value for the first argument since it has been consumed!
if restore {
if let Some(backup) = backup {
*args[0] = backup;
}
r
@ -709,7 +695,7 @@ impl Engine {
.into(),
false,
),
_ => (result, updated),
_ => (result, func.is_method()),
});
}
@ -780,14 +766,12 @@ impl Engine {
let scope_len = scope.len();
// Put arguments into scope as variables
// Actually consume the arguments instead of cloning them
scope.extend(
fn_def
.params
.iter()
.zip(
// Actually consume the arguments instead of cloning them
args.into_iter().map(|v| mem::take(*v)),
)
.zip(args.iter_mut().map(|v| mem::take(*v)))
.map(|(name, value)| {
let var_name =
unsafe_cast_var_name_to_lifetime(name.as_str(), &mut state);
@ -826,14 +810,12 @@ impl Engine {
let mut scope = Scope::new();
// Put arguments into scope as variables
// Actually consume the arguments instead of cloning them
scope.extend(
fn_def
.params
.iter()
.zip(
// Actually consume the arguments instead of cloning them
args.into_iter().map(|v| mem::take(*v)),
)
.zip(args.iter_mut().map(|v| mem::take(*v)))
.map(|(name, value)| (name, ScopeEntryType::Normal, value)),
);
@ -1558,32 +1540,43 @@ impl Engine {
};
// First search in script-defined functions (can override built-in)
if let Some(fn_def) = module.get_qualified_scripted_fn(*hash_fn_def) {
let args = args.as_mut();
let (result, state2) =
self.call_script_fn(None, *state, name, fn_def, args, *pos, level)?;
*state = state2;
Ok(result)
} else {
// Then search in Rust functions
self.inc_operations(state, *pos)?;
let func = match module.get_qualified_fn(name, *hash_fn_def) {
Err(err) if matches!(*err, EvalAltResult::ErrorFunctionNotFound(_, _)) => {
// Then search in Rust functions
self.inc_operations(state, *pos)?;
// Rust functions are indexed in two steps:
// 1) Calculate a hash in a similar manner to script-defined functions,
// i.e. qualifiers + function name + dummy parameter types (one for each parameter).
// 2) Calculate a second hash with no qualifiers, empty function name, and
// the actual list of parameter `TypeId`'.s
let hash_fn_args = calc_fn_hash(empty(), "", args.iter().map(|a| a.type_id()));
// 3) The final hash is the XOR of the two hashes.
let hash_fn_native = *hash_fn_def ^ hash_fn_args;
// Rust functions are indexed in two steps:
// 1) Calculate a hash in a similar manner to script-defined functions,
// i.e. qualifiers + function name + dummy parameter types (one for each parameter).
// 2) Calculate a second hash with no qualifiers, empty function name, and
// the actual list of parameter `TypeId`'.s
let hash_fn_args =
calc_fn_hash(empty(), "", args.iter().map(|a| a.type_id()));
// 3) The final hash is the XOR of the two hashes.
let hash_fn_native = *hash_fn_def ^ hash_fn_args;
match module.get_qualified_fn(name, hash_fn_native) {
Ok(func) => func
.call(args.as_mut())
.map_err(|err| err.new_position(*pos)),
Err(_) if def_val.is_some() => Ok(def_val.clone().unwrap()),
Err(err) => Err(err),
module.get_qualified_fn(name, hash_fn_native)
}
r => r,
};
match func {
Ok(x) if x.is_script() => {
let args = args.as_mut();
let fn_def = x.get_fn_def();
let (result, state2) =
self.call_script_fn(None, *state, name, fn_def, args, *pos, level)?;
*state = state2;
Ok(result)
}
Ok(x) => x.get_native_fn()(args.as_mut()).map_err(|err| err.new_position(*pos)),
Err(err)
if def_val.is_some()
&& matches!(*err, EvalAltResult::ErrorFunctionNotFound(_, _)) =>
{
Ok(def_val.clone().unwrap())
}
Err(err) => Err(err),
}
}
@ -1733,7 +1726,7 @@ impl Engine {
let iter_type = self.eval_expr(scope, state, expr, level)?;
let tid = iter_type.type_id();
if let Some(iter_fn) = self
if let Some(func) = self
.global_module
.get_iter(tid)
.or_else(|| self.packages.get_iter(tid))
@ -1744,7 +1737,7 @@ impl Engine {
let index = scope.len() - 1;
state.scope_level += 1;
for loop_var in iter_fn(iter_type) {
for loop_var in func.get_iter_fn()(iter_type) {
*scope.get_mut(index).0 = loop_var;
self.inc_operations(state, stmt.position())?;

View File

@ -1,4 +1,5 @@
use crate::any::Dynamic;
use crate::parser::{FnDef, SharedFnDef};
use crate::result::EvalAltResult;
use crate::stdlib::{boxed::Box, rc::Rc, sync::Arc};
@ -72,70 +73,98 @@ 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 {}
/// A type representing the type of ABI of a native Rust function.
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
pub enum NativeFunctionABI {
/// A pure function where all arguments are passed by value.
Pure,
/// An object method where the first argument is the object passed by mutable reference.
/// All other arguments are passed by value.
Method,
/// A type encapsulating a function callable by Rhai.
pub enum CallableFunction {
/// A pure native Rust function with all arguments passed by value.
Pure(Box<FnAny>),
/// A native Rust object method with the first argument passed by reference,
/// and the rest passed by value.
Method(Box<FnAny>),
/// An iterator function.
Iterator(Box<IteratorFn>),
/// A script-defined function.
Script(SharedFnDef),
}
/*
/// Trait implemented by all native Rust functions that are callable by Rhai.
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,
}
}
/// 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,
}
}
/// Is this an iterator function?
pub fn is_iter(&self) -> bool {
match self {
CallableFunction::Iterator(_) => true,
CallableFunction::Pure(_)
| CallableFunction::Method(_)
| CallableFunction::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,
}
}
/// Get a reference to a native Rust function.
///
/// # Panics
///
/// Panics if the `CallableFunction` is not `Pure` or `Method`.
pub fn get_native_fn(&self) -> &Box<FnAny> {
match self {
CallableFunction::Pure(f) | CallableFunction::Method(f) => f,
CallableFunction::Iterator(_) | CallableFunction::Script(_) => panic!(),
}
}
/// Get a reference to a script-defined function definition.
///
/// # Panics
///
/// 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,
}
}
/// Get a reference to an iterator function.
///
/// # Panics
///
/// Panics if the `CallableFunction` is not `Iterator`.
pub fn get_iter_fn(&self) -> &Box<IteratorFn> {
match self {
CallableFunction::Pure(_)
| CallableFunction::Method(_)
| CallableFunction::Script(_) => panic!(),
CallableFunction::Iterator(f) => f,
}
}
}
/// A callable function.
#[cfg(not(feature = "sync"))]
pub trait NativeCallable {
/// Get the ABI type of a native Rust function.
fn abi(&self) -> NativeFunctionABI;
/// Call a native Rust function.
fn call(&self, args: &mut FnCallArgs) -> Result<Dynamic, Box<EvalAltResult>>;
}
/// Trait implemented by all native Rust functions that are callable by Rhai.
pub type SharedFunction = Rc<CallableFunction>;
/// A callable function.
#[cfg(feature = "sync")]
pub trait NativeCallable: Send + Sync {
/// Get the ABI type of a native Rust function.
fn abi(&self) -> NativeFunctionABI;
/// Call a native Rust function.
fn call(&self, args: &mut FnCallArgs) -> Result<Dynamic, Box<EvalAltResult>>;
}
*/
/// A type encapsulating a native Rust function callable by Rhai.
pub struct NativeFunction(Box<FnAny>, NativeFunctionABI);
impl NativeFunction {
pub fn abi(&self) -> NativeFunctionABI {
self.1
}
pub fn call(&self, args: &mut FnCallArgs) -> Result<Dynamic, Box<EvalAltResult>> {
(self.0)(args)
}
}
impl From<(Box<FnAny>, NativeFunctionABI)> for NativeFunction {
fn from(func: (Box<FnAny>, NativeFunctionABI)) -> Self {
Self::new(func.0, func.1)
}
}
impl NativeFunction {
/// Create a new `NativeFunction`.
pub fn new(func: Box<FnAny>, abi: NativeFunctionABI) -> Self {
Self(func, abi)
}
}
/// An external native Rust function.
#[cfg(not(feature = "sync"))]
pub type SharedNativeFunction = Rc<NativeFunction>;
/// An external native Rust function.
#[cfg(feature = "sync")]
pub type SharedNativeFunction = Arc<NativeFunction>;
/// A type iterator function.
#[cfg(not(feature = "sync"))]
pub type SharedIteratorFunction = Rc<Box<IteratorFn>>;
/// An external native Rust function.
#[cfg(feature = "sync")]
pub type SharedIteratorFunction = Arc<Box<IteratorFn>>;
pub type SharedFunction = Arc<CallableFunction>;

View File

@ -4,7 +4,10 @@
use crate::any::{Dynamic, Variant};
use crate::engine::Engine;
use crate::fn_native::{FnCallArgs, NativeFunctionABI::*};
use crate::fn_native::{
CallableFunction::{Method, Pure},
FnCallArgs,
};
use crate::parser::FnAccess;
use crate::result::EvalAltResult;
@ -181,9 +184,9 @@ pub fn map_result<T: Variant + Clone>(
macro_rules! def_register {
() => {
def_register!(imp Pure;);
def_register!(imp Pure :);
};
(imp $abi:expr ; $($par:ident => $mark:ty => $param:ty => $clone:expr),*) => {
(imp $abi:ident : $($par:ident => $mark:ty => $param:ty => $clone:expr),*) => {
// ^ function ABI type
// ^ function parameter generic type name (A, B, C etc.)
// ^ function parameter marker type (T, Ref<T> or Mut<T>)
@ -202,9 +205,9 @@ macro_rules! def_register {
> RegisterFn<FN, ($($mark,)*), RET> for Engine
{
fn register_fn(&mut self, name: &str, f: FN) {
self.global_module.set_fn(name.to_string(), $abi, FnAccess::Public,
self.global_module.set_fn(name.to_string(), FnAccess::Public,
&[$(TypeId::of::<$par>()),*],
make_func!(f : map_dynamic ; $($par => $clone),*)
$abi(make_func!(f : map_dynamic ; $($par => $clone),*))
);
}
}
@ -220,9 +223,9 @@ macro_rules! def_register {
> RegisterDynamicFn<FN, ($($mark,)*)> for Engine
{
fn register_dynamic_fn(&mut self, name: &str, f: FN) {
self.global_module.set_fn(name.to_string(), $abi, FnAccess::Public,
self.global_module.set_fn(name.to_string(), FnAccess::Public,
&[$(TypeId::of::<$par>()),*],
make_func!(f : map_identity ; $($par => $clone),*)
$abi(make_func!(f : map_identity ; $($par => $clone),*))
);
}
}
@ -239,9 +242,9 @@ macro_rules! def_register {
> RegisterResultFn<FN, ($($mark,)*), RET> for Engine
{
fn register_result_fn(&mut self, name: &str, f: FN) {
self.global_module.set_fn(name.to_string(), $abi, FnAccess::Public,
self.global_module.set_fn(name.to_string(), FnAccess::Public,
&[$(TypeId::of::<$par>()),*],
make_func!(f : map_result ; $($par => $clone),*)
$abi(make_func!(f : map_result ; $($par => $clone),*))
);
}
}
@ -249,8 +252,9 @@ 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 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)*);
// ^ CallableFunction
// handle the first parameter ^ first parameter passed through
// ^ others passed by value (by_value)

View File

@ -91,7 +91,6 @@ mod utils;
pub use any::Dynamic;
pub use engine::Engine;
pub use error::{ParseError, ParseErrorType};
//pub use fn_native::NativeCallable;
pub use fn_register::{RegisterDynamicFn, RegisterFn, RegisterResultFn};
pub use module::Module;
pub use parser::{AST, INT};

View File

@ -4,10 +4,11 @@ use crate::any::{Dynamic, Variant};
use crate::calc_fn_hash;
use crate::engine::{Engine, FunctionsLib};
use crate::fn_native::{
FnAny, FnCallArgs, IteratorFn, NativeFunction, NativeFunctionABI, NativeFunctionABI::*,
SharedIteratorFunction, SharedNativeFunction,
CallableFunction,
CallableFunction::{Method, Pure},
FnCallArgs, IteratorFn, SharedFunction,
};
use crate::parser::{FnAccess, FnDef, SharedFnDef, AST};
use crate::parser::{FnAccess, AST};
use crate::result::EvalAltResult;
use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope};
use crate::token::{Position, Token};
@ -51,19 +52,17 @@ pub struct Module {
all_variables: HashMap<u64, Dynamic>,
/// External Rust functions.
functions: HashMap<u64, (String, FnAccess, StaticVec<TypeId>, SharedNativeFunction)>,
/// Flattened collection of all external Rust functions, including those in sub-modules.
all_functions: HashMap<u64, SharedNativeFunction>,
functions: HashMap<u64, (String, FnAccess, StaticVec<TypeId>, SharedFunction)>,
/// Script-defined functions.
fn_lib: FunctionsLib,
/// 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<TypeId, SharedIteratorFunction>,
type_iterators: HashMap<TypeId, SharedFunction>,
/// Flattened collection of all external Rust functions, native or scripted,
/// including those in sub-modules.
all_functions: HashMap<u64, SharedFunction>,
}
impl fmt::Debug for Module {
@ -278,23 +277,16 @@ impl Module {
pub fn set_fn(
&mut self,
name: String,
abi: NativeFunctionABI,
access: FnAccess,
params: &[TypeId],
func: Box<FnAny>,
func: CallableFunction,
) -> u64 {
let hash_fn = calc_fn_hash(empty(), &name, params.iter().cloned());
let f = NativeFunction::from((func, abi));
#[cfg(not(feature = "sync"))]
let func = Rc::new(f);
#[cfg(feature = "sync")]
let func = Arc::new(f);
let params = params.into_iter().cloned().collect();
self.functions.insert(hash_fn, (name, access, params, func));
self.functions
.insert(hash_fn, (name, access, params, func.into()));
hash_fn
}
@ -320,7 +312,7 @@ impl Module {
) -> u64 {
let f = move |_: &mut FnCallArgs| func().map(Dynamic::from);
let arg_types = [];
self.set_fn(name.into(), Pure, DEF_ACCESS, &arg_types, Box::new(f))
self.set_fn(name.into(), DEF_ACCESS, &arg_types, Pure(Box::new(f)))
}
/// Set a Rust function taking one parameter into the module, returning a hash key.
@ -345,7 +337,7 @@ impl Module {
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(), Pure, DEF_ACCESS, &arg_types, Box::new(f))
self.set_fn(name.into(), DEF_ACCESS, &arg_types, Pure(Box::new(f)))
}
/// Set a Rust function taking one mutable parameter into the module, returning a hash key.
@ -371,7 +363,7 @@ impl Module {
func(args[0].downcast_mut::<A>().unwrap()).map(Dynamic::from)
};
let arg_types = [TypeId::of::<A>()];
self.set_fn(name.into(), Method, DEF_ACCESS, &arg_types, Box::new(f))
self.set_fn(name.into(), DEF_ACCESS, &arg_types, Method(Box::new(f)))
}
/// Set a Rust function taking two parameters into the module, returning a hash key.
@ -402,7 +394,7 @@ impl Module {
func(a, b).map(Dynamic::from)
};
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>()];
self.set_fn(name.into(), Pure, DEF_ACCESS, &arg_types, Box::new(f))
self.set_fn(name.into(), DEF_ACCESS, &arg_types, Pure(Box::new(f)))
}
/// Set a Rust function taking two parameters (the first one mutable) into the module,
@ -437,7 +429,7 @@ impl Module {
func(a, b).map(Dynamic::from)
};
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>()];
self.set_fn(name.into(), Method, DEF_ACCESS, &arg_types, Box::new(f))
self.set_fn(name.into(), DEF_ACCESS, &arg_types, Method(Box::new(f)))
}
/// Set a Rust function taking three parameters into the module, returning a hash key.
@ -475,7 +467,7 @@ 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(), Pure, DEF_ACCESS, &arg_types, Box::new(f))
self.set_fn(name.into(), DEF_ACCESS, &arg_types, Pure(Box::new(f)))
}
/// Set a Rust function taking three parameters (the first one mutable) into the module,
@ -514,7 +506,7 @@ 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(), Method, DEF_ACCESS, &arg_types, Box::new(f))
self.set_fn(name.into(), DEF_ACCESS, &arg_types, Method(Box::new(f)))
}
/// Get a Rust function.
@ -531,7 +523,7 @@ 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<&NativeFunction> {
pub fn get_fn(&self, hash_fn: u64) -> Option<&CallableFunction> {
self.functions.get(&hash_fn).map(|(_, _, _, v)| v.as_ref())
}
@ -543,7 +535,7 @@ impl Module {
&mut self,
name: &str,
hash_fn_native: u64,
) -> Result<&NativeFunction, Box<EvalAltResult>> {
) -> Result<&CallableFunction, Box<EvalAltResult>> {
self.all_functions
.get(&hash_fn_native)
.map(|f| f.as_ref())
@ -555,13 +547,6 @@ impl Module {
})
}
/// Get a modules-qualified script-defined functions.
///
/// The `u64` hash is calculated by the function `crate::calc_fn_hash`.
pub(crate) fn get_qualified_scripted_fn(&mut self, hash_fn_def: u64) -> Option<&FnDef> {
self.all_fn_lib.get_function(hash_fn_def)
}
/// Create a new `Module` by evaluating an `AST`.
///
/// # Examples
@ -620,13 +605,12 @@ impl Module {
module: &'a Module,
qualifiers: &mut Vec<&'a str>,
variables: &mut Vec<(u64, Dynamic)>,
functions: &mut Vec<(u64, SharedNativeFunction)>,
fn_lib: &mut Vec<(u64, SharedFnDef)>,
functions: &mut Vec<(u64, SharedFunction)>,
) {
for (name, m) in &module.modules {
// Index all the sub-modules first.
qualifiers.push(name);
index_module(m, qualifiers, variables, functions, fn_lib);
index_module(m, qualifiers, variables, functions);
qualifiers.pop();
}
@ -672,25 +656,17 @@ impl Module {
&fn_def.name,
repeat(EMPTY_TYPE_ID()).take(fn_def.params.len()),
);
fn_lib.push((hash_fn_def, fn_def.clone()));
functions.push((hash_fn_def, CallableFunction::Script(fn_def.clone()).into()));
}
}
let mut variables = Vec::new();
let mut functions = Vec::new();
let mut fn_lib = Vec::new();
index_module(
self,
&mut vec!["root"],
&mut variables,
&mut functions,
&mut fn_lib,
);
index_module(self, &mut vec!["root"], &mut variables, &mut functions);
self.all_variables = variables.into_iter().collect();
self.all_functions = functions.into_iter().collect();
self.all_fn_lib = fn_lib.into();
}
/// Does a type iterator exist in the module?
@ -701,14 +677,16 @@ 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(func));
self.type_iterators
.insert(typ, Rc::new(CallableFunction::Iterator(func)));
#[cfg(feature = "sync")]
self.type_iterators.insert(typ, Arc::new(func));
self.type_iterators
.insert(typ, Arc::new(CallableFunction::Iterator(func)));
}
/// Get the specified type iterator.
pub fn get_iter(&self, id: TypeId) -> Option<&SharedIteratorFunction> {
self.type_iterators.get(&id)
pub fn get_iter(&self, id: TypeId) -> Option<&CallableFunction> {
self.type_iterators.get(&id).map(|v| v.as_ref())
}
}

View File

@ -119,12 +119,12 @@ fn call_fn(
pos: Position,
) -> Result<Option<Dynamic>, Box<EvalAltResult>> {
// Search built-in's and external functions
let hash = calc_fn_hash(empty(), fn_name, args.iter().map(|a| a.type_id()));
let hash_fn = calc_fn_hash(empty(), fn_name, args.iter().map(|a| a.type_id()));
global_module
.get_fn(hash)
.or_else(|| packages.get_fn(hash))
.map(|func| func.call(args))
.get_fn(hash_fn)
.or_else(|| packages.get_fn(hash_fn))
.map(|func| func.get_native_fn()(args))
.transpose()
.map_err(|err| err.new_position(pos))
}

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::{NativeFunction, SharedIteratorFunction};
use crate::fn_native::CallableFunction;
use crate::module::Module;
use crate::utils::StaticVec;
@ -69,7 +69,7 @@ impl PackagesCollection {
self.packages.iter().any(|p| p.contains_fn(hash))
}
/// Get specified function via its hash key.
pub fn get_fn(&self, hash: u64) -> Option<&NativeFunction> {
pub fn get_fn(&self, hash: u64) -> Option<&CallableFunction> {
self.packages
.iter()
.map(|p| p.get_fn(hash))
@ -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<&SharedIteratorFunction> {
pub fn get_iter(&self, id: TypeId) -> Option<&CallableFunction> {
self.packages
.iter()
.map(|p| p.get_iter(id))

View File

@ -36,10 +36,6 @@ pub enum EvalAltResult {
/// An error has occurred inside a called function.
/// Wrapped values re the name of the function and the interior error.
ErrorInFunctionCall(String, Box<EvalAltResult>, Position),
/// Function call has incorrect number of arguments.
/// Wrapped values are the name of the function, the number of parameters required
/// and the actual number of arguments passed.
ErrorFunctionArgsMismatch(String, usize, usize, Position),
/// Non-boolean operand encountered for boolean operator. Wrapped value is the operator.
ErrorBooleanArgMismatch(String, Position),
/// Non-character value encountered where a character is required.
@ -108,9 +104,6 @@ impl EvalAltResult {
Self::ErrorParsing(p) => p.desc(),
Self::ErrorInFunctionCall(_, _, _) => "Error in called function",
Self::ErrorFunctionNotFound(_, _) => "Function not found",
Self::ErrorFunctionArgsMismatch(_, _, _, _) => {
"Function call with wrong number of arguments"
}
Self::ErrorBooleanArgMismatch(_, _) => "Boolean operator expects boolean operands",
Self::ErrorCharMismatch(_) => "Character expected",
Self::ErrorNumericIndexExpr(_) => {
@ -208,21 +201,6 @@ impl fmt::Display for EvalAltResult {
Self::ErrorLoopBreak(_, pos) => write!(f, "{} ({})", desc, pos),
Self::Return(_, pos) => write!(f, "{} ({})", desc, pos),
Self::ErrorFunctionArgsMismatch(fn_name, 0, n, pos) => write!(
f,
"Function '{}' expects no argument but {} found ({})",
fn_name, n, pos
),
Self::ErrorFunctionArgsMismatch(fn_name, 1, n, pos) => write!(
f,
"Function '{}' expects one argument but {} found ({})",
fn_name, n, pos
),
Self::ErrorFunctionArgsMismatch(fn_name, need, n, pos) => write!(
f,
"Function '{}' expects {} argument(s) but {} found ({})",
fn_name, need, n, pos
),
Self::ErrorBooleanArgMismatch(op, pos) => {
write!(f, "{} operator expects boolean operands ({})", op, pos)
}
@ -292,7 +270,6 @@ impl EvalAltResult {
Self::ErrorFunctionNotFound(_, pos)
| Self::ErrorInFunctionCall(_, _, pos)
| Self::ErrorFunctionArgsMismatch(_, _, _, pos)
| Self::ErrorBooleanArgMismatch(_, pos)
| Self::ErrorCharMismatch(pos)
| Self::ErrorArrayBounds(_, _, pos)
@ -331,7 +308,6 @@ impl EvalAltResult {
Self::ErrorFunctionNotFound(_, pos)
| Self::ErrorInFunctionCall(_, _, pos)
| Self::ErrorFunctionArgsMismatch(_, _, _, pos)
| Self::ErrorBooleanArgMismatch(_, pos)
| Self::ErrorCharMismatch(pos)
| Self::ErrorArrayBounds(_, _, pos)