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`. * 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. * `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 Version 0.19.14

View File

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

View File

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

View File

@ -3,7 +3,7 @@
use crate::ast::{FnAccess, Ident}; use crate::ast::{FnAccess, Ident};
use crate::dynamic::Variant; use crate::dynamic::Variant;
use crate::fn_native::{shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, SendSync}; 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::{ use crate::stdlib::{
any::TypeId, any::TypeId,
boxed::Box, boxed::Box,
@ -607,7 +607,7 @@ impl Module {
/// Does the particular Rust function exist in the [`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 /// # Example
/// ///
@ -615,7 +615,7 @@ impl Module {
/// use rhai::Module; /// use rhai::Module;
/// ///
/// let mut module = Module::new(); /// 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)); /// assert!(module.contains_fn(hash, true));
/// ``` /// ```
#[inline(always)] #[inline(always)]
@ -634,7 +634,7 @@ impl Module {
/// Update the metadata (parameter names/types and return type) of a registered function. /// 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 /// ## Parameter Names and Types
/// ///
@ -654,7 +654,7 @@ impl Module {
/// Update the namespace of a registered function. /// 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)] #[inline(always)]
pub fn update_fn_namespace(&mut self, hash_fn: u64, namespace: FnNamespace) -> &mut Self { pub fn update_fn_namespace(&mut self, hash_fn: u64, namespace: FnNamespace) -> &mut Self {
if let Some(f) = self.functions.get_mut(&hash_fn) { 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. /// 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 /// # 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 /// # Example
/// ///
@ -836,101 +842,22 @@ impl Module {
/// use rhai::Module; /// use rhai::Module;
/// ///
/// let mut module = Module::new(); /// 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)); /// assert!(module.contains_fn(hash, true));
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn set_fn_0<T: Variant + Clone>( pub fn set_native_fn<ARGS, T, F>(&mut self, name: impl Into<String>, func: F) -> u64
&mut self, where
name: impl Into<String>, T: Variant + Clone,
func: impl Fn() -> Result<T, Box<EvalAltResult>> + SendSync + 'static, F: RegisterNativeFunction<ARGS, Result<T, Box<EvalAltResult>>>,
) -> u64 { {
let f = move |_: NativeCallContext, _: &mut FnCallArgs| func().map(Dynamic::from);
let arg_types = [];
self.set_fn( self.set_fn(
name, name,
FnNamespace::Internal, FnNamespace::Internal,
FnAccess::Public, FnAccess::Public,
None, None,
&arg_types, &F::param_types(),
CallableFunction::from_pure(Box::new(f)), func.into_callable_function(),
)
}
/// 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)),
) )
} }
@ -954,104 +881,20 @@ impl Module {
/// ``` /// ```
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
#[inline(always)] #[inline(always)]
pub fn set_getter_fn<A: Variant + Clone, T: Variant + Clone>( pub fn set_getter_fn<ARGS, A, T, F>(&mut self, name: impl Into<String>, func: F) -> u64
&mut self, where
name: impl Into<String>, A: Variant + Clone,
func: impl Fn(&mut A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static, T: Variant + Clone,
) -> u64 { F: RegisterNativeFunction<ARGS, Result<T, Box<EvalAltResult>>>,
self.set_fn_1_mut( F: Fn(&mut A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
{
self.set_fn(
crate::engine::make_getter(&name.into()), crate::engine::make_getter(&name.into()),
FnNamespace::Global, 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, FnAccess::Public,
None, None,
&arg_types, &F::param_types(),
CallableFunction::from_pure(Box::new(f)), func.into_callable_function(),
)
}
/// 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)),
) )
} }
@ -1079,15 +922,20 @@ impl Module {
/// ``` /// ```
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
#[inline(always)] #[inline(always)]
pub fn set_setter_fn<A: Variant + Clone, B: Variant + Clone>( pub fn set_setter_fn<ARGS, A, B, F>(&mut self, name: impl Into<String>, func: F) -> u64
&mut self, where
name: impl Into<String>, A: Variant + Clone,
func: impl Fn(&mut A, B) -> Result<(), Box<EvalAltResult>> + SendSync + 'static, B: Variant + Clone,
) -> u64 { F: RegisterNativeFunction<ARGS, Result<(), Box<EvalAltResult>>>,
self.set_fn_2_mut( F: Fn(&mut A, B) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
{
self.set_fn(
crate::engine::make_setter(&name.into()), crate::engine::make_setter(&name.into()),
FnNamespace::Global, FnNamespace::Global,
func, FnAccess::Public,
None,
&F::param_types(),
func.into_callable_function(),
) )
} }
@ -1119,10 +967,14 @@ impl Module {
/// ``` /// ```
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
#[inline(always)] #[inline(always)]
pub fn set_indexer_get_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>( pub fn set_indexer_get_fn<ARGS, A, B, T, F>(&mut self, func: F) -> u64
&mut self, where
func: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static, A: Variant + Clone,
) -> u64 { 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>() { if TypeId::of::<A>() == TypeId::of::<Array>() {
panic!("Cannot register indexer for arrays."); panic!("Cannot register indexer for arrays.");
} }
@ -1137,107 +989,13 @@ impl Module {
panic!("Cannot register indexer for strings."); 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( self.set_fn(
name, crate::engine::FN_IDX_GET,
FnNamespace::Internal, FnNamespace::Global,
FnAccess::Public, FnAccess::Public,
None, None,
&arg_types, &F::param_types(),
CallableFunction::from_pure(Box::new(f)), func.into_callable_function(),
)
}
/// 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)),
) )
} }
@ -1270,10 +1028,14 @@ impl Module {
/// ``` /// ```
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
#[inline(always)] #[inline(always)]
pub fn set_indexer_set_fn<A: Variant + Clone, B: Variant + Clone, C: Variant + Clone>( pub fn set_indexer_set_fn<ARGS, A, B, C, F>(&mut self, func: F) -> u64
&mut self, where
func: impl Fn(&mut A, B, C) -> Result<(), Box<EvalAltResult>> + SendSync + 'static, A: Variant + Clone,
) -> u64 { 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>() { if TypeId::of::<A>() == TypeId::of::<Array>() {
panic!("Cannot register indexer for arrays."); panic!("Cannot register indexer for arrays.");
} }
@ -1288,21 +1050,13 @@ impl Module {
panic!("Cannot register indexer for strings."); 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( self.set_fn(
crate::engine::FN_IDX_SET, crate::engine::FN_IDX_SET,
FnNamespace::Internal, FnNamespace::Global,
FnAccess::Public, FnAccess::Public,
None, None,
&arg_types, &F::param_types(),
CallableFunction::from_method(Box::new(f)), 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. /// 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)] #[inline(always)]
pub(crate) fn get_fn(&self, hash_fn: u64, public_only: bool) -> Option<&CallableFunction> { 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 { 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:ident | $x:expr => $( $y:ty ),*) => {
$( $(
$lib.set_iterator::<Range<$y>>(); $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, &[ $lib.update_fn_metadata(hash, &[
concat!("from: ", stringify!($y)), concat!("from: ", stringify!($y)),
concat!("to: ", stringify!($y)), concat!("to: ", stringify!($y)),
@ -152,7 +152,7 @@ macro_rules! reg_range {
($lib:ident | step $x:expr => $( $y:ty ),*) => { ($lib:ident | step $x:expr => $( $y:ty ),*) => {
$( $(
$lib.set_iterator::<StepRange<$y>>(); $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, &[ $lib.update_fn_metadata(hash, &[
concat!("from: ", stringify!($y)), concat!("from: ", stringify!($y)),
concat!("to: ", stringify!($y)), concat!("to: ", stringify!($y)),
@ -248,10 +248,10 @@ def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
lib.set_iterator::<StepDecimalRange>(); 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>"]); 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>"]); 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]) /// Macro that makes it easy to define a _package_ (which is basically a shared [module][Module])
/// and register functions into it. /// and register functions into it.
/// ///
/// Functions can be added to the package using the standard module methods such as /// Functions can be added to the package using [`Module::set_native_fn`].
/// [`set_fn_2`][Module::set_fn_2], [`set_fn_3_mut`][Module::set_fn_3_mut], [`set_fn_0`][Module::set_fn_0] etc.
/// ///
/// # Example /// # Example
/// ///
@ -69,7 +68,7 @@ pub trait Package {
/// def_package!(rhai:MyPackage:"My super-duper package", lib, /// def_package!(rhai:MyPackage:"My super-duper package", lib,
/// { /// {
/// // Load a binary function with all value parameters. /// // Load a binary function with all value parameters.
/// lib.set_fn_2("my_add", add); /// lib.set_native_fn("my_add", add);
/// }); /// });
/// ``` /// ```
#[macro_export] #[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 // Set a type iterator deep inside a nested module chain
let mut sub_module = Module::new(); let mut sub_module = Module::new();
sub_module.set_iterable::<MyIterableType>(); 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(); let mut module = Module::new();
module.set_sub_module("inner", sub_module); 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"))] #[cfg(not(feature = "no_module"))]
{ {
let mut m = Module::new(); 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); m.update_fn_namespace(hash, FnNamespace::Global);
engine.register_static_module("hello", m.into()); 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(); let mut sub_module2 = Module::new();
sub_module2.set_var("answer", 41 as INT); 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(); sub_module2.build_index();
assert!(!sub_module2.contains_indexed_global_functions()); 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(); sub_module2.build_index();
assert!(sub_module2.contains_indexed_global_functions()); assert!(sub_module2.contains_indexed_global_functions());
@ -91,16 +92,16 @@ fn test_module_resolver() -> Result<(), Box<EvalAltResult>> {
let mut module = Module::new(); let mut module = Module::new();
module.set_var("answer", 42 as INT); 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_native_fn("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| { let double_hash = module.set_native_fn("double", |x: &mut INT| {
*x *= 2; *x *= 2;
Ok(()) Ok(())
}); });
module.update_fn_namespace(double_hash, FnNamespace::Global);
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
module.set_fn_4_mut( module.set_native_fn(
"sum_of_three_args", "sum_of_three_args",
FnNamespace::Internal,
|target: &mut INT, a: INT, b: INT, c: rhai::FLOAT| { |target: &mut INT, a: INT, b: INT, c: rhai::FLOAT| {
*target = a + b + c as INT; *target = a + b + c as INT;
Ok(()) Ok(())
@ -407,9 +408,9 @@ fn test_module_str() -> Result<(), Box<EvalAltResult>> {
let mut engine = rhai::Engine::new(); let mut engine = rhai::Engine::new();
let mut module = Module::new(); let mut module = Module::new();
module.set_fn_1("test", test_fn); module.set_native_fn("test", test_fn);
module.set_fn_1("test2", test_fn2); module.set_native_fn("test2", test_fn2);
module.set_fn_1("test3", test_fn3); module.set_native_fn("test3", test_fn3);
let mut static_modules = rhai::module_resolvers::StaticModuleResolver::new(); let mut static_modules = rhai::module_resolvers::StaticModuleResolver::new();
static_modules.insert("test", module); static_modules.insert("test", module);