2021-11-20 14:57:21 +08:00
|
|
|
//! Module that defines the public function/module registration API of [`Engine`].
|
|
|
|
|
|
|
|
use crate::func::{FnCallArgs, RegisterNativeFunction, SendSync};
|
|
|
|
use crate::types::dynamic::Variant;
|
|
|
|
use crate::{
|
2021-12-25 23:49:14 +08:00
|
|
|
Engine, FnAccess, FnNamespace, Identifier, Module, NativeCallContext, RhaiResultOf, Shared,
|
2022-11-08 15:01:40 +08:00
|
|
|
SharedModule,
|
2021-11-20 14:57:21 +08:00
|
|
|
};
|
|
|
|
use std::any::{type_name, TypeId};
|
|
|
|
#[cfg(feature = "no_std")]
|
|
|
|
use std::prelude::v1::*;
|
|
|
|
|
2022-08-22 22:28:27 +08:00
|
|
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
|
|
|
use crate::func::register::Mut;
|
|
|
|
|
2021-11-20 14:57:21 +08:00
|
|
|
impl Engine {
|
2022-03-19 09:43:18 +08:00
|
|
|
/// Get the global namespace module (which is the fist module in `global_modules`).
|
2021-11-20 14:57:21 +08:00
|
|
|
#[inline(always)]
|
|
|
|
#[allow(dead_code)]
|
2022-09-25 12:24:03 +08:00
|
|
|
#[must_use]
|
2021-11-20 14:57:21 +08:00
|
|
|
pub(crate) fn global_namespace(&self) -> &Module {
|
2022-01-06 11:07:52 +08:00
|
|
|
self.global_modules.first().unwrap()
|
2021-11-20 14:57:21 +08:00
|
|
|
}
|
|
|
|
/// Get a mutable reference to the global namespace module
|
|
|
|
/// (which is the first module in `global_modules`).
|
|
|
|
#[inline(always)]
|
2022-09-25 12:24:03 +08:00
|
|
|
#[must_use]
|
2021-11-20 14:57:21 +08:00
|
|
|
pub(crate) fn global_namespace_mut(&mut self) -> &mut Module {
|
2022-01-06 11:07:52 +08:00
|
|
|
let module = self.global_modules.first_mut().unwrap();
|
|
|
|
Shared::get_mut(module).expect("not shared")
|
2021-11-20 14:57:21 +08:00
|
|
|
}
|
|
|
|
/// Register a custom function with the [`Engine`].
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
|
|
|
/// // Normal function
|
|
|
|
/// fn add(x: i64, y: i64) -> i64 {
|
|
|
|
/// x + y
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
|
|
|
/// engine.register_fn("add", add);
|
|
|
|
///
|
|
|
|
/// assert_eq!(engine.eval::<i64>("add(40, 2)")?, 42);
|
|
|
|
///
|
|
|
|
/// // You can also register a closure.
|
|
|
|
/// engine.register_fn("sub", |x: i64, y: i64| x - y );
|
|
|
|
///
|
|
|
|
/// assert_eq!(engine.eval::<i64>("sub(44, 2)")?, 42);
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[inline]
|
2022-08-24 18:27:58 +08:00
|
|
|
pub fn register_fn<A, R, S, F: RegisterNativeFunction<A, R, S>>(
|
|
|
|
&mut self,
|
|
|
|
name: impl AsRef<str> + Into<Identifier>,
|
|
|
|
func: F,
|
|
|
|
) -> &mut Self {
|
2021-11-20 14:57:21 +08:00
|
|
|
let param_types = F::param_types();
|
|
|
|
|
|
|
|
#[cfg(feature = "metadata")]
|
|
|
|
let mut param_type_names: crate::StaticVec<_> = F::param_names()
|
|
|
|
.iter()
|
2022-01-17 21:51:04 +08:00
|
|
|
.map(|ty| format!("_: {}", self.format_type_name(ty)))
|
2021-11-20 14:57:21 +08:00
|
|
|
.collect();
|
|
|
|
|
|
|
|
#[cfg(feature = "metadata")]
|
|
|
|
if F::return_type() != TypeId::of::<()>() {
|
2022-01-17 21:51:04 +08:00
|
|
|
param_type_names.push(self.format_type_name(F::return_type_name()).into());
|
2021-11-20 14:57:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "metadata")]
|
2022-01-06 11:07:52 +08:00
|
|
|
let param_type_names: crate::StaticVec<_> =
|
2022-07-27 18:04:59 +08:00
|
|
|
param_type_names.iter().map(String::as_str).collect();
|
2022-01-06 11:07:52 +08:00
|
|
|
#[cfg(feature = "metadata")]
|
|
|
|
let param_type_names = Some(param_type_names.as_ref());
|
2021-11-20 14:57:21 +08:00
|
|
|
|
|
|
|
#[cfg(not(feature = "metadata"))]
|
2022-01-06 11:07:52 +08:00
|
|
|
let param_type_names: Option<&[&str]> = None;
|
2021-11-20 14:57:21 +08:00
|
|
|
|
|
|
|
self.global_namespace_mut().set_fn(
|
|
|
|
name,
|
|
|
|
FnNamespace::Global,
|
|
|
|
FnAccess::Public,
|
2022-01-06 11:07:52 +08:00
|
|
|
param_type_names,
|
|
|
|
param_types,
|
2021-11-20 14:57:21 +08:00
|
|
|
func.into_callable_function(),
|
|
|
|
);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
/// Register a function of the [`Engine`].
|
|
|
|
///
|
|
|
|
/// # WARNING - Low Level API
|
|
|
|
///
|
2021-12-09 12:49:12 +08:00
|
|
|
/// This function is very low level. It takes a list of [`TypeId`][std::any::TypeId]'s
|
|
|
|
/// indicating the actual types of the parameters.
|
2021-11-20 14:57:21 +08:00
|
|
|
///
|
2021-12-27 11:43:11 +08:00
|
|
|
/// # Arguments
|
2021-11-29 12:43:59 +08:00
|
|
|
///
|
2021-12-09 12:49:12 +08:00
|
|
|
/// Arguments are simply passed in as a mutable array of [`&mut Dynamic`][crate::Dynamic].
|
2021-11-20 14:57:21 +08:00
|
|
|
/// The arguments are guaranteed to be of the correct types matching the [`TypeId`][std::any::TypeId]'s.
|
|
|
|
///
|
|
|
|
/// To access a primary argument value (i.e. cloning is cheap), use: `args[n].as_xxx().unwrap()`
|
|
|
|
///
|
|
|
|
/// To access an argument value and avoid cloning, use `std::mem::take(args[n]).cast::<T>()`.
|
|
|
|
/// Notice that this will _consume_ the argument, replacing it with `()`.
|
|
|
|
///
|
|
|
|
/// To access the first mutable parameter, use `args.get_mut(0).unwrap()`
|
|
|
|
#[inline(always)]
|
2022-08-24 18:27:58 +08:00
|
|
|
pub fn register_raw_fn<T: Variant + Clone>(
|
2021-11-20 14:57:21 +08:00
|
|
|
&mut self,
|
2022-08-24 18:27:58 +08:00
|
|
|
name: impl AsRef<str> + Into<Identifier>,
|
2022-01-04 15:22:48 +08:00
|
|
|
arg_types: impl AsRef<[TypeId]>,
|
2021-12-25 23:49:14 +08:00
|
|
|
func: impl Fn(NativeCallContext, &mut FnCallArgs) -> RhaiResultOf<T> + SendSync + 'static,
|
2022-08-24 18:27:58 +08:00
|
|
|
) -> &mut Self {
|
2021-11-20 14:57:21 +08:00
|
|
|
self.global_namespace_mut().set_raw_fn(
|
|
|
|
name,
|
|
|
|
FnNamespace::Global,
|
|
|
|
FnAccess::Public,
|
|
|
|
arg_types,
|
|
|
|
func,
|
|
|
|
);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
/// Register a custom type for use with the [`Engine`].
|
|
|
|
/// The type must implement [`Clone`].
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// #[derive(Debug, Clone, Eq, PartialEq)]
|
|
|
|
/// struct TestStruct {
|
|
|
|
/// field: i64
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl TestStruct {
|
2021-12-27 21:56:50 +08:00
|
|
|
/// fn new() -> Self {
|
|
|
|
/// Self { field: 1 }
|
|
|
|
/// }
|
|
|
|
/// fn update(&mut self, offset: i64) {
|
|
|
|
/// self.field += offset;
|
|
|
|
/// }
|
2021-11-20 14:57:21 +08:00
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
|
|
|
/// // Register API for the custom type.
|
|
|
|
/// engine
|
|
|
|
/// .register_type::<TestStruct>()
|
|
|
|
/// .register_fn("new_ts", TestStruct::new)
|
|
|
|
/// // Use `register_fn` to register methods on the type.
|
|
|
|
/// .register_fn("update", TestStruct::update);
|
|
|
|
///
|
|
|
|
/// # #[cfg(not(feature = "no_object"))]
|
|
|
|
/// assert_eq!(
|
|
|
|
/// engine.eval::<TestStruct>("let x = new_ts(); x.update(41); x")?,
|
|
|
|
/// TestStruct { field: 42 }
|
|
|
|
/// );
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn register_type<T: Variant + Clone>(&mut self) -> &mut Self {
|
|
|
|
self.register_type_with_name::<T>(type_name::<T>())
|
|
|
|
}
|
|
|
|
/// Register a custom type for use with the [`Engine`], with a pretty-print name
|
|
|
|
/// for the `type_of` function. The type must implement [`Clone`].
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// #[derive(Clone)]
|
|
|
|
/// struct TestStruct {
|
|
|
|
/// field: i64
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl TestStruct {
|
2021-12-27 21:56:50 +08:00
|
|
|
/// fn new() -> Self {
|
|
|
|
/// Self { field: 1 }
|
|
|
|
/// }
|
2021-11-20 14:57:21 +08:00
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
|
|
|
/// // Register API for the custom type.
|
|
|
|
/// engine
|
|
|
|
/// .register_type::<TestStruct>()
|
|
|
|
/// .register_fn("new_ts", TestStruct::new);
|
|
|
|
///
|
|
|
|
/// assert_eq!(
|
|
|
|
/// engine.eval::<String>("let x = new_ts(); type_of(x)")?,
|
|
|
|
/// "rust_out::TestStruct"
|
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// // Re-register the custom type with a name.
|
|
|
|
/// engine.register_type_with_name::<TestStruct>("Hello");
|
|
|
|
///
|
|
|
|
/// assert_eq!(
|
|
|
|
/// engine.eval::<String>("let x = new_ts(); type_of(x)")?,
|
|
|
|
/// "Hello"
|
|
|
|
/// );
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn register_type_with_name<T: Variant + Clone>(&mut self, name: &str) -> &mut Self {
|
2022-03-29 08:18:20 +08:00
|
|
|
self.global_namespace_mut().set_custom_type::<T>(name);
|
2022-03-19 09:43:18 +08:00
|
|
|
self
|
2021-12-09 12:49:12 +08:00
|
|
|
}
|
|
|
|
/// Register a custom type for use with the [`Engine`], with a pretty-print name
|
|
|
|
/// for the `type_of` function. The type must implement [`Clone`].
|
|
|
|
///
|
|
|
|
/// # WARNING - Low Level API
|
|
|
|
///
|
|
|
|
/// This function is low level.
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn register_type_with_name_raw(
|
|
|
|
&mut self,
|
2022-10-04 15:33:51 +08:00
|
|
|
type_path: impl Into<Identifier>,
|
2022-01-06 11:07:52 +08:00
|
|
|
name: impl Into<Identifier>,
|
2021-12-09 12:49:12 +08:00
|
|
|
) -> &mut Self {
|
2021-11-20 14:57:21 +08:00
|
|
|
// Add the pretty-print type name into the map
|
2022-03-29 08:18:20 +08:00
|
|
|
self.global_namespace_mut()
|
2022-10-04 15:33:51 +08:00
|
|
|
.set_custom_type_raw(type_path, name);
|
2021-11-20 14:57:21 +08:00
|
|
|
self
|
|
|
|
}
|
2022-08-22 14:02:24 +08:00
|
|
|
/// Register a type iterator for an iterable type with the [`Engine`].
|
2022-03-09 09:25:55 +08:00
|
|
|
/// This is an advanced API.
|
2021-11-20 14:57:21 +08:00
|
|
|
#[inline(always)]
|
|
|
|
pub fn register_iterator<T>(&mut self) -> &mut Self
|
|
|
|
where
|
|
|
|
T: Variant + Clone + IntoIterator,
|
|
|
|
<T as IntoIterator>::Item: Variant + Clone,
|
|
|
|
{
|
|
|
|
self.global_namespace_mut().set_iterable::<T>();
|
|
|
|
self
|
|
|
|
}
|
2022-08-22 14:02:24 +08:00
|
|
|
/// Register a fallible type iterator for an iterable type with the [`Engine`].
|
|
|
|
/// This is an advanced API.
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn register_iterator_result<T, X>(&mut self) -> &mut Self
|
|
|
|
where
|
|
|
|
T: Variant + Clone + IntoIterator<Item = RhaiResultOf<X>>,
|
|
|
|
X: Variant + Clone,
|
|
|
|
{
|
|
|
|
self.global_namespace_mut().set_iterable_result::<T, X>();
|
|
|
|
self
|
|
|
|
}
|
2021-11-20 14:57:21 +08:00
|
|
|
/// Register a getter function for a member of a registered type with the [`Engine`].
|
|
|
|
///
|
|
|
|
/// The function signature must start with `&mut self` and not `&self`.
|
|
|
|
///
|
|
|
|
/// Not available under `no_object`.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// #[derive(Clone)]
|
|
|
|
/// struct TestStruct {
|
|
|
|
/// field: i64
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl TestStruct {
|
2021-12-27 21:56:50 +08:00
|
|
|
/// fn new() -> Self {
|
|
|
|
/// Self { field: 1 }
|
|
|
|
/// }
|
2021-11-20 14:57:21 +08:00
|
|
|
/// // Even a getter must start with `&mut self` and not `&self`.
|
2021-12-27 21:56:50 +08:00
|
|
|
/// fn get_field(&mut self) -> i64 {
|
|
|
|
/// self.field
|
|
|
|
/// }
|
2021-11-20 14:57:21 +08:00
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
|
|
|
/// // Register API for the custom type.
|
|
|
|
/// engine
|
|
|
|
/// .register_type::<TestStruct>()
|
|
|
|
/// .register_fn("new_ts", TestStruct::new)
|
|
|
|
/// // Register a getter on a property (notice it doesn't have to be the same name).
|
|
|
|
/// .register_get("xyz", TestStruct::get_field);
|
|
|
|
///
|
|
|
|
/// assert_eq!(engine.eval::<i64>("let a = new_ts(); a.xyz")?, 1);
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
|
|
|
#[inline(always)]
|
2022-08-21 22:59:49 +08:00
|
|
|
pub fn register_get<T: Variant + Clone, V: Variant + Clone, S>(
|
2021-11-20 14:57:21 +08:00
|
|
|
&mut self,
|
2021-11-27 23:04:45 +08:00
|
|
|
name: impl AsRef<str>,
|
2022-08-21 22:59:49 +08:00
|
|
|
get_fn: impl RegisterNativeFunction<(Mut<T>,), V, S> + SendSync + 'static,
|
2021-11-20 14:57:21 +08:00
|
|
|
) -> &mut Self {
|
2022-01-04 15:22:48 +08:00
|
|
|
self.register_fn(crate::engine::make_getter(name.as_ref()).as_str(), get_fn)
|
2021-11-20 14:57:21 +08:00
|
|
|
}
|
|
|
|
/// Register a setter function for a member of a registered type with the [`Engine`].
|
|
|
|
///
|
|
|
|
/// Not available under `no_object`.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// #[derive(Debug, Clone, Eq, PartialEq)]
|
|
|
|
/// struct TestStruct {
|
|
|
|
/// field: i64
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl TestStruct {
|
2021-12-27 21:56:50 +08:00
|
|
|
/// fn new() -> Self {
|
|
|
|
/// Self { field: 1 }
|
|
|
|
/// }
|
|
|
|
/// fn set_field(&mut self, new_val: i64) {
|
|
|
|
/// self.field = new_val;
|
|
|
|
/// }
|
2021-11-20 14:57:21 +08:00
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
|
|
|
/// // Register API for the custom type.
|
|
|
|
/// engine
|
|
|
|
/// .register_type::<TestStruct>()
|
|
|
|
/// .register_fn("new_ts", TestStruct::new)
|
|
|
|
/// // Register a setter on a property (notice it doesn't have to be the same name)
|
|
|
|
/// .register_set("xyz", TestStruct::set_field);
|
|
|
|
///
|
|
|
|
/// // Notice that, with a getter, there is no way to get the property value
|
|
|
|
/// assert_eq!(
|
|
|
|
/// engine.eval::<TestStruct>("let a = new_ts(); a.xyz = 42; a")?,
|
|
|
|
/// TestStruct { field: 42 }
|
|
|
|
/// );
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
|
|
|
#[inline(always)]
|
2022-08-21 22:59:49 +08:00
|
|
|
pub fn register_set<T: Variant + Clone, V: Variant + Clone, S>(
|
2021-11-20 14:57:21 +08:00
|
|
|
&mut self,
|
2021-11-27 23:04:45 +08:00
|
|
|
name: impl AsRef<str>,
|
2022-08-21 22:59:49 +08:00
|
|
|
set_fn: impl RegisterNativeFunction<(Mut<T>, V), (), S> + SendSync + 'static,
|
2021-11-20 14:57:21 +08:00
|
|
|
) -> &mut Self {
|
2022-01-04 15:22:48 +08:00
|
|
|
self.register_fn(crate::engine::make_setter(name.as_ref()).as_str(), set_fn)
|
2021-11-20 14:57:21 +08:00
|
|
|
}
|
|
|
|
/// Short-hand for registering both getter and setter functions
|
|
|
|
/// of a registered type with the [`Engine`].
|
|
|
|
///
|
|
|
|
/// All function signatures must start with `&mut self` and not `&self`.
|
|
|
|
///
|
|
|
|
/// Not available under `no_object`.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// #[derive(Clone)]
|
|
|
|
/// struct TestStruct {
|
|
|
|
/// field: i64
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl TestStruct {
|
2021-12-27 21:56:50 +08:00
|
|
|
/// fn new() -> Self {
|
|
|
|
/// Self { field: 1 }
|
|
|
|
/// }
|
2021-11-20 14:57:21 +08:00
|
|
|
/// // Even a getter must start with `&mut self` and not `&self`.
|
2021-12-27 21:56:50 +08:00
|
|
|
/// fn get_field(&mut self) -> i64 {
|
|
|
|
/// self.field
|
|
|
|
/// }
|
|
|
|
/// fn set_field(&mut self, new_val: i64) {
|
|
|
|
/// self.field = new_val;
|
|
|
|
/// }
|
2021-11-20 14:57:21 +08:00
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
|
|
|
/// // Register API for the custom type.
|
|
|
|
/// engine
|
|
|
|
/// .register_type::<TestStruct>()
|
|
|
|
/// .register_fn("new_ts", TestStruct::new)
|
|
|
|
/// // Register both a getter and a setter on a property
|
|
|
|
/// // (notice it doesn't have to be the same name)
|
|
|
|
/// .register_get_set("xyz", TestStruct::get_field, TestStruct::set_field);
|
|
|
|
///
|
|
|
|
/// assert_eq!(engine.eval::<i64>("let a = new_ts(); a.xyz = 42; a.xyz")?, 42);
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
|
|
|
#[inline(always)]
|
2022-08-22 00:15:00 +08:00
|
|
|
pub fn register_get_set<T: Variant + Clone, V: Variant + Clone, S1, S2>(
|
2021-11-20 14:57:21 +08:00
|
|
|
&mut self,
|
2021-11-27 23:04:45 +08:00
|
|
|
name: impl AsRef<str>,
|
2022-08-22 00:15:00 +08:00
|
|
|
get_fn: impl RegisterNativeFunction<(Mut<T>,), V, S1> + SendSync + 'static,
|
|
|
|
set_fn: impl RegisterNativeFunction<(Mut<T>, V), (), S2> + SendSync + 'static,
|
2021-11-20 14:57:21 +08:00
|
|
|
) -> &mut Self {
|
2021-11-27 23:04:45 +08:00
|
|
|
self.register_get(&name, get_fn).register_set(&name, set_fn)
|
2021-11-20 14:57:21 +08:00
|
|
|
}
|
|
|
|
/// Register an index getter for a custom type with the [`Engine`].
|
|
|
|
///
|
|
|
|
/// The function signature must start with `&mut self` and not `&self`.
|
|
|
|
///
|
|
|
|
/// Not available under both `no_index` and `no_object`.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
2021-12-06 20:52:47 +08:00
|
|
|
/// Panics if the type is [`Array`][crate::Array], [`Map`][crate::Map], [`String`],
|
2021-11-20 14:57:21 +08:00
|
|
|
/// [`ImmutableString`][crate::ImmutableString], `&str` or [`INT`][crate::INT].
|
|
|
|
/// Indexers for arrays, object maps, strings and integers cannot be registered.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// #[derive(Clone)]
|
|
|
|
/// struct TestStruct {
|
|
|
|
/// fields: Vec<i64>
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl TestStruct {
|
2021-12-27 21:56:50 +08:00
|
|
|
/// fn new() -> Self {
|
|
|
|
/// Self { fields: vec![1, 2, 3, 4, 5] }
|
|
|
|
/// }
|
2021-11-20 14:57:21 +08:00
|
|
|
/// // Even a getter must start with `&mut self` and not `&self`.
|
2021-12-27 21:56:50 +08:00
|
|
|
/// fn get_field(&mut self, index: i64) -> i64 {
|
|
|
|
/// self.fields[index as usize]
|
|
|
|
/// }
|
2021-11-20 14:57:21 +08:00
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
|
|
|
/// // Register API for the custom type.
|
|
|
|
/// # #[cfg(not(feature = "no_object"))]
|
|
|
|
/// engine.register_type::<TestStruct>();
|
|
|
|
///
|
|
|
|
/// engine
|
|
|
|
/// .register_fn("new_ts", TestStruct::new)
|
|
|
|
/// // Register an indexer.
|
|
|
|
/// .register_indexer_get(TestStruct::get_field);
|
|
|
|
///
|
|
|
|
/// # #[cfg(not(feature = "no_index"))]
|
|
|
|
/// assert_eq!(engine.eval::<i64>("let a = new_ts(); a[2]")?, 3);
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
|
|
|
#[inline]
|
2022-08-21 22:59:49 +08:00
|
|
|
pub fn register_indexer_get<T: Variant + Clone, X: Variant + Clone, V: Variant + Clone, S>(
|
2021-11-20 14:57:21 +08:00
|
|
|
&mut self,
|
2022-08-21 22:59:49 +08:00
|
|
|
get_fn: impl RegisterNativeFunction<(Mut<T>, X), V, S> + SendSync + 'static,
|
2021-11-20 14:57:21 +08:00
|
|
|
) -> &mut Self {
|
|
|
|
#[cfg(not(feature = "no_index"))]
|
2021-12-06 20:52:47 +08:00
|
|
|
if TypeId::of::<T>() == TypeId::of::<crate::Array>() {
|
2021-11-20 14:57:21 +08:00
|
|
|
panic!("Cannot register indexer for arrays.");
|
|
|
|
}
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
2021-12-06 20:52:47 +08:00
|
|
|
if TypeId::of::<T>() == TypeId::of::<crate::Map>() {
|
2021-11-20 14:57:21 +08:00
|
|
|
panic!("Cannot register indexer for object maps.");
|
|
|
|
}
|
|
|
|
if TypeId::of::<T>() == TypeId::of::<String>()
|
|
|
|
|| TypeId::of::<T>() == TypeId::of::<&str>()
|
|
|
|
|| TypeId::of::<T>() == TypeId::of::<crate::ImmutableString>()
|
|
|
|
{
|
|
|
|
panic!("Cannot register indexer for strings.");
|
|
|
|
}
|
|
|
|
if TypeId::of::<T>() == TypeId::of::<crate::INT>() {
|
|
|
|
panic!("Cannot register indexer for integers.");
|
|
|
|
}
|
|
|
|
|
|
|
|
self.register_fn(crate::engine::FN_IDX_GET, get_fn)
|
|
|
|
}
|
|
|
|
/// Register an index setter for a custom type with the [`Engine`].
|
|
|
|
///
|
|
|
|
/// Not available under both `no_index` and `no_object`.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
2021-12-06 20:52:47 +08:00
|
|
|
/// Panics if the type is [`Array`][crate::Array], [`Map`][crate::Map], [`String`],
|
2021-11-20 14:57:21 +08:00
|
|
|
/// [`ImmutableString`][crate::ImmutableString], `&str` or [`INT`][crate::INT].
|
|
|
|
/// Indexers for arrays, object maps, strings and integers cannot be registered.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// #[derive(Clone)]
|
|
|
|
/// struct TestStruct {
|
|
|
|
/// fields: Vec<i64>
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl TestStruct {
|
2021-12-27 21:56:50 +08:00
|
|
|
/// fn new() -> Self {
|
|
|
|
/// Self { fields: vec![1, 2, 3, 4, 5] }
|
|
|
|
/// }
|
|
|
|
/// fn set_field(&mut self, index: i64, value: i64) {
|
|
|
|
/// self.fields[index as usize] = value;
|
|
|
|
/// }
|
2021-11-20 14:57:21 +08:00
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
|
|
|
/// // Register API for the custom type.
|
|
|
|
/// # #[cfg(not(feature = "no_object"))]
|
|
|
|
/// engine.register_type::<TestStruct>();
|
|
|
|
///
|
|
|
|
/// engine
|
|
|
|
/// .register_fn("new_ts", TestStruct::new)
|
|
|
|
/// // Register an indexer.
|
|
|
|
/// .register_indexer_set(TestStruct::set_field);
|
|
|
|
///
|
|
|
|
/// # #[cfg(not(feature = "no_index"))]
|
2021-12-27 21:56:50 +08:00
|
|
|
/// let result = engine.eval::<TestStruct>("let a = new_ts(); a[2] = 42; a")?;
|
|
|
|
///
|
|
|
|
/// # #[cfg(not(feature = "no_index"))]
|
|
|
|
/// assert_eq!(result.fields[2], 42);
|
2021-11-20 14:57:21 +08:00
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
|
|
|
#[inline]
|
2022-08-21 22:59:49 +08:00
|
|
|
pub fn register_indexer_set<T: Variant + Clone, X: Variant + Clone, V: Variant + Clone, S>(
|
2021-11-20 14:57:21 +08:00
|
|
|
&mut self,
|
2022-08-21 22:59:49 +08:00
|
|
|
set_fn: impl RegisterNativeFunction<(Mut<T>, X, V), (), S> + SendSync + 'static,
|
2021-11-20 14:57:21 +08:00
|
|
|
) -> &mut Self {
|
|
|
|
#[cfg(not(feature = "no_index"))]
|
2021-12-06 20:52:47 +08:00
|
|
|
if TypeId::of::<T>() == TypeId::of::<crate::Array>() {
|
2021-11-20 14:57:21 +08:00
|
|
|
panic!("Cannot register indexer for arrays.");
|
|
|
|
}
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
2021-12-06 20:52:47 +08:00
|
|
|
if TypeId::of::<T>() == TypeId::of::<crate::Map>() {
|
2021-11-20 14:57:21 +08:00
|
|
|
panic!("Cannot register indexer for object maps.");
|
|
|
|
}
|
|
|
|
if TypeId::of::<T>() == TypeId::of::<String>()
|
|
|
|
|| TypeId::of::<T>() == TypeId::of::<&str>()
|
|
|
|
|| TypeId::of::<T>() == TypeId::of::<crate::ImmutableString>()
|
|
|
|
{
|
|
|
|
panic!("Cannot register indexer for strings.");
|
|
|
|
}
|
|
|
|
if TypeId::of::<T>() == TypeId::of::<crate::INT>() {
|
|
|
|
panic!("Cannot register indexer for integers.");
|
|
|
|
}
|
|
|
|
|
|
|
|
self.register_fn(crate::engine::FN_IDX_SET, set_fn)
|
|
|
|
}
|
|
|
|
/// Short-hand for registering both index getter and setter functions for a custom type with the [`Engine`].
|
|
|
|
///
|
|
|
|
/// Not available under both `no_index` and `no_object`.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
2021-12-06 20:52:47 +08:00
|
|
|
/// Panics if the type is [`Array`][crate::Array], [`Map`][crate::Map], [`String`],
|
2021-11-20 14:57:21 +08:00
|
|
|
/// [`ImmutableString`][crate::ImmutableString], `&str` or [`INT`][crate::INT].
|
|
|
|
/// Indexers for arrays, object maps, strings and integers cannot be registered.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// #[derive(Clone)]
|
|
|
|
/// struct TestStruct {
|
|
|
|
/// fields: Vec<i64>
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl TestStruct {
|
2021-12-27 21:56:50 +08:00
|
|
|
/// fn new() -> Self {
|
|
|
|
/// Self { fields: vec![1, 2, 3, 4, 5] }
|
|
|
|
/// }
|
2021-11-20 14:57:21 +08:00
|
|
|
/// // Even a getter must start with `&mut self` and not `&self`.
|
2021-12-27 21:56:50 +08:00
|
|
|
/// fn get_field(&mut self, index: i64) -> i64 {
|
|
|
|
/// self.fields[index as usize]
|
|
|
|
/// }
|
|
|
|
/// fn set_field(&mut self, index: i64, value: i64) {
|
|
|
|
/// self.fields[index as usize] = value;
|
|
|
|
/// }
|
2021-11-20 14:57:21 +08:00
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
|
|
/// use rhai::Engine;
|
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
|
|
|
/// // Register API for the custom type.
|
|
|
|
/// # #[cfg(not(feature = "no_object"))]
|
|
|
|
/// engine.register_type::<TestStruct>();
|
|
|
|
///
|
|
|
|
/// engine
|
|
|
|
/// .register_fn("new_ts", TestStruct::new)
|
|
|
|
/// // Register an indexer.
|
|
|
|
/// .register_indexer_get_set(TestStruct::get_field, TestStruct::set_field);
|
|
|
|
///
|
|
|
|
/// # #[cfg(not(feature = "no_index"))]
|
|
|
|
/// assert_eq!(engine.eval::<i64>("let a = new_ts(); a[2] = 42; a[2]")?, 42);
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
|
|
|
#[inline(always)]
|
2022-08-21 22:59:49 +08:00
|
|
|
pub fn register_indexer_get_set<
|
|
|
|
T: Variant + Clone,
|
|
|
|
X: Variant + Clone,
|
|
|
|
V: Variant + Clone,
|
2022-08-22 00:15:00 +08:00
|
|
|
S1,
|
|
|
|
S2,
|
2022-08-21 22:59:49 +08:00
|
|
|
>(
|
2021-11-20 14:57:21 +08:00
|
|
|
&mut self,
|
2022-08-22 00:15:00 +08:00
|
|
|
get_fn: impl RegisterNativeFunction<(Mut<T>, X), V, S1> + SendSync + 'static,
|
|
|
|
set_fn: impl RegisterNativeFunction<(Mut<T>, X, V), (), S2> + SendSync + 'static,
|
2021-11-20 14:57:21 +08:00
|
|
|
) -> &mut Self {
|
|
|
|
self.register_indexer_get(get_fn)
|
|
|
|
.register_indexer_set(set_fn)
|
|
|
|
}
|
|
|
|
/// Register a shared [`Module`] into the global namespace of [`Engine`].
|
|
|
|
///
|
|
|
|
/// All functions and type iterators are automatically available to scripts without namespace
|
|
|
|
/// qualifications.
|
|
|
|
///
|
|
|
|
/// Sub-modules and variables are **ignored**.
|
|
|
|
///
|
|
|
|
/// When searching for functions, modules loaded later are preferred. In other words, loaded
|
|
|
|
/// modules are searched in reverse order.
|
|
|
|
#[inline(always)]
|
2022-11-08 15:01:40 +08:00
|
|
|
pub fn register_global_module(&mut self, module: SharedModule) -> &mut Self {
|
2021-11-20 14:57:21 +08:00
|
|
|
// Insert the module into the front.
|
|
|
|
// The first module is always the global namespace.
|
|
|
|
self.global_modules.insert(1, module);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
/// 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.
|
|
|
|
///
|
|
|
|
/// Not available under `no_module`.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
|
|
/// use rhai::{Engine, Shared, Module};
|
|
|
|
///
|
|
|
|
/// let mut engine = Engine::new();
|
|
|
|
///
|
|
|
|
/// // Create the module
|
|
|
|
/// let mut module = Module::new();
|
|
|
|
/// module.set_native_fn("calc", |x: i64| Ok(x + 1));
|
|
|
|
///
|
2022-11-08 16:37:35 +08:00
|
|
|
/// let module: Shared<Module> = module.into();
|
2021-11-20 14:57:21 +08:00
|
|
|
///
|
|
|
|
/// engine
|
|
|
|
/// // Register the module as a fixed sub-module
|
|
|
|
/// .register_static_module("foo::bar::baz", module.clone())
|
|
|
|
/// // Multiple registrations to the same partial path is also OK!
|
|
|
|
/// .register_static_module("foo::bar::hello", module.clone())
|
|
|
|
/// .register_static_module("CalcService", module);
|
|
|
|
///
|
|
|
|
/// assert_eq!(engine.eval::<i64>("foo::bar::baz::calc(41)")?, 42);
|
|
|
|
/// assert_eq!(engine.eval::<i64>("foo::bar::hello::calc(41)")?, 42);
|
|
|
|
/// assert_eq!(engine.eval::<i64>("CalcService::calc(41)")?, 42);
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[cfg(not(feature = "no_module"))]
|
|
|
|
pub fn register_static_module(
|
|
|
|
&mut self,
|
2022-01-04 15:22:48 +08:00
|
|
|
name: impl AsRef<str>,
|
2022-11-08 15:01:40 +08:00
|
|
|
module: SharedModule,
|
2021-11-20 14:57:21 +08:00
|
|
|
) -> &mut Self {
|
|
|
|
fn register_static_module_raw(
|
2022-11-08 15:01:40 +08:00
|
|
|
root: &mut std::collections::BTreeMap<Identifier, SharedModule>,
|
2022-01-04 15:22:48 +08:00
|
|
|
name: &str,
|
2022-11-08 15:01:40 +08:00
|
|
|
module: SharedModule,
|
2021-11-20 14:57:21 +08:00
|
|
|
) {
|
2022-11-22 23:30:43 +08:00
|
|
|
let separator = crate::tokenizer::Token::DoubleColon.literal_syntax();
|
2021-11-20 14:57:21 +08:00
|
|
|
|
2022-07-27 18:04:59 +08:00
|
|
|
if name.contains(separator) {
|
2022-07-05 16:26:38 +08:00
|
|
|
let mut iter = name.splitn(2, separator);
|
2021-11-20 14:57:21 +08:00
|
|
|
let sub_module = iter.next().expect("contains separator").trim();
|
|
|
|
let remainder = iter.next().expect("contains separator").trim();
|
|
|
|
|
2022-03-03 13:02:57 +08:00
|
|
|
if root.is_empty() || !root.contains_key(sub_module) {
|
2021-11-20 14:57:21 +08:00
|
|
|
let mut m = Module::new();
|
2022-09-15 08:55:07 +08:00
|
|
|
register_static_module_raw(m.get_sub_modules_mut(), remainder, module);
|
2021-11-20 14:57:21 +08:00
|
|
|
m.build_index();
|
|
|
|
root.insert(sub_module.into(), m.into());
|
|
|
|
} else {
|
|
|
|
let m = root.remove(sub_module).expect("contains sub-module");
|
2022-06-26 14:10:09 +08:00
|
|
|
let mut m = crate::func::shared_take_or_clone(m);
|
2022-09-15 08:55:07 +08:00
|
|
|
register_static_module_raw(m.get_sub_modules_mut(), remainder, module);
|
2021-11-20 14:57:21 +08:00
|
|
|
m.build_index();
|
|
|
|
root.insert(sub_module.into(), m.into());
|
|
|
|
}
|
2022-07-27 18:04:59 +08:00
|
|
|
} else if module.is_indexed() {
|
|
|
|
root.insert(name.into(), module);
|
|
|
|
} else {
|
|
|
|
// Index the module (making a clone copy if necessary) if it is not indexed
|
|
|
|
let mut module = crate::func::shared_take_or_clone(module);
|
|
|
|
module.build_index();
|
|
|
|
root.insert(name.into(), module.into());
|
2021-11-20 14:57:21 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-04 15:22:48 +08:00
|
|
|
register_static_module_raw(&mut self.global_sub_modules, name.as_ref(), module);
|
2021-11-20 14:57:21 +08:00
|
|
|
self
|
|
|
|
}
|
|
|
|
/// _(metadata)_ Generate a list of all registered functions.
|
|
|
|
/// Exported under the `metadata` feature only.
|
|
|
|
///
|
|
|
|
/// Functions from the following sources are included, in order:
|
|
|
|
/// 1) Functions registered into the global namespace
|
|
|
|
/// 2) Functions in registered sub-modules
|
2022-01-17 23:15:22 +08:00
|
|
|
/// 3) Functions in registered packages
|
|
|
|
/// 4) Functions in standard packages (optional)
|
2021-11-20 14:57:21 +08:00
|
|
|
#[cfg(feature = "metadata")]
|
|
|
|
#[inline]
|
|
|
|
#[must_use]
|
|
|
|
pub fn gen_fn_signatures(&self, include_packages: bool) -> Vec<String> {
|
|
|
|
let mut signatures = Vec::with_capacity(64);
|
|
|
|
|
|
|
|
signatures.extend(self.global_namespace().gen_fn_signatures());
|
|
|
|
|
2022-01-29 11:09:43 +08:00
|
|
|
#[cfg(not(feature = "no_module"))]
|
2022-01-28 18:59:18 +08:00
|
|
|
for (name, m) in &self.global_sub_modules {
|
2022-08-11 19:01:23 +08:00
|
|
|
signatures.extend(m.gen_fn_signatures().map(|f| format!("{name}::{f}")));
|
2022-01-28 18:59:18 +08:00
|
|
|
}
|
2021-11-20 14:57:21 +08:00
|
|
|
|
2022-01-17 23:15:22 +08:00
|
|
|
signatures.extend(
|
|
|
|
self.global_modules
|
|
|
|
.iter()
|
|
|
|
.skip(1)
|
|
|
|
.filter(|m| !m.internal && (include_packages || !m.standard))
|
|
|
|
.flat_map(|m| m.gen_fn_signatures()),
|
|
|
|
);
|
2021-11-20 14:57:21 +08:00
|
|
|
|
|
|
|
signatures
|
|
|
|
}
|
|
|
|
}
|