Merge pull request #624 from schungx/master

Deprecate _result registration methods.
This commit is contained in:
Stephen Chung 2022-08-22 23:01:43 +08:00 committed by GitHub
commit 56b732d83b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 307 additions and 504 deletions

View File

@ -10,11 +10,15 @@ Bug fixes
* API for registering property getters/setters and indexers to an `Engine` now works with functions that take a first parameter of `NativeCallContext`.
* Missing API function `Module::set_getter_setter_fn` is added.
Deprecated API
--------------
* All versions of the `Engine::register_XXX_result` API that register a function returning `Result<T, Box<EvalAltResult>>` are now deprecated. The regular, non-`result` versions handle all functions correctly.
New features
------------
Fallible type iterators
-----------------------
### Fallible type iterators
* For very special needs, the ability to register fallible type iterators is added.

View File

@ -303,7 +303,7 @@ pub fn register_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenS
Ok((engine_expr, export_name, rust_mod_path)) => {
let gen_mod_path = crate::register::generated_module_path(&rust_mod_path);
proc_macro::TokenStream::from(quote! {
#engine_expr.register_result_fn(#export_name, #gen_mod_path::dynamic_result_fn)
#engine_expr.register_fn(#export_name, #gen_mod_path::dynamic_result_fn)
})
}
Err(e) => e.to_compile_error().into(),

View File

