Change call_fn_dynamic to accept any type that is IntoIterator<Item=Dynamic>.

This commit is contained in:
Stephen Chung 2020-06-12 19:54:55 +08:00
parent 5275778952
commit b24fdd7a4d
4 changed files with 45 additions and 25 deletions

View File

@ -359,16 +359,14 @@ let result: i64 = engine.call_fn(&mut scope, &ast, "hello", () )?;
let result: () = engine.call_fn(&mut scope, &ast, "hidden", ())?; let result: () = engine.call_fn(&mut scope, &ast, "hidden", ())?;
``` ```
For more control, construct all arguments as `Dynamic` values and use `Engine::call_fn_dynamic`: For more control, construct all arguments as `Dynamic` values and use `Engine::call_fn_dynamic`, passing it
anything that implements `IntoIterator<Item = Dynamic>` (such as a simple `Vec<Dynamic>`):
```rust ```rust
let result: Dynamic = engine.call_fn_dynamic(&mut scope, &ast, "hello", let result: Dynamic = engine.call_fn_dynamic(&mut scope, &ast, "hello",
&mut [ String::from("abc").into(), 123_i64.into() ])?; vec![ String::from("abc").into(), 123_i64.into() ])?;
``` ```
However, beware that `Engine::call_fn_dynamic` _consumes_ its arguments, meaning that all arguments passed to it
will be replaced by `()` afterwards. To re-use the arguments, clone them beforehand and pass in the clone.
### Creating Rust anonymous functions from Rhai script ### Creating Rust anonymous functions from Rhai script
[`Func`]: #creating-rust-anonymous-functions-from-rhai-script [`Func`]: #creating-rust-anonymous-functions-from-rhai-script
@ -738,7 +736,7 @@ use rhai::Dynamic;
let x = (42_i64).into(); // 'into()' works for standard types let x = (42_i64).into(); // 'into()' works for standard types
let y = Dynamic::from(String::from("hello!")); // remember &str is not supported by Rhai let y = Dynamic::from("hello!".to_string()); // remember &str is not supported by Rhai
``` ```
Functions registered with the [`Engine`] can be _overloaded_ as long as the _signature_ is unique, Functions registered with the [`Engine`] can be _overloaded_ as long as the _signature_ is unique,
@ -1124,14 +1122,14 @@ not available under [`no_index`].
To use custom types for `print` and `debug`, or convert its value into a [string], it is necessary that the following To use custom types for `print` and `debug`, or convert its value into a [string], it is necessary that the following
functions be registered (assuming the custom type is `T : Display + Debug`): functions be registered (assuming the custom type is `T : Display + Debug`):
| Function | Signature | Typical implementation | Usage | | Function | Signature | Typical implementation | Usage |
| ----------- | ------------------------------------------------ | ------------------------------ | --------------------------------------------------------------------------------------- | | ----------- | ------------------------------------------------ | ------------------------------------- | --------------------------------------------------------------------------------------- |
| `to_string` | `|s: &mut T| -> String` | `s.to_string()` | Converts the custom type into a [string] | | `to_string` | `|s: &mut T| -> ImmutableString` | `s.to_string().into()` | Converts the custom type into a [string] |
| `print` | `|s: &mut T| -> String` | `s.to_string()` | Converts the custom type into a [string] for the [`print`](#print-and-debug) statement | | `print` | `|s: &mut T| -> ImmutableString` | `s.to_string().into()` | Converts the custom type into a [string] for the [`print`](#print-and-debug) statement |
| `debug` | `|s: &mut T| -> String` | `format!("{:?}", s)` | Converts the custom type into a [string] for the [`debug`](#print-and-debug) statement | | `debug` | `|s: &mut T| -> ImmutableString` | `format!("{:?}", s).into()` | Converts the custom type into a [string] for the [`debug`](#print-and-debug) statement |
| `+` | `|s1: ImmutableString, s: T| -> ImmutableString` | `s1 + s` | Append the custom type to another [string], for `print("Answer: " + type);` usage | | `+` | `|s1: ImmutableString, s: T| -> ImmutableString` | `s1 + s` | Append the custom type to another [string], for `print("Answer: " + type);` usage |
| `+` | `|s: T, s2: ImmutableString| -> String` | `s.to_string().push_str(&s2);` | Append another [string] to the custom type, for `print(type + " is the answer");` usage | | `+` | `|s: T, s2: ImmutableString| -> ImmutableString` | `s.to_string().push_str(&s2).into();` | Append another [string] to the custom type, for `print(type + " is the answer");` usage |
| `+=` | `|s1: &mut ImmutableString, s: T|` | `s1 += s.to_string()` | Append the custom type to an existing [string], for `s += type;` usage | | `+=` | `|s1: &mut ImmutableString, s: T|` | `s1 += s.to_string()` | Append the custom type to an existing [string], for `s += type;` usage |
`Scope` - Initializing and maintaining state `Scope` - Initializing and maintaining state
------------------------------------------- -------------------------------------------

View File

@ -14,6 +14,7 @@ Breaking changes
* `Engine::register_indexer` is renamed to `Engine::register_indexer_get`. * `Engine::register_indexer` is renamed to `Engine::register_indexer_get`.
* `Module::set_indexer_fn` is renamed to `Module::set_indexer_get_fn`. * `Module::set_indexer_fn` is renamed to `Module::set_indexer_get_fn`.
* The tuple `ParseError` now exposes the internal fields and the `ParseError::error_type` and `ParseError::position` methods are removed. The first tuple field is the `ParseErrorType` and the second tuple field is the `Position`. * The tuple `ParseError` now exposes the internal fields and the `ParseError::error_type` and `ParseError::position` methods are removed. The first tuple field is the `ParseErrorType` and the second tuple field is the `Position`.
* `Engine::call_fn_dynamic` now takes any type that implements `IntoIterator<Item = Dynamic>`.
New features New features
------------ ------------

View File

@ -1114,7 +1114,7 @@ impl Engine {
args: A, args: A,
) -> Result<T, Box<EvalAltResult>> { ) -> Result<T, Box<EvalAltResult>> {
let mut arg_values = args.into_vec(); let mut arg_values = args.into_vec();
let result = self.call_fn_dynamic(scope, ast, name, arg_values.as_mut())?; let result = self.call_fn_dynamic_raw(scope, ast, name, arg_values.as_mut())?;
let return_type = self.map_type_name(result.type_name()); let return_type = self.map_type_name(result.type_name());
@ -1128,13 +1128,6 @@ impl Engine {
/// Call a script function defined in an `AST` with multiple `Dynamic` arguments. /// Call a script function defined in an `AST` with multiple `Dynamic` arguments.
/// ///
/// ## WARNING
///
/// All the arguments are _consumed_, meaning that they're replaced by `()`.
/// This is to avoid unnecessarily cloning the arguments.
/// Do you use the arguments after this call. If you need them afterwards,
/// clone them _before_ calling this function.
///
/// # Example /// # Example
/// ///
/// ``` /// ```
@ -1155,13 +1148,13 @@ impl Engine {
/// scope.push("foo", 42_i64); /// scope.push("foo", 42_i64);
/// ///
/// // Call the script-defined function /// // Call the script-defined function
/// let result = engine.call_fn_dynamic(&mut scope, &ast, "add", &mut [ String::from("abc").into(), 123_i64.into() ])?; /// let result = engine.call_fn_dynamic(&mut scope, &ast, "add", vec![ String::from("abc").into(), 123_i64.into() ])?;
/// assert_eq!(result.cast::<i64>(), 168); /// assert_eq!(result.cast::<i64>(), 168);
/// ///
/// let result = engine.call_fn_dynamic(&mut scope, &ast, "add1", &mut [ String::from("abc").into() ])?; /// let result = engine.call_fn_dynamic(&mut scope, &ast, "add1", vec![ String::from("abc").into() ])?;
/// assert_eq!(result.cast::<i64>(), 46); /// assert_eq!(result.cast::<i64>(), 46);
/// ///
/// let result= engine.call_fn_dynamic(&mut scope, &ast, "bar", &mut [])?; /// let result= engine.call_fn_dynamic(&mut scope, &ast, "bar", vec![])?;
/// assert_eq!(result.cast::<i64>(), 21); /// assert_eq!(result.cast::<i64>(), 21);
/// # } /// # }
/// # Ok(()) /// # Ok(())
@ -1169,6 +1162,25 @@ impl Engine {
/// ``` /// ```
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
pub fn call_fn_dynamic( pub fn call_fn_dynamic(
&self,
scope: &mut Scope,
ast: &AST,
name: &str,
arg_values: impl IntoIterator<Item = Dynamic>,
) -> Result<Dynamic, Box<EvalAltResult>> {
let mut arg_values: StaticVec<_> = arg_values.into_iter().collect();
self.call_fn_dynamic_raw(scope, ast, name, arg_values.as_mut())
}
/// Call a script function defined in an `AST` with multiple `Dynamic` arguments.
///
/// ## WARNING
///
/// 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.
pub(crate) fn call_fn_dynamic_raw(
&self, &self,
scope: &mut Scope, scope: &mut Scope,
ast: &AST, ast: &AST,

View File

@ -216,6 +216,15 @@ impl<T> FromIterator<T> for StaticVec<T> {
} }
} }
impl<T: 'static> IntoIterator for StaticVec<T> {
type Item = T;
type IntoIter = Box<dyn Iterator<Item = T>>;
fn into_iter(self) -> Self::IntoIter {
self.into_iter()
}
}
impl<T> StaticVec<T> { impl<T> StaticVec<T> {
/// Create a new `StaticVec`. /// Create a new `StaticVec`.
#[inline(always)] #[inline(always)]