Deprecate Module::set_fn_XXX API.

This commit is contained in:
Stephen Chung 2021-03-15 12:39:06 +08:00
parent d0922adb5b
commit e9f280f917
9 changed files with 169 additions and 514 deletions

View File

@ -9,6 +9,7 @@ Breaking changes
* The traits `RegisterFn` and `RegisterResultFn` are removed. `Engine::register_fn` and `Engine::register_result_fn` are now implemented directly on `Engine`.
* `FnPtr::call_dynamic` now takes `&NativeCallContext` instead of consuming it.
* All `Module::set_fn_XXX` methods are removed, in favor of `Module::set_native_fn`.
Version 0.19.14

View File

@ -51,8 +51,18 @@ impl Engine {
/// # Ok(())
/// # }
/// ```
pub fn register_fn<A>(&mut self, name: &str, func: impl RegisterNativeFunction<A, ()>) -> &mut Self {
func.register_into(self, name);
pub fn register_fn<A, F>(&mut self, name: &str, func: F) -> &mut Self
where
F: RegisterNativeFunction<A, ()>,
{
self.global_namespace.set_fn(
name,
FnNamespace::Global,
FnAccess::Public,
None,
&F::param_types(),
func.into_callable_function(),
);
self
}
/// Register a custom fallible function with the [`Engine`].
@ -79,12 +89,18 @@ impl Engine {
/// engine.eval::<i64>("div(42, 0)")
/// .expect_err("expecting division by zero error!");
/// ```
pub fn register_result_fn<A>(
&mut self,
name: &str,
func: impl RegisterNativeFunction<A, RhaiResult>,
) -> &mut Self {
func.register_into(self, name);
pub fn register_result_fn<A, F>(&mut self, name: &str, func: F) -> &mut Self
where
F: RegisterNativeFunction<A, RhaiResult>,
{
self.global_namespace.set_fn(
name,
FnNamespace::Global,
FnAccess::Public,
None,
&F::param_types(),
func.into_callable_function(),
);
self
}
/// Register a function of the [`Engine`].
@ -803,8 +819,7 @@ impl Engine {
pub fn load_package(&mut self, module: impl Into<Shared<Module>>) -> &mut Self {
self.register_global_module(module.into())
}
/// Register a shared [`Module`] as a static module namespace with the
/// [`Engine`].
/// Register a shared [`Module`] as a static module namespace with the [`Engine`].
///
/// Functions marked [`FnNamespace::Global`] and type iterators are exposed to scripts without
/// namespace qualifications.
@ -819,7 +834,7 @@ impl Engine {
///
/// // Create the module
/// let mut module = Module::new();
/// module.set_fn_1("calc", |x: i64| Ok(x + 1));
/// module.set_native_fn("calc", |x: i64| Ok(x + 1));
///
/// let module: Shared<Module> = module.into();
///

View File

@ -5,8 +5,8 @@
use crate::dynamic::{DynamicWriteLock, Variant};
use crate::fn_native::{CallableFunction, FnAny, FnCallArgs, SendSync};
use crate::r#unsafe::unsafe_try_cast;
use crate::stdlib::{any::TypeId, boxed::Box, mem, string::String};
use crate::{Dynamic, Engine, FnAccess, FnNamespace, NativeCallContext, RhaiResult};
use crate::stdlib::{any::TypeId, boxed::Box, mem, string::String, vec};
use crate::{Dynamic, EvalAltResult, NativeCallContext};
// These types are used to build a unique _marker_ tuple type for each combination
// of function parameter types in order to make each trait implementation unique.
@ -53,10 +53,12 @@ pub fn by_value<T: Variant + Clone>(data: &mut Dynamic) -> T {
}
}
/// Trait to register custom functions with an [`Engine`].
/// Trait to register custom Rust functions.
pub trait RegisterNativeFunction<Args, Result> {
/// Register the function with an [`Engine`].
fn register_into(self, engine: &mut Engine, name: &str);
/// Get the types of this function's parameters.
fn param_types() -> Box<[TypeId]>;
/// Convert this function into a [`CallableFunction`].
fn into_callable_function(self) -> CallableFunction;
}
macro_rules! def_register {
@ -77,21 +79,20 @@ macro_rules! def_register {
RET: Variant + Clone
> RegisterNativeFunction<($($mark,)*), ()> for FN {
#[inline(always)]
fn register_into(self, engine: &mut Engine, name: &str) {
engine.global_namespace.set_fn(name, FnNamespace::Global, FnAccess::Public, None,
&[$(TypeId::of::<$par>()),*],
CallableFunction::$abi(Box::new(move |_: NativeCallContext, args: &mut FnCallArgs| {
// The arguments are assumed to be of the correct number and types!
let mut _drain = args.iter_mut();
$($let $par = ($clone)(_drain.next().unwrap()); )*
fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() }
#[inline(always)]
fn into_callable_function(self) -> CallableFunction {
CallableFunction::$abi(Box::new(move |_: NativeCallContext, args: &mut FnCallArgs| {
// The arguments are assumed to be of the correct number and types!
let mut _drain = args.iter_mut();
$($let $par = ($clone)(_drain.next().unwrap()); )*
// Call the function with each argument value
let r = self($($arg),*);
// Call the function with each argument value
let r = self($($arg),*);
// Map the result
Ok(r.into_dynamic())
}) as Box<FnAny>)
);
// Map the result
Ok(r.into_dynamic())
}) as Box<FnAny>)
}
}
@ -101,61 +102,60 @@ macro_rules! def_register {
RET: Variant + Clone
> RegisterNativeFunction<(NativeCallContext<'static>, $($mark,)*), ()> for FN {
#[inline(always)]
fn register_into(self, engine: &mut Engine, name: &str) {
engine.global_namespace.set_fn(name, FnNamespace::Global, FnAccess::Public, None,
&[$(TypeId::of::<$par>()),*],
CallableFunction::$abi(Box::new(move |ctx: NativeCallContext, args: &mut FnCallArgs| {
// The arguments are assumed to be of the correct number and types!
let mut _drain = args.iter_mut();
$($let $par = ($clone)(_drain.next().unwrap()); )*
fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() }
#[inline(always)]
fn into_callable_function(self) -> CallableFunction {
CallableFunction::$abi(Box::new(move |ctx: NativeCallContext, args: &mut FnCallArgs| {
// The arguments are assumed to be of the correct number and types!
let mut _drain = args.iter_mut();
$($let $par = ($clone)(_drain.next().unwrap()); )*
// Call the function with each argument value
let r = self(ctx, $($arg),*);
// Call the function with each argument value
let r = self(ctx, $($arg),*);
// Map the result
Ok(r.into_dynamic())
}) as Box<FnAny>)
);
// Map the result
Ok(r.into_dynamic())
}) as Box<FnAny>)
}
}
impl<
FN: Fn($($param),*) -> RhaiResult + SendSync + 'static,
FN: Fn($($param),*) -> Result<RET, Box<EvalAltResult>> + SendSync + 'static,
$($par: Variant + Clone,)*
> RegisterNativeFunction<($($mark,)*), RhaiResult> for FN {
RET: Variant + Clone
> RegisterNativeFunction<($($mark,)*), Result<RET, Box<EvalAltResult>>> for FN {
#[inline(always)]
fn register_into(self, engine: &mut Engine, name: &str) {
engine.global_namespace.set_fn(name, FnNamespace::Global, FnAccess::Public, None,
&[$(TypeId::of::<$par>()),*],
CallableFunction::$abi(Box::new(move |_: NativeCallContext, args: &mut FnCallArgs| {
// The arguments are assumed to be of the correct number and types!
let mut _drain = args.iter_mut();
$($let $par = ($clone)(_drain.next().unwrap()); )*
fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() }
#[inline(always)]
fn into_callable_function(self) -> CallableFunction {
CallableFunction::$abi(Box::new(move |_: NativeCallContext, args: &mut FnCallArgs| {
// The arguments are assumed to be of the correct number and types!
let mut _drain = args.iter_mut();
$($let $par = ($clone)(_drain.next().unwrap()); )*
// Call the function with each argument value
self($($arg),*)
}) as Box<FnAny>)
);
// Call the function with each argument value
self($($arg),*).map(Dynamic::from)
}) as Box<FnAny>)
}
}
impl<
FN: for<'a> Fn(NativeCallContext<'a>, $($param),*) -> RhaiResult + SendSync + 'static,
FN: for<'a> Fn(NativeCallContext<'a>, $($param),*) -> Result<RET, Box<EvalAltResult>> + SendSync + 'static,
$($par: Variant + Clone,)*
> RegisterNativeFunction<(NativeCallContext<'static>, $($mark,)*), RhaiResult> for FN {
RET: Variant + Clone
> RegisterNativeFunction<(NativeCallContext<'static>, $($mark,)*), Result<RET, Box<EvalAltResult>>> for FN {
#[inline(always)]
fn register_into(self, engine: &mut Engine, name: &str) {
engine.global_namespace.set_fn(name, FnNamespace::Global, FnAccess::Public, None,
&[$(TypeId::of::<$par>()),*],
CallableFunction::$abi(Box::new(move |ctx: NativeCallContext, args: &mut FnCallArgs| {
// The arguments are assumed to be of the correct number and types!
let mut _drain = args.iter_mut();
$($let $par = ($clone)(_drain.next().unwrap()); )*
fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() }
#[inline(always)]
fn into_callable_function(self) -> CallableFunction {
CallableFunction::$abi(Box::new(move |ctx: NativeCallContext, args: &mut FnCallArgs| {
// The arguments are assumed to be of the correct number and types!
let mut _drain = args.iter_mut();
$($let $par = ($clone)(_drain.next().unwrap()); )*
// Call the function with each argument value
self(ctx, $($arg),*)
}) as Box<FnAny>)
);
// Call the function with each argument value
self(ctx, $($arg),*).map(Dynamic::from)
}) as Box<FnAny>)
}
}

View File

@ -3,7 +3,7 @@
use crate::ast::{FnAccess, Ident};
use crate::dynamic::Variant;
use crate::fn_native::{shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, SendSync};
use crate::fn_register::by_value as cast_arg;
use crate::fn_register::RegisterNativeFunction;
use crate::stdlib::{
any::TypeId,
boxed::Box,
@ -607,7 +607,7 @@ impl Module {
/// Does the particular Rust function exist in the [`Module`]?
///
/// The [`u64`] hash is returned by the `set_fn_XXX` calls.
/// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call.
///
/// # Example
///
@ -615,7 +615,7 @@ impl Module {
/// use rhai::Module;
///
/// let mut module = Module::new();
/// let hash = module.set_fn_0("calc", || Ok(42_i64));
/// let hash = module.set_native_fn("calc", || Ok(42_i64));
/// assert!(module.contains_fn(hash, true));
/// ```
#[inline(always)]
@ -634,7 +634,7 @@ impl Module {
/// Update the metadata (parameter names/types and return type) of a registered function.
///
/// The [`u64`] hash is returned by the `set_fn_XXX` calls.
/// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call.
///
/// ## Parameter Names and Types
///
@ -654,7 +654,7 @@ impl Module {
/// Update the namespace of a registered function.
///
/// The [`u64`] hash is returned by the `set_fn_XXX` calls.
/// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call.
#[inline(always)]
pub fn update_fn_namespace(&mut self, hash_fn: u64, namespace: FnNamespace) -> &mut Self {
if let Some(f) = self.functions.get_mut(&hash_fn) {
@ -822,13 +822,19 @@ impl Module {
)
}
/// Set a Rust function taking no parameters into the [`Module`], returning a hash key.
/// Set a Rust function into the [`Module`], returning a hash key.
///
/// If there is a similar existing Rust function, it is replaced.
///
/// # Function Namespace
///
/// The default function namespace is [`FnNamespace::Internal`].
/// Use [`update_fn_namespace`][Module::update_fn_namespace] to change it.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
/// No metadata for the function is registered.
/// Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata.
///
/// # Example
///
@ -836,101 +842,22 @@ impl Module {
/// use rhai::Module;
///
/// let mut module = Module::new();
/// let hash = module.set_fn_0("calc", || Ok(42_i64));
/// let hash = module.set_native_fn("calc", || Ok(42_i64));
/// assert!(module.contains_fn(hash, true));
/// ```
#[inline(always)]
pub fn set_fn_0<T: Variant + Clone>(
&mut self,
name: impl Into<String>,
func: impl Fn() -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
) -> u64 {
let f = move |_: NativeCallContext, _: &mut FnCallArgs| func().map(Dynamic::from);
let arg_types = [];
pub fn set_native_fn<ARGS, T, F>(&mut self, name: impl Into<String>, func: F) -> u64
where
T: Variant + Clone,
F: RegisterNativeFunction<ARGS, Result<T, Box<EvalAltResult>>>,
{
self.set_fn(
name,
FnNamespace::Internal,
FnAccess::Public,
None,
&arg_types,
CallableFunction::from_pure(Box::new(f)),
)
}
/// Set a Rust function taking one parameter into the [`Module`], returning a hash key.
///
/// If there is a similar existing Rust function, it is replaced.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
/// use rhai::Module;
///
/// let mut module = Module::new();
/// let hash = module.set_fn_1("calc", |x: i64| Ok(x + 1));
/// assert!(module.contains_fn(hash, true));
/// ```
#[inline(always)]
pub fn set_fn_1<A: Variant + Clone, T: Variant + Clone>(
&mut self,
name: impl Into<String>,
func: impl Fn(A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
) -> u64 {
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
func(cast_arg::<A>(&mut args[0])).map(Dynamic::from)
};
let arg_types = [TypeId::of::<A>()];
self.set_fn(
name,
FnNamespace::Internal,
FnAccess::Public,
None,
&arg_types,
CallableFunction::from_pure(Box::new(f)),
)
}
/// Set a Rust function taking one mutable parameter into the [`Module`], returning a hash key.
///
/// If there is a similar existing Rust function, it is replaced.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
/// use rhai::{Module, FnNamespace};
///
/// let mut module = Module::new();
/// let hash = module.set_fn_1_mut("calc", FnNamespace::Internal,
/// |x: &mut i64| { *x += 1; Ok(*x) }
/// );
/// assert!(module.contains_fn(hash, true));
/// ```
#[inline(always)]
pub fn set_fn_1_mut<A: Variant + Clone, T: Variant + Clone>(
&mut self,
name: impl Into<String>,
namespace: FnNamespace,
func: impl Fn(&mut A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
) -> u64 {
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
func(&mut args[0].write_lock::<A>().unwrap()).map(Dynamic::from)
};
let arg_types = [TypeId::of::<A>()];
self.set_fn(
name,
namespace,
FnAccess::Public,
None,
&arg_types,
CallableFunction::from_method(Box::new(f)),
&F::param_types(),
func.into_callable_function(),
)
}
@ -954,104 +881,20 @@ impl Module {
/// ```
#[cfg(not(feature = "no_object"))]
#[inline(always)]
pub fn set_getter_fn<A: Variant + Clone, T: Variant + Clone>(
&mut self,
name: impl Into<String>,
func: impl Fn(&mut A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
) -> u64 {
self.set_fn_1_mut(
pub fn set_getter_fn<ARGS, A, T, F>(&mut self, name: impl Into<String>, func: F) -> u64
where
A: Variant + Clone,
T: Variant + Clone,
F: RegisterNativeFunction<ARGS, Result<T, Box<EvalAltResult>>>,
F: Fn(&mut A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
{
self.set_fn(
crate::engine::make_getter(&name.into()),
FnNamespace::Global,
func,
)
}
/// Set a Rust function taking two parameters into the [`Module`], returning a hash key.
///
/// If there is a similar existing Rust function, it is replaced.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
/// use rhai::{Module, ImmutableString};
///
/// let mut module = Module::new();
/// let hash = module.set_fn_2("calc", |x: i64, y: ImmutableString| {
/// Ok(x + y.len() as i64)
/// });
/// assert!(module.contains_fn(hash, true));
/// ```
#[inline(always)]
pub fn set_fn_2<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
&mut self,
name: impl Into<String>,
func: impl Fn(A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
) -> u64 {
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
let a = cast_arg::<A>(&mut args[0]);
let b = cast_arg::<B>(&mut args[1]);
func(a, b).map(Dynamic::from)
};
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>()];
self.set_fn(
name,
FnNamespace::Internal,
FnAccess::Public,
None,
&arg_types,
CallableFunction::from_pure(Box::new(f)),
)
}
/// Set a Rust function taking two parameters (the first one mutable) into the [`Module`],
/// returning a hash key.
///
/// If there is a similar existing Rust function, it is replaced.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
/// use rhai::{Module, FnNamespace, ImmutableString};
///
/// let mut module = Module::new();
/// let hash = module.set_fn_2_mut("calc", FnNamespace::Internal,
/// |x: &mut i64, y: ImmutableString| {
/// *x += y.len() as i64;
/// Ok(*x)
/// }
/// );
/// assert!(module.contains_fn(hash, true));
/// ```
#[inline(always)]
pub fn set_fn_2_mut<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
&mut self,
name: impl Into<String>,
namespace: FnNamespace,
func: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
) -> u64 {
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
let b = cast_arg::<B>(&mut args[1]);
let a = &mut args[0].write_lock::<A>().unwrap();
func(a, b).map(Dynamic::from)
};
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>()];
self.set_fn(
name,
namespace,
FnAccess::Public,
None,
&arg_types,
CallableFunction::from_method(Box::new(f)),
&F::param_types(),
func.into_callable_function(),
)
}
@ -1079,15 +922,20 @@ impl Module {
/// ```
#[cfg(not(feature = "no_object"))]
#[inline(always)]
pub fn set_setter_fn<A: Variant + Clone, B: Variant + Clone>(
&mut self,
name: impl Into<String>,
func: impl Fn(&mut A, B) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
) -> u64 {
self.set_fn_2_mut(
pub fn set_setter_fn<ARGS, A, B, F>(&mut self, name: impl Into<String>, func: F) -> u64
where
A: Variant + Clone,
B: Variant + Clone,
F: RegisterNativeFunction<ARGS, Result<(), Box<EvalAltResult>>>,
F: Fn(&mut A, B) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
{
self.set_fn(
crate::engine::make_setter(&name.into()),
FnNamespace::Global,
func,
FnAccess::Public,
None,
&F::param_types(),
func.into_callable_function(),
)
}
@ -1119,10 +967,14 @@ impl Module {
/// ```
#[cfg(not(feature = "no_index"))]
#[inline(always)]
pub fn set_indexer_get_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
&mut self,
func: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
) -> u64 {
pub fn set_indexer_get_fn<ARGS, A, B, T, F>(&mut self, func: F) -> u64
where
A: Variant + Clone,
B: Variant + Clone,
T: Variant + Clone,
F: RegisterNativeFunction<ARGS, Result<T, Box<EvalAltResult>>>,
F: Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
{
if TypeId::of::<A>() == TypeId::of::<Array>() {
panic!("Cannot register indexer for arrays.");
}
@ -1137,107 +989,13 @@ impl Module {
panic!("Cannot register indexer for strings.");
}
self.set_fn_2_mut(crate::engine::FN_IDX_GET, FnNamespace::Global, func)
}
/// Set a Rust function taking three parameters into the [`Module`], returning a hash key.
///
/// If there is a similar existing Rust function, it is replaced.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
/// use rhai::{Module, ImmutableString};
///
/// let mut module = Module::new();
/// let hash = module.set_fn_3("calc", |x: i64, y: ImmutableString, z: i64| {
/// Ok(x + y.len() as i64 + z)
/// });
/// assert!(module.contains_fn(hash, true));
/// ```
#[inline(always)]
pub fn set_fn_3<
A: Variant + Clone,
B: Variant + Clone,
C: Variant + Clone,
T: Variant + Clone,
>(
&mut self,
name: impl Into<String>,
func: impl Fn(A, B, C) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
) -> u64 {
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
let a = cast_arg::<A>(&mut args[0]);
let b = cast_arg::<B>(&mut args[1]);
let c = cast_arg::<C>(&mut args[2]);
func(a, b, c).map(Dynamic::from)
};
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
self.set_fn(
name,
FnNamespace::Internal,
crate::engine::FN_IDX_GET,
FnNamespace::Global,
FnAccess::Public,
None,
&arg_types,
CallableFunction::from_pure(Box::new(f)),
)
}
/// Set a Rust function taking three parameters (the first one mutable) into the [`Module`],
/// returning a hash key.
///
/// If there is a similar existing Rust function, it is replaced.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
/// use rhai::{Module, FnNamespace, ImmutableString};
///
/// let mut module = Module::new();
/// let hash = module.set_fn_3_mut("calc", FnNamespace::Internal,
/// |x: &mut i64, y: ImmutableString, z: i64| {
/// *x += y.len() as i64 + z;
/// Ok(*x)
/// }
/// );
/// assert!(module.contains_fn(hash, true));
/// ```
#[inline(always)]
pub fn set_fn_3_mut<
A: Variant + Clone,
B: Variant + Clone,
C: Variant + Clone,
T: Variant + Clone,
>(
&mut self,
name: impl Into<String>,
namespace: FnNamespace,
func: impl Fn(&mut A, B, C) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
) -> u64 {
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
let b = cast_arg::<B>(&mut args[2]);
let c = cast_arg::<C>(&mut args[3]);
let a = &mut args[0].write_lock::<A>().unwrap();
func(a, b, c).map(Dynamic::from)
};
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
self.set_fn(
name,
namespace,
FnAccess::Public,
None,
&arg_types,
CallableFunction::from_method(Box::new(f)),
&F::param_types(),
func.into_callable_function(),
)
}
@ -1270,10 +1028,14 @@ impl Module {
/// ```
#[cfg(not(feature = "no_index"))]
#[inline(always)]
pub fn set_indexer_set_fn<A: Variant + Clone, B: Variant + Clone, C: Variant + Clone>(
&mut self,
func: impl Fn(&mut A, B, C) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
) -> u64 {
pub fn set_indexer_set_fn<ARGS, A, B, C, F>(&mut self, func: F) -> u64
where
A: Variant + Clone,
B: Variant + Clone,
C: Variant + Clone,
F: RegisterNativeFunction<ARGS, Result<(), Box<EvalAltResult>>>,
F: Fn(&mut A, B, C) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
{
if TypeId::of::<A>() == TypeId::of::<Array>() {
panic!("Cannot register indexer for arrays.");
}
@ -1288,21 +1050,13 @@ impl Module {
panic!("Cannot register indexer for strings.");
}
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
let b = cast_arg::<B>(&mut args[1]);
let c = cast_arg::<C>(&mut args[2]);
let a = &mut args[0].write_lock::<A>().unwrap();
func(a, b, c).map(Dynamic::from)
};
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
self.set_fn(
crate::engine::FN_IDX_SET,
FnNamespace::Internal,
FnNamespace::Global,
FnAccess::Public,
None,
&arg_types,
CallableFunction::from_method(Box::new(f)),
&F::param_types(),
func.into_callable_function(),
)
}
@ -1352,124 +1106,9 @@ impl Module {
)
}
/// Set a Rust function taking four parameters into the [`Module`], returning a hash key.
///
/// If there is a similar existing Rust function, it is replaced.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
/// use rhai::{Module, ImmutableString};
///
/// let mut module = Module::new();
/// let hash = module.set_fn_4("calc", |x: i64, y: ImmutableString, z: i64, _w: ()| {
/// Ok(x + y.len() as i64 + z)
/// });
/// assert!(module.contains_fn(hash, true));
/// ```
#[inline(always)]
pub fn set_fn_4<
A: Variant + Clone,
B: Variant + Clone,
C: Variant + Clone,
D: Variant + Clone,
T: Variant + Clone,
>(
&mut self,
name: impl Into<String>,
func: impl Fn(A, B, C, D) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
) -> u64 {
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
let a = cast_arg::<A>(&mut args[0]);
let b = cast_arg::<B>(&mut args[1]);
let c = cast_arg::<C>(&mut args[2]);
let d = cast_arg::<D>(&mut args[3]);
func(a, b, c, d).map(Dynamic::from)
};
let arg_types = [
TypeId::of::<A>(),
TypeId::of::<B>(),
TypeId::of::<C>(),
TypeId::of::<D>(),
];
self.set_fn(
name,
FnNamespace::Internal,
FnAccess::Public,
None,
&arg_types,
CallableFunction::from_pure(Box::new(f)),
)
}
/// Set a Rust function taking four parameters (the first one mutable) into the [`Module`],
/// returning a hash key.
///
/// If there is a similar existing Rust function, it is replaced.
///
/// # Function Metadata
///
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
///
/// # Example
///
/// ```
/// use rhai::{Module, FnNamespace, ImmutableString};
///
/// let mut module = Module::new();
/// let hash = module.set_fn_4_mut("calc", FnNamespace::Internal,
/// |x: &mut i64, y: ImmutableString, z: i64, _w: ()| {
/// *x += y.len() as i64 + z;
/// Ok(*x)
/// }
/// );
/// assert!(module.contains_fn(hash, true));
/// ```
#[inline(always)]
pub fn set_fn_4_mut<
A: Variant + Clone,
B: Variant + Clone,
C: Variant + Clone,
D: Variant + Clone,
T: Variant + Clone,
>(
&mut self,
name: impl Into<String>,
namespace: FnNamespace,
func: impl Fn(&mut A, B, C, D) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
) -> u64 {
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
let b = cast_arg::<B>(&mut args[1]);
let c = cast_arg::<C>(&mut args[2]);
let d = cast_arg::<D>(&mut args[3]);
let a = &mut args[0].write_lock::<A>().unwrap();
func(a, b, c, d).map(Dynamic::from)
};
let arg_types = [
TypeId::of::<A>(),
TypeId::of::<B>(),
TypeId::of::<C>(),
TypeId::of::<D>(),
];
self.set_fn(
name,
namespace,
FnAccess::Public,
None,
&arg_types,
CallableFunction::from_method(Box::new(f)),
)
}
/// Get a Rust function.
///
/// The [`u64`] hash is returned by the `set_fn_XXX` calls.
/// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call.
#[inline(always)]
pub(crate) fn get_fn(&self, hash_fn: u64, public_only: bool) -> Option<&CallableFunction> {
self.functions.get(&hash_fn).and_then(|f| match f.access {

View File

@ -141,7 +141,7 @@ macro_rules! reg_range {
($lib:ident | $x:expr => $( $y:ty ),*) => {
$(
$lib.set_iterator::<Range<$y>>();
let hash = $lib.set_fn_2($x, get_range::<$y>);
let hash = $lib.set_native_fn($x, get_range::<$y>);
$lib.update_fn_metadata(hash, &[
concat!("from: ", stringify!($y)),
concat!("to: ", stringify!($y)),
@ -152,7 +152,7 @@ macro_rules! reg_range {
($lib:ident | step $x:expr => $( $y:ty ),*) => {
$(
$lib.set_iterator::<StepRange<$y>>();
let hash = $lib.set_fn_3($x, get_step_range::<$y>);
let hash = $lib.set_native_fn($x, get_step_range::<$y>);
$lib.update_fn_metadata(hash, &[
concat!("from: ", stringify!($y)),
concat!("to: ", stringify!($y)),
@ -248,10 +248,10 @@ def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
lib.set_iterator::<StepDecimalRange>();
let hash = lib.set_fn_2("range", |from, to| StepDecimalRange::new(from, to, Decimal::one()));
let hash = lib.set_native_fn("range", |from, to| StepDecimalRange::new(from, to, Decimal::one()));
lib.update_fn_metadata(hash, &["from: Decimal", "to: Decimal", "Iterator<Item=Decimal>"]);
let hash = lib.set_fn_3("range", |from, to, step| StepDecimalRange::new(from, to, step));
let hash = lib.set_native_fn("range", |from, to, step| StepDecimalRange::new(from, to, step));
lib.update_fn_metadata(hash, &["from: Decimal", "to: Decimal", "step: Decimal", "Iterator<Item=Decimal>"]);
}
});

View File

@ -53,8 +53,7 @@ pub trait Package {
/// Macro that makes it easy to define a _package_ (which is basically a shared [module][Module])
/// and register functions into it.
///
/// Functions can be added to the package using the standard module methods such as
/// [`set_fn_2`][Module::set_fn_2], [`set_fn_3_mut`][Module::set_fn_3_mut], [`set_fn_0`][Module::set_fn_0] etc.
/// Functions can be added to the package using [`Module::set_native_fn`].
///
/// # Example
///
@ -69,7 +68,7 @@ pub trait Package {
/// def_package!(rhai:MyPackage:"My super-duper package", lib,
/// {
/// // Load a binary function with all value parameters.
/// lib.set_fn_2("my_add", add);
/// lib.set_native_fn("my_add", add);
/// });
/// ```
#[macro_export]

View File

@ -171,7 +171,7 @@ fn test_for_module_iterator() -> Result<(), Box<EvalAltResult>> {
// Set a type iterator deep inside a nested module chain
let mut sub_module = Module::new();
sub_module.set_iterable::<MyIterableType>();
sub_module.set_fn_0("new_ts", || Ok(MyIterableType("hello".to_string())));
sub_module.set_native_fn("new_ts", || Ok(MyIterableType("hello".to_string())));
let mut module = Module::new();
module.set_sub_module("inner", sub_module);

View File

@ -75,7 +75,7 @@ fn test_functions_namespaces() -> Result<(), Box<EvalAltResult>> {
#[cfg(not(feature = "no_module"))]
{
let mut m = Module::new();
let hash = m.set_fn_0("test", || Ok(999 as INT));
let hash = m.set_native_fn("test", || Ok(999 as INT));
m.update_fn_namespace(hash, FnNamespace::Global);
engine.register_static_module("hello", m.into());

View File

@ -23,11 +23,12 @@ fn test_module_sub_module() -> Result<(), Box<EvalAltResult>> {
let mut sub_module2 = Module::new();
sub_module2.set_var("answer", 41 as INT);
let hash_inc = sub_module2.set_fn_1_mut("inc", FnNamespace::Internal, |x: &mut INT| Ok(*x + 1));
let hash_inc = sub_module2.set_native_fn("inc", |x: &mut INT| Ok(*x + 1));
sub_module2.build_index();
assert!(!sub_module2.contains_indexed_global_functions());
sub_module2.set_fn_1_mut("super_inc", FnNamespace::Global, |x: &mut INT| Ok(*x + 1));
let super_hash = sub_module2.set_native_fn("super_inc", |x: &mut INT| Ok(*x + 1));
sub_module2.update_fn_namespace(super_hash, FnNamespace::Global);
sub_module2.build_index();
assert!(sub_module2.contains_indexed_global_functions());
@ -91,16 +92,16 @@ fn test_module_resolver() -> Result<(), Box<EvalAltResult>> {
let mut module = Module::new();
module.set_var("answer", 42 as INT);
module.set_fn_4("sum", |x: INT, y: INT, z: INT, w: INT| Ok(x + y + z + w));
module.set_fn_1_mut("double", FnNamespace::Global, |x: &mut INT| {
module.set_native_fn("sum", |x: INT, y: INT, z: INT, w: INT| Ok(x + y + z + w));
let double_hash = module.set_native_fn("double", |x: &mut INT| {
*x *= 2;
Ok(())
});
module.update_fn_namespace(double_hash, FnNamespace::Global);
#[cfg(not(feature = "no_float"))]
module.set_fn_4_mut(
module.set_native_fn(
"sum_of_three_args",
FnNamespace::Internal,
|target: &mut INT, a: INT, b: INT, c: rhai::FLOAT| {
*target = a + b + c as INT;
Ok(())
@ -407,9 +408,9 @@ fn test_module_str() -> Result<(), Box<EvalAltResult>> {
let mut engine = rhai::Engine::new();
let mut module = Module::new();
module.set_fn_1("test", test_fn);
module.set_fn_1("test2", test_fn2);
module.set_fn_1("test3", test_fn3);
module.set_native_fn("test", test_fn);
module.set_native_fn("test2", test_fn2);
module.set_native_fn("test3", test_fn3);
let mut static_modules = rhai::module_resolvers::StaticModuleResolver::new();
static_modules.insert("test", module);