@ -1,11 +1,14 @@
//! Trait to build a custom type for use with [`Engine`].
#![allow(deprecated)]
use crate::{types::dynamic::Variant, Engine, Identifier, RegisterNativeFunction, RhaiResultOf};
use crate::{types::dynamic::Variant, Engine, Identifier, RegisterNativeFunction};
use std::marker::PhantomData;
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
use crate::func::register::Mut;
/// Trait to build the API of a custom type for use with an [`Engine`]
/// (i.e. register the type and its getters, setters, methods, etc.).
///
@ -133,17 +136,6 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
self.engine.register_fn(name, method);
self
}
/// Register a custom fallible function.
#[inline(always)]
pub fn with_result_fn<N, A, F, R, S>(&mut self, name: N, method: F) -> &mut Self
where
N: AsRef<str> + Into<Identifier>,
F: RegisterNativeFunction<A, R, RhaiResultOf<S>>,
{
self.engine.register_result_fn(name, method);
self
}
}
impl<'a, T> TypeBuilder<'a, T>
@ -168,67 +160,39 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
///
/// Not available under `no_object`.
#[inline(always)]
pub fn with_get<V: Variant + Clone>(
pub fn with_get<V: Variant + Clone, S>(
&mut self,
name: impl AsRef<str>,
get_fn: impl Fn(&mut T) -> V + crate::func::SendSync + 'static,
get_fn: impl RegisterNativeFunction<(Mut<T>,), V, S> + crate::func::SendSync + 'static,
) -> &mut Self {
self.engine.register_get(name, get_fn);
self
}
/// Register a fallible getter function.
///
/// The function signature must start with `&mut self` and not `&self`.
///
/// Not available under `no_object`.
#[inline(always)]
pub fn with_get_result<V: Variant + Clone>(
&mut self,
name: impl AsRef<str>,
get_fn: impl Fn(&mut T) -> RhaiResultOf<V> + crate::func::SendSync + 'static,
) -> &mut Self {
self.engine.register_get_result(name, get_fn);
self
}
/// Register a setter function.
///
/// Not available under `no_object`.
#[inline(always)]
pub fn with_set<V: Variant + Clone>(
pub fn with_set<V: Variant + Clone, S>(
&mut self,
name: impl AsRef<str>,
set_fn: impl Fn(&mut T, V) + crate::func::SendSync + 'static,
set_fn: impl RegisterNativeFunction<(Mut<T>, V), (), S> + crate::func::SendSync + 'static,
) -> &mut Self {
self.engine.register_set(name, set_fn);
self
}
/// Register a fallible setter function.
///
/// Not available under `no_object`.
#[inline(always)]
pub fn with_set_result<V: Variant + Clone>(
&mut self,
name: impl AsRef<str>,
set_fn: impl Fn(&mut T, V) -> RhaiResultOf<()> + crate::func::SendSync + 'static,
) -> &mut Self {
self.engine.register_set_result(name, set_fn);
self
}
/// Short-hand for registering both getter and setter functions.
///
/// All function signatures must start with `&mut self` and not `&self`.
///
/// Not available under `no_object`.
#[inline(always)]
pub fn with_get_set<V: Variant + Clone>(
pub fn with_get_set<V: Variant + Clone, S1, S2>(
&mut self,
name: impl AsRef<str>,
get_fn: impl Fn(&mut T) -> V + crate::func::SendSync + 'static,
set_fn: impl Fn(&mut T, V) + crate::func::SendSync + 'static,
get_fn: impl RegisterNativeFunction<(Mut<T>,), V, S1> + crate::func::SendSync + 'static,
set_fn: impl RegisterNativeFunction<(Mut<T>, V), (), S2> + crate::func::SendSync + 'static,
) -> &mut Self {
self.engine.register_get_set(name, get_fn, set_fn);
self
@ -243,60 +207,34 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
///
/// Not available under both `no_index` and `no_object`.
#[inline(always)]
pub fn with_indexer_get<X: Variant + Clone, V: Variant + Clone>(
pub fn with_indexer_get<X: Variant + Clone, V: Variant + Clone, S>(
&mut self,
get_fn: impl Fn(&mut T, X) -> V + crate::func::SendSync + 'static,
get_fn: impl RegisterNativeFunction<(Mut<T>, X), V, S> + crate::func::SendSync + 'static,
) -> &mut Self {
self.engine.register_indexer_get(get_fn);
self
}
/// Register an fallible index getter.
///
/// The function signature must start with `&mut self` and not `&self`.
///
/// Not available under both `no_index` and `no_object`.
#[inline(always)]
pub fn with_indexer_get_result<X: Variant + Clone, V: Variant + Clone>(
&mut self,
get_fn: impl Fn(&mut T, X) -> RhaiResultOf<V> + crate::func::SendSync + 'static,
) -> &mut Self {
self.engine.register_indexer_get_result(get_fn);
self
}
/// Register an index setter.
///
/// Not available under both `no_index` and `no_object`.
#[inline(always)]
pub fn with_indexer_set<X: Variant + Clone, V: Variant + Clone>(
pub fn with_indexer_set<X: Variant + Clone, V: Variant + Clone, S>(
&mut self,
set_fn: impl Fn(&mut T, X, V) + crate::func::SendSync + 'static,
set_fn: impl RegisterNativeFunction<(Mut<T>, X, V), (), S> + crate::func::SendSync + 'static,
) -> &mut Self {
self.engine.register_indexer_set(set_fn);
self
}
/// Register an fallible index setter.
///
/// Not available under both `no_index` and `no_object`.
#[inline(always)]
pub fn with_indexer_set_result<X: Variant + Clone, V: Variant + Clone>(
&mut self,
set_fn: impl Fn(&mut T, X, V) -> RhaiResultOf<()> + crate::func::SendSync + 'static,
) -> &mut Self {
self.engine.register_indexer_set_result(set_fn);
self
}
/// Short-hand for registering both index getter and setter functions.
///
/// Not available under both `no_index` and `no_object`.
#[inline(always)]
pub fn with_indexer_get_set<X: Variant + Clone, V: Variant + Clone>(
pub fn with_indexer_get_set<X: Variant + Clone, V: Variant + Clone, S1, S2>(
&mut self,
get_fn: impl Fn(&mut T, X) -> V + crate::func::SendSync + 'static,
set_fn: impl Fn(&mut T, X, V) + crate::func::SendSync + 'static,
get_fn: impl RegisterNativeFunction<(Mut<T>, X), V, S1> + crate::func::SendSync + 'static,
set_fn: impl RegisterNativeFunction<(Mut<T>, X, V), (), S2> + crate::func::SendSync + 'static,
) -> &mut Self {
self.engine.register_indexer_get_set(get_fn, set_fn);
self

View File

@ -1,12 +1,17 @@
//! Module containing all deprecated API that will be removed in the next major version.
use crate::func::RegisterNativeFunction;
use crate::types::dynamic::Variant;
use crate::{
Dynamic, Engine, EvalAltResult, FnPtr, ImmutableString, NativeCallContext, Position,
RhaiResult, RhaiResultOf, Scope, AST,
Dynamic, Engine, EvalAltResult, FnPtr, Identifier, ImmutableString, NativeCallContext,
Position, RhaiResult, RhaiResultOf, Scope, AST,
};
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
use crate::func::register::Mut;
#[cfg(not(feature = "no_std"))]
#[cfg(not(target_family = "wasm"))]
use std::path::PathBuf;
@ -115,58 +120,6 @@ impl Engine {
/// This method is deprecated. Use [`run_ast_with_scope`][Engine::run_ast_with_scope] instead.
///
/// This method will be removed in the next major version.
///
/// # WARNING - Low Level API
///
/// This function is very low level.
///
/// # Arguments
///
/// All the arguments are _consumed_, meaning that they're replaced by `()`.
/// This is to avoid unnecessarily cloning the arguments.
///
/// Do not use the arguments after this call. If they are needed afterwards,
/// clone them _before_ calling this function.
///
/// # Example
///
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// # #[cfg(not(feature = "no_function"))]
/// # {
/// use rhai::{Engine, Scope, Dynamic};
///
/// let engine = Engine::new();
///
/// let ast = engine.compile("
/// fn add(x, y) { len(x) + y + foo }
/// fn add1(x) { len(x) + 1 + foo }
/// fn bar() { foo/2 }
/// fn action(x) { this += x; } // function using 'this' pointer
/// ")?;
///
/// let mut scope = Scope::new();
/// scope.push("foo", 42_i64);
///
/// // Call the script-defined function
/// let result = engine.call_fn_dynamic(&mut scope, &ast, true, "add", None, [ "abc".into(), 123_i64.into() ])?;
/// // ^^^^ no 'this' pointer
/// assert_eq!(result.cast::<i64>(), 168);
///
/// let result = engine.call_fn_dynamic(&mut scope, &ast, true, "add1", None, [ "abc".into() ])?;
/// assert_eq!(result.cast::<i64>(), 46);
///
/// let result = engine.call_fn_dynamic(&mut scope, &ast, true, "bar", None, [])?;
/// assert_eq!(result.cast::<i64>(), 21);
///
/// let mut value: Dynamic = 1_i64.into();
/// let result = engine.call_fn_dynamic(&mut scope, &ast, true, "action", Some(&mut value), [ 41_i64.into() ])?;
/// // ^^^^^^^^^^^^^^^^ binding the 'this' pointer
/// assert_eq!(value.as_int().expect("value should be INT"), 42);
/// # }
/// # Ok(())
/// # }
/// ```
#[deprecated(since = "1.1.0", note = "use `call_fn_raw` instead")]
#[cfg(not(feature = "no_function"))]
#[inline(always)]
@ -181,6 +134,130 @@ impl Engine {
) -> RhaiResult {
self.call_fn_raw(scope, ast, eval_ast, true, name, this_ptr, arg_values)
}
/// Register a custom fallible function with the [`Engine`].
///
/// # Deprecated
///
/// This method is deprecated. Use [`register_fn`][Engine::register_fn] instead.
///
/// This method will be removed in the next major version.
#[deprecated(since = "1.9.1", note = "use `register_fn` instead")]
#[inline(always)]
pub fn register_result_fn<N, A, F, R, S>(&mut self, name: N, func: F) -> &mut Self
where
N: AsRef<str> + Into<Identifier>,
F: RegisterNativeFunction<A, R, RhaiResultOf<S>>,
{
self.register_fn(name, func)
}
/// 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`.
///
/// # Deprecated
///
/// This method is deprecated. Use [`register_get`][Engine::register_get] instead.
///
/// This method will be removed in the next major version.
#[deprecated(since = "1.9.1", note = "use `register_get` instead")]
#[cfg(not(feature = "no_object"))]
#[inline(always)]
pub fn register_get_result<T: Variant + Clone, V: Variant + Clone, S>(
&mut self,
name: impl AsRef<str>,
get_fn: impl RegisterNativeFunction<(Mut<T>,), V, RhaiResultOf<S>>
+ crate::func::SendSync
+ 'static,
) -> &mut Self {
self.register_get(name, get_fn)
}
/// Register a setter function for a member of a registered type with the [`Engine`].
///
/// Not available under `no_object`.
///
/// # Deprecated
///
/// This method is deprecated. Use [`register_set`][Engine::register_set] instead.
///
/// This method will be removed in the next major version.
#[deprecated(since = "1.9.1", note = "use `register_set` instead")]
#[cfg(not(feature = "no_object"))]
#[inline(always)]
pub fn register_set_result<T: Variant + Clone, V: Variant + Clone, S>(
&mut self,
name: impl AsRef<str>,
set_fn: impl RegisterNativeFunction<(Mut<T>, V), (), RhaiResultOf<S>>
+ crate::func::SendSync
+ 'static,
) -> &mut Self {
self.register_set(name, set_fn)
}
/// 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`.
///
/// # Deprecated
///
/// This method is deprecated. Use [`register_indexer_get`][Engine::register_indexer_get] instead.
///
/// This method will be removed in the next major version.
///
/// # Panics
///
/// Panics if the type is [`Array`][crate::Array], [`Map`][crate::Map], [`String`],
/// [`ImmutableString`][crate::ImmutableString], `&str` or [`INT`][crate::INT].
/// Indexers for arrays, object maps, strings and integers cannot be registered.
#[deprecated(since = "1.9.1", note = "use `register_indexer_get` instead")]
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[inline(always)]
pub fn register_indexer_get_result<
T: Variant + Clone,
X: Variant + Clone,
V: Variant + Clone,
S,
>(
&mut self,
get_fn: impl RegisterNativeFunction<(Mut<T>, X), V, RhaiResultOf<S>>
+ crate::func::SendSync
+ 'static,
) -> &mut Self {
self.register_indexer_get(get_fn)
}
/// Register an index setter for a custom type with the [`Engine`].
///
/// Not available under both `no_index` and `no_object`.
///
/// # Deprecated
///
/// This method is deprecated. Use [`register_indexer_set`][Engine::register_indexer_set] instead.
///
/// This method will be removed in the next major version.
///
/// # Panics
///
/// Panics if the type is [`Array`][crate::Array], [`Map`][crate::Map], [`String`],
/// [`ImmutableString`][crate::ImmutableString], `&str` or [`INT`][crate::INT].
/// Indexers for arrays, object maps, strings and integers cannot be registered.
#[deprecated(since = "1.9.1", note = "use `register_indexer_set` instead")]
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[inline(always)]
pub fn register_indexer_set_result<
T: Variant + Clone,
X: Variant + Clone,
V: Variant + Clone,
S,
>(
&mut self,
set_fn: impl RegisterNativeFunction<(Mut<T>, X, V), (), RhaiResultOf<S>>
+ crate::func::SendSync
+ 'static,
) -> &mut Self {
self.register_indexer_set(set_fn)
}
}
impl Dynamic {
@ -217,21 +294,6 @@ impl Dynamic {
impl NativeCallContext<'_> {
/// Call a function inside the call context.
///
/// # WARNING - Low Level API
///
/// This function is very low level.
///
/// # Arguments
///
/// All arguments may be _consumed_, meaning that they may be replaced by `()`. This is to avoid
/// unnecessarily cloning the arguments.
///
/// Do not use the arguments after this call. If they are needed afterwards, clone them _before_
/// calling this function.
///
/// If `is_method` is [`true`], the first argument is assumed to be passed by reference and is
/// not consumed.
///
/// # Deprecated
///
/// This method is deprecated. Use [`call_fn_raw`][NativeCallContext::call_fn_raw] instead.
@ -285,18 +347,6 @@ impl FnPtr {
/// [`call_raw`][FnPtr::call_raw] instead.
///
/// This method will be removed in the next major version.
///
/// # WARNING - Low Level API
///
/// This function is very low level.
///
/// # Arguments
///
/// All the arguments are _consumed_, meaning that they're replaced by `()`.
/// This is to avoid unnecessarily cloning the arguments.
///
/// Do not use the arguments after this call. If they are needed afterwards,
/// clone them _before_ calling this function.
#[deprecated(
since = "1.3.0",
note = "use `call_within_context` or `call_raw` instead"
@ -352,3 +402,113 @@ impl Position {
}
}
}
#[allow(deprecated)]
impl<'a, T: Variant + Clone> crate::TypeBuilder<'a, T> {
/// Register a custom fallible function.
///
/// # Deprecated
///
/// This method is deprecated. Use `with_fn` instead.
///
/// This method will be removed in the next major version.
#[deprecated(since = "1.9.1", note = "use `with_fn` instead")]
#[inline(always)]
pub fn with_result_fn<N, A, F, R, S>(&mut self, name: N, method: F) -> &mut Self
where
N: AsRef<str> + Into<Identifier>,
F: RegisterNativeFunction<A, R, RhaiResultOf<S>>,
{
self.with_fn(name, method)
}
/// Register a fallible getter function.
///
/// The function signature must start with `&mut self` and not `&self`.
///
/// Not available under `no_object`.
///
/// # Deprecated
///
/// This method is deprecated. Use `with_get` instead.
///
/// This method will be removed in the next major version.
#[deprecated(since = "1.9.1", note = "use `with_get` instead")]
#[cfg(not(feature = "no_object"))]
#[inline(always)]
pub fn with_get_result<V: Variant + Clone, S>(
&mut self,
name: impl AsRef<str>,
get_fn: impl RegisterNativeFunction<(Mut<T>,), V, RhaiResultOf<S>>
+ crate::func::SendSync
+ 'static,
) -> &mut Self {
self.with_get(name, get_fn)
}
/// Register a fallible setter function.
///
/// Not available under `no_object`.
///
/// # Deprecated
///
/// This method is deprecated. Use `with_set` instead.
///
/// This method will be removed in the next major version.
#[deprecated(since = "1.9.1", note = "use `with_set` instead")]
#[cfg(not(feature = "no_object"))]
#[inline(always)]
pub fn with_set_result<V: Variant + Clone, S>(
&mut self,
name: impl AsRef<str>,
set_fn: impl RegisterNativeFunction<(Mut<T>, V), (), RhaiResultOf<S>>
+ crate::func::SendSync
+ 'static,
) -> &mut Self {
self.with_set(name, set_fn)
}
/// Register an fallible index getter.
///
/// The function signature must start with `&mut self` and not `&self`.
///
/// Not available under both `no_index` and `no_object`.
///
/// # Deprecated
///
/// This method is deprecated. Use `with_indexer_get` instead.
///
/// This method will be removed in the next major version.
#[deprecated(since = "1.9.1", note = "use `with_indexer_get` instead")]
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[inline(always)]
pub fn with_indexer_get_result<X: Variant + Clone, V: Variant + Clone, S>(
&mut self,
get_fn: impl RegisterNativeFunction<(Mut<T>, X), V, RhaiResultOf<S>>
+ crate::func::SendSync
+ 'static,
) -> &mut Self {
self.with_indexer_get(get_fn)
}
/// Register an fallible index setter.
///
/// Not available under both `no_index` and `no_object`.
///
/// # Deprecated
///
/// This method is deprecated. Use `with_indexer_set` instead.
///
/// This method will be removed in the next major version.
#[deprecated(since = "1.9.1", note = "use `with_indexer_set` instead")]
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[inline(always)]
pub fn with_indexer_set_result<X: Variant + Clone, V: Variant + Clone, S>(
&mut self,
set_fn: impl RegisterNativeFunction<(Mut<T>, X, V), (), RhaiResultOf<S>>
+ crate::func::SendSync
+ 'static,
) -> &mut Self {
self.with_indexer_set(set_fn)
}
}

View File

@ -1,6 +1,5 @@
//! Module that defines the public function/module registration API of [`Engine`].
use crate::func::register::Mut;
use crate::func::{FnCallArgs, RegisterNativeFunction, SendSync};
use crate::types::dynamic::Variant;
use crate::{
@ -10,6 +9,9 @@ use std::any::{type_name, TypeId};
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
use crate::func::register::Mut;
impl Engine {
/// Get the global namespace module (which is the fist module in `global_modules`).
#[inline(always)]
@ -88,64 +90,6 @@ impl Engine {
);
self
}
/// Register a custom fallible function with the [`Engine`].
///
/// # Example
///
/// ```
/// use rhai::{Engine, EvalAltResult};
///
/// // Normal function
/// fn div(x: i64, y: i64) -> Result<i64, Box<EvalAltResult>> {
/// if y == 0 {
/// // '.into()' automatically converts to 'Box<EvalAltResult::ErrorRuntime>'
/// Err("division by zero!".into())
/// } else {
/// Ok(x / y)
/// }
/// }
///
/// let mut engine = Engine::new();
///
/// engine.register_result_fn("div", div);
///
/// engine.eval::<i64>("div(42, 0)")
/// .expect_err("expecting division by zero error!");
/// ```
#[inline]
pub fn register_result_fn<N, A, F, R, S>(&mut self, name: N, func: F) -> &mut Self
where
N: AsRef<str> + Into<Identifier>,
F: RegisterNativeFunction<A, R, RhaiResultOf<S>>,
{
let param_types = F::param_types();
#[cfg(feature = "metadata")]
let param_type_names: crate::StaticVec<_> = F::param_names()
.iter()
.map(|ty| format!("_: {}", self.format_type_name(ty)))
.chain(Some(self.format_type_name(F::return_type_name()).into()))
.collect();
#[cfg(feature = "metadata")]
let param_type_names: crate::StaticVec<_> =
param_type_names.iter().map(String::as_str).collect();
#[cfg(feature = "metadata")]
let param_type_names = Some(param_type_names.as_ref());
#[cfg(not(feature = "metadata"))]
let param_type_names: Option<&[&str]> = None;
self.global_namespace_mut().set_fn(
name,
FnNamespace::Global,
FnAccess::Public,
param_type_names,
param_types,
func.into_callable_function(),
);
self
}
/// Register a function of the [`Engine`].
///
/// # WARNING - Low Level API
@ -363,55 +307,6 @@ impl Engine {
) -> &mut Self {
self.register_fn(crate::engine::make_getter(name.as_ref()).as_str(), get_fn)
}
/// 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
///
/// ```
/// use rhai::{Engine, Dynamic, EvalAltResult};
///
/// #[derive(Clone)]
/// struct TestStruct {
/// field: i64
/// }
///
/// impl TestStruct {
/// fn new() -> Self {
/// Self { field: 1 }
/// }
/// // Even a getter must start with `&mut self` and not `&self`.
/// fn get_field(&mut self) -> Result<i64, Box<EvalAltResult>> {
/// Ok(self.field)
/// }
/// }
///
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// 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_result("xyz", TestStruct::get_field);
///
/// assert_eq!(engine.eval::<i64>("let a = new_ts(); a.xyz")?, 1);
/// # Ok(())
/// # }
/// ```
#[cfg(not(feature = "no_object"))]
#[inline(always)]
pub fn register_get_result<T: Variant + Clone, V: Variant + Clone, S>(
&mut self,
name: impl AsRef<str>,
get_fn: impl RegisterNativeFunction<(Mut<T>,), V, RhaiResultOf<S>> + SendSync + 'static,
) -> &mut Self {
self.register_result_fn(crate::engine::make_getter(name.as_ref()).as_str(), get_fn)
}
/// Register a setter function for a member of a registered type with the [`Engine`].
///
/// Not available under `no_object`.
@ -462,57 +357,6 @@ impl Engine {
) -> &mut Self {
self.register_fn(crate::engine::make_setter(name.as_ref()).as_str(), set_fn)
}
/// Register a setter function for a member of a registered type with the [`Engine`].
///
/// Not available under `no_object`.
///
/// # Example
///
/// ```
/// use rhai::{Engine, Dynamic, EvalAltResult};
///
/// #[derive(Debug, Clone, Eq, PartialEq)]
/// struct TestStruct {
/// field: i64
/// }
///
/// impl TestStruct {
/// fn new() -> Self {
/// Self { field: 1 }
/// }
/// fn set_field(&mut self, new_val: i64) -> Result<(), Box<rhai::EvalAltResult>> {
/// self.field = new_val;
/// Ok(())
/// }
/// }
///
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// 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_result("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)]
pub fn register_set_result<T: Variant + Clone, V: Variant + Clone, S>(
&mut self,
name: impl AsRef<str>,
set_fn: impl RegisterNativeFunction<(Mut<T>, V), (), RhaiResultOf<S>> + SendSync + 'static,
) -> &mut Self {
self.register_result_fn(crate::engine::make_setter(name.as_ref()).as_str(), set_fn)
}
/// Short-hand for registering both getter and setter functions
/// of a registered type with the [`Engine`].
///
@ -643,86 +487,6 @@ impl Engine {
self.register_fn(crate::engine::FN_IDX_GET, get_fn)
}
/// 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
///
/// Panics if the type is [`Array`][crate::Array], [`Map`][crate::Map], [`String`],
/// [`ImmutableString`][crate::ImmutableString], `&str` or [`INT`][crate::INT].
/// Indexers for arrays, object maps, strings and integers cannot be registered.
///
/// # Example
///
/// ```
/// use rhai::{Engine, Dynamic, EvalAltResult};
///
/// #[derive(Clone)]
/// struct TestStruct {
/// fields: Vec<i64>
/// }
///
/// impl TestStruct {
/// fn new() -> Self {
/// Self { fields: vec![1, 2, 3, 4, 5] }
/// }
/// // Even a getter must start with `&mut self` and not `&self`.
/// fn get_field(&mut self, index: i64) -> Result<i64, Box<EvalAltResult>> {
/// Ok(self.fields[index as usize])
/// }
/// }
///
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// 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_result(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]
pub fn register_indexer_get_result<
T: Variant + Clone,
X: Variant + Clone,
V: Variant + Clone,
S,
>(
&mut self,
get_fn: impl RegisterNativeFunction<(Mut<T>, X), V, RhaiResultOf<S>> + SendSync + 'static,
) -> &mut Self {
#[cfg(not(feature = "no_index"))]
if TypeId::of::<T>() == TypeId::of::<crate::Array>() {
panic!("Cannot register indexer for arrays.");
}
#[cfg(not(feature = "no_object"))]
if TypeId::of::<T>() == TypeId::of::<crate::Map>() {
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_result_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`.
@ -798,87 +562,6 @@ impl Engine {
self.register_fn(crate::engine::FN_IDX_SET, set_fn)
}
/// Register an index setter for a custom type with the [`Engine`].
///
/// Not available under both `no_index` and `no_object`.
///
/// # Panics
///
/// Panics if the type is [`Array`][crate::Array], [`Map`][crate::Map], [`String`],
/// [`ImmutableString`][crate::ImmutableString], `&str` or [`INT`][crate::INT].
/// Indexers for arrays, object maps, strings and integers cannot be registered.
///
/// # Example
///
/// ```
/// use rhai::{Engine, Dynamic, EvalAltResult};
///
/// #[derive(Clone)]
/// struct TestStruct {
/// fields: Vec<i64>
/// }
///
/// impl TestStruct {
/// fn new() -> Self {
/// Self { fields: vec![1, 2, 3, 4, 5] }
/// }
/// fn set_field(&mut self, index: i64, value: i64) -> Result<(), Box<rhai::EvalAltResult>> {
/// self.fields[index as usize] = value;
/// Ok(())
/// }
/// }
///
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// 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_result(TestStruct::set_field);
///
/// # #[cfg(not(feature = "no_index"))]
/// let result = engine.eval::<TestStruct>("let a = new_ts(); a[2] = 42; a")?;
///
/// # #[cfg(not(feature = "no_index"))]
/// assert_eq!(result.fields[2], 42);
/// # Ok(())
/// # }
/// ```
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[inline]
pub fn register_indexer_set_result<
T: Variant + Clone,
X: Variant + Clone,
V: Variant + Clone,
S,
>(
&mut self,
set_fn: impl RegisterNativeFunction<(Mut<T>, X, V), (), RhaiResultOf<S>> + SendSync + 'static,
) -> &mut Self {
#[cfg(not(feature = "no_index"))]
if TypeId::of::<T>() == TypeId::of::<crate::Array>() {
panic!("Cannot register indexer for arrays.");
}
#[cfg(not(feature = "no_object"))]
if TypeId::of::<T>() == TypeId::of::<crate::Map>() {
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_result_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`.

View File

@ -1,7 +1,6 @@
//! Module defining external-loaded modules for Rhai.
use crate::ast::FnAccess;
use crate::func::register::Mut;
use crate::func::{
shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, RegisterNativeFunction,
SendSync,
@ -21,6 +20,9 @@ use std::{
ops::{Add, AddAssign},
};
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
use crate::func::register::Mut;
/// A type representing the namespace of a function.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(feature = "metadata", derive(serde::Serialize))]
@ -586,10 +588,10 @@ impl Module {
///
/// assert_eq!(module.get_custom_type(name), Some("MyType"));
/// ```
#[inline(always)]
#[inline]
#[must_use]
pub fn get_custom_type(&self, key: &str) -> Option<&str> {
self.custom_types.get(key)
self.custom_types.get(key).map(|t| t.display_name.as_str())
}
/// Returns `true` if this [`Module`] contains no items.

View File

@ -3,14 +3,18 @@
use crate::Identifier;
use std::{any::type_name, collections::BTreeMap, fmt};
/// _(internals)_ A custom type.
/// _(internals)_ Information for a custom type.
/// Exported under the `internals` feature only.
pub type CustomType = Identifier;
#[derive(Debug, Eq, PartialEq, Clone, Hash, Default)]
pub struct CustomTypeInfo {
/// Friendly display name of the custom type.
pub display_name: Identifier,
}
/// _(internals)_ A collection of custom types.
/// Exported under the `internals` feature only.
#[derive(Clone, Hash, Default)]
pub struct CustomTypesCollection(BTreeMap<Identifier, CustomType>);
pub struct CustomTypesCollection(BTreeMap<Identifier, CustomTypeInfo>);
impl fmt::Debug for CustomTypesCollection {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@ -33,21 +37,31 @@ impl CustomTypesCollection {
/// Register a custom type.
#[inline(always)]
pub fn add(&mut self, type_name: impl Into<Identifier>, name: impl Into<Identifier>) {
self.add_raw(type_name, name.into());
self.add_raw(
type_name,
CustomTypeInfo {
display_name: name.into(),
},
);
}
/// Register a custom type.
#[inline(always)]
pub fn add_type<T>(&mut self, name: &str) {
self.add_raw(type_name::<T>(), name.into());
self.add_raw(
type_name::<T>(),
CustomTypeInfo {
display_name: name.into(),
},
);
}
/// Register a custom type.
#[inline(always)]
pub fn add_raw(&mut self, type_name: impl Into<Identifier>, custom_type: CustomType) {
pub fn add_raw(&mut self, type_name: impl Into<Identifier>, custom_type: CustomTypeInfo) {
self.0.insert(type_name.into(), custom_type);
}
/// Find a custom type.
#[inline(always)]
pub fn get(&self, key: &str) -> Option<&str> {
self.0.get(key).map(CustomType::as_str)
pub fn get(&self, key: &str) -> Option<&CustomTypeInfo> {
self.0.get(key)
}
}

View File

@ -9,7 +9,7 @@ pub mod interner;
pub mod parse_error;
pub mod scope;
pub use custom_types::{CustomType, CustomTypesCollection};
pub use custom_types::{CustomTypeInfo, CustomTypesCollection};
pub use dynamic::Dynamic;
#[cfg(not(feature = "no_std"))]
pub use dynamic::Instant;

View File

@ -66,7 +66,7 @@ fn build_type() -> Result<(), Box<EvalAltResult>> {
.with_get_set("z", Self::get_z, Self::set_z);
#[cfg(not(feature = "no_index"))]
builder.with_indexer_get_result(Self::get_component);
builder.with_indexer_get(Self::get_component);
}
}

View File

@ -97,7 +97,7 @@ fn test_functions_global_module() -> Result<(), Box<EvalAltResult>> {
if matches!(&*err, EvalAltResult::ErrorVariableNotFound(v, ..) if v == "global::ANSWER")
));
engine.register_result_fn(
engine.register_fn(
"do_stuff",
|context: NativeCallContext, callback: rhai::FnPtr| -> Result<INT, _> {
callback.call_within_context(&context, ())

View File

@ -315,11 +315,13 @@ fn test_get_set_indexer() -> Result<(), Box<EvalAltResult>> {
engine
.register_type_with_name::<MyMap>("MyMap")
.register_fn("new_map", || MyMap::new())
.register_indexer_get_result(|map: &mut MyMap, index: &str| {
.register_indexer_get(
|map: &mut MyMap, index: &str| -> Result<_, Box<EvalAltResult>> {
map.get(index).cloned().ok_or_else(|| {
EvalAltResult::ErrorIndexNotFound(index.into(), rhai::Position::NONE).into()
})
})
},
)
.register_indexer_set(|map: &mut MyMap, index: &str, value: INT| {
map.insert(index.to_string(), value);
});

View File

@ -598,7 +598,7 @@ fn test_module_dynamic() -> Result<(), Box<EvalAltResult>> {
let mut static_modules = rhai::module_resolvers::StaticModuleResolver::new();
static_modules.insert("test", module);
engine.set_module_resolver(static_modules);
engine.register_result_fn("test2", test_fn);
engine.register_fn("test2", test_fn);
assert_eq!(engine.eval::<INT>(r#"test2("test", 38);"#)?, 42);