diff --git a/README.md b/README.md index 2b70b36d..7ad9c478 100644 --- a/README.md +++ b/README.md @@ -359,16 +359,14 @@ let result: i64 = engine.call_fn(&mut scope, &ast, "hello", () )?; 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` (such as a simple `Vec`): ```rust 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 [`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 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, @@ -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 functions be registered (assuming the custom type is `T : Display + Debug`): -| Function | Signature | Typical implementation | Usage | -| ----------- | ------------------------------------------------ | ------------------------------ | --------------------------------------------------------------------------------------- | -| `to_string` | `|s: &mut T| -> String` | `s.to_string()` | 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 | -| `debug` | `|s: &mut T| -> String` | `format!("{:?}", s)` | 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 | -| `+` | `|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 | -| `+=` | `|s1: &mut ImmutableString, s: T|` | `s1 += s.to_string()` | Append the custom type to an existing [string], for `s += type;` usage | +| Function | Signature | Typical implementation | Usage | +| ----------- | ------------------------------------------------ | ------------------------------------- | --------------------------------------------------------------------------------------- | +| `to_string` | `|s: &mut T| -> ImmutableString` | `s.to_string().into()` | Converts the custom type into a [string] | +| `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| -> 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 | +| `+` | `|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 | `Scope` - Initializing and maintaining state ------------------------------------------- diff --git a/RELEASES.md b/RELEASES.md index 0b3136c1..6667774c 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -14,6 +14,7 @@ Breaking changes * `Engine::register_indexer` is renamed to `Engine::register_indexer_get`. * `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`. +* `Engine::call_fn_dynamic` now takes any type that implements `IntoIterator`. New features ------------ diff --git a/src/api.rs b/src/api.rs index df92f891..8e2af013 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1114,7 +1114,7 @@ impl Engine { args: A, ) -> Result> { 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()); @@ -1128,13 +1128,6 @@ impl Engine { /// 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 /// /// ``` @@ -1155,13 +1148,13 @@ impl Engine { /// scope.push("foo", 42_i64); /// /// // 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::(), 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::(), 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::(), 21); /// # } /// # Ok(()) @@ -1169,6 +1162,25 @@ impl Engine { /// ``` #[cfg(not(feature = "no_function"))] pub fn call_fn_dynamic( + &self, + scope: &mut Scope, + ast: &AST, + name: &str, + arg_values: impl IntoIterator, + ) -> Result> { + 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, scope: &mut Scope, ast: &AST, diff --git a/src/utils.rs b/src/utils.rs index bedf73b2..77cef0e7 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -216,6 +216,15 @@ impl FromIterator for StaticVec { } } +impl IntoIterator for StaticVec { + type Item = T; + type IntoIter = Box>; + + fn into_iter(self) -> Self::IntoIter { + self.into_iter() + } +} + impl StaticVec { /// Create a new `StaticVec`. #[inline(always)]