Rename AnonymousFn to Func
This commit is contained in:
parent
518725e119
commit
34ef2d6e00
33
README.md
33
README.md
@ -261,25 +261,25 @@ let result: i64 = engine.call_fn(&mut scope, &ast, "hello", () )?
|
|||||||
|
|
||||||
### Creating Rust anonymous functions from Rhai script
|
### Creating Rust anonymous functions from Rhai script
|
||||||
|
|
||||||
[`AnonymousFn`]: #creating-rust-anonymous-functions-from-rhai-script
|
[`Func`]: #creating-rust-anonymous-functions-from-rhai-script
|
||||||
|
|
||||||
It is possible to further encapsulate a script in Rust such that it essentially becomes a normal Rust function.
|
It is possible to further encapsulate a script in Rust such that it essentially becomes a normal Rust function.
|
||||||
This is accomplished via the `AnonymousFn` trait which contains `create_from_script` (as well as its associate
|
This is accomplished via the `Func` trait which contains `create_from_script` (as well as its associate
|
||||||
method `create_from_ast`):
|
method `create_from_ast`):
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use rhai::{Engine, AnonymousFn}; // use 'AnonymousFn' for 'create_from_script'
|
use rhai::{Engine, Func}; // use 'Func' for 'create_from_script'
|
||||||
|
|
||||||
let engine = Engine::new(); // create a new 'Engine' just for this
|
let engine = Engine::new(); // create a new 'Engine' just for this
|
||||||
|
|
||||||
let script = "fn calc(x, y) { x + y.len() < 42 }";
|
let script = "fn calc(x, y) { x + y.len() < 42 }";
|
||||||
|
|
||||||
// AnonymousFn takes two type parameters:
|
// Func takes two type parameters:
|
||||||
// 1) a tuple made up of the types of the script function's parameters
|
// 1) a tuple made up of the types of the script function's parameters
|
||||||
// 2) the return type of the script function
|
// 2) the return type of the script function
|
||||||
//
|
//
|
||||||
// 'func' will have type Box<dyn Fn(i64, String) -> Result<bool, EvalAltResult>> and is callable!
|
// 'func' will have type Box<dyn Fn(i64, String) -> Result<bool, EvalAltResult>> and is callable!
|
||||||
let func = AnonymousFn::<(i64, String), bool>::create_from_script(
|
let func = Func::<(i64, String), bool>::create_from_script(
|
||||||
// ^^^^^^^^^^^^^ function parameter types in tuple
|
// ^^^^^^^^^^^^^ function parameter types in tuple
|
||||||
|
|
||||||
engine, // the 'Engine' is consumed into the closure
|
engine, // the 'Engine' is consumed into the closure
|
||||||
@ -336,6 +336,7 @@ Values and types
|
|||||||
|
|
||||||
[`type_of()`]: #values-and-types
|
[`type_of()`]: #values-and-types
|
||||||
[`to_string()`]: #values-and-types
|
[`to_string()`]: #values-and-types
|
||||||
|
[`()`]: #values-and-types
|
||||||
|
|
||||||
The following primitive types are supported natively:
|
The following primitive types are supported natively:
|
||||||
|
|
||||||
@ -353,8 +354,6 @@ The following primitive types are supported natively:
|
|||||||
| **System floating-point** (current configuration, disabled with [`no_float`]) | `rhai::FLOAT` (`f32` or `f64`) | `"f32"` or `"f64"` | `"123.456"` etc. |
|
| **System floating-point** (current configuration, disabled with [`no_float`]) | `rhai::FLOAT` (`f32` or `f64`) | `"f32"` or `"f64"` | `"123.456"` etc. |
|
||||||
| **Nothing/void/nil/null** (or whatever you want to call it) | `()` | `"()"` | `""` _(empty string)_ |
|
| **Nothing/void/nil/null** (or whatever you want to call it) | `()` | `"()"` | `""` _(empty string)_ |
|
||||||
|
|
||||||
[`()`]: #values-and-types
|
|
||||||
|
|
||||||
All types are treated strictly separate by Rhai, meaning that `i32` and `i64` and `u32` are completely different -
|
All types are treated strictly separate by Rhai, meaning that `i32` and `i64` and `u32` are completely different -
|
||||||
they even cannot be added together. This is very similar to Rust.
|
they even cannot be added together. This is very similar to Rust.
|
||||||
|
|
||||||
@ -479,6 +478,20 @@ let c = 'X'; // character
|
|||||||
print("c is '" + c + "' and its code is " + c.to_int()); // prints "c is 'X' and its code is 88"
|
print("c is '" + c + "' and its code is " + c.to_int()); // prints "c is 'X' and its code is 88"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Traits
|
||||||
|
------
|
||||||
|
|
||||||
|
A number of traits, under the `rhai::` module namespace, provide additional functionalities.
|
||||||
|
|
||||||
|
| Trait | Description | Methods |
|
||||||
|
| ------------------- | --------------------------------------------------------------------------------- | --------------------------------------- |
|
||||||
|
| `Any` | Generic trait that represents a [`Dynamic`] type | `type_id`, `type_name`, `into_dynamic` |
|
||||||
|
| `AnyExt` | Extension trait to allows casting of a [`Dynamic`] value to Rust types | `cast`, `try_cast` |
|
||||||
|
| `RegisterFn` | Trait for registering functions | `register_fn` |
|
||||||
|
| `RegisterDynamicFn` | Trait for registering functions returning [`Dynamic`] | `register_dynamic_fn` |
|
||||||
|
| `RegisterResultFn` | Trait for registering fallible functions returning `Result<`_T_`, EvalAltResult>` | `register_result_fn` |
|
||||||
|
| `Func` | Trait for creating anonymous functions from script | `create_from_ast`, `create_from_script` |
|
||||||
|
|
||||||
Working with functions
|
Working with functions
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
@ -1245,7 +1258,7 @@ Property values can be accessed via the dot notation (_object_ `.` _property_) o
|
|||||||
The dot notation allows only property names that follow the same naming rules as [variables].
|
The dot notation allows only property names that follow the same naming rules as [variables].
|
||||||
The index notation allows setting/getting properties of arbitrary names (even the empty string).
|
The index notation allows setting/getting properties of arbitrary names (even the empty string).
|
||||||
|
|
||||||
**Important:** Trying to read a non-existent property returns `()` instead of causing an error.
|
**Important:** Trying to read a non-existent property returns [`()`] instead of causing an error.
|
||||||
|
|
||||||
The Rust type of a Rhai object map is `rhai::Map`. [`type_of()`] an object map returns `"map"`.
|
The Rust type of a Rhai object map is `rhai::Map`. [`type_of()`] an object map returns `"map"`.
|
||||||
|
|
||||||
@ -1620,6 +1633,10 @@ fn do_addition(x) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Unlike C/C++, functions can be defined _anywhere_ within the global level. A function does not need to be defined
|
||||||
|
prior to being used in a script; a statement in the script can freely call a function defined afterwards.
|
||||||
|
This is similar to Rust and many other modern languages.
|
||||||
|
|
||||||
### Functions overloading
|
### Functions overloading
|
||||||
|
|
||||||
Functions can be _overloaded_ and are resolved purely upon the function's _name_ and the _number_ of parameters
|
Functions can be _overloaded_ and are resolved purely upon the function's _name_ and the _number_ of parameters
|
||||||
|
@ -9,8 +9,10 @@ use crate::parser::AST;
|
|||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
|
|
||||||
|
use crate::stdlib::{boxed::Box, string::ToString};
|
||||||
|
|
||||||
/// A trait to create a Rust anonymous function from a script.
|
/// A trait to create a Rust anonymous function from a script.
|
||||||
pub trait AnonymousFn<ARGS, RET> {
|
pub trait Func<ARGS, RET> {
|
||||||
type Output;
|
type Output;
|
||||||
|
|
||||||
/// Create a Rust anonymous function from an `AST`.
|
/// Create a Rust anonymous function from an `AST`.
|
||||||
@ -20,18 +22,18 @@ pub trait AnonymousFn<ARGS, RET> {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
||||||
/// use rhai::{Engine, AnonymousFn}; // use 'AnonymousFn' for 'create_from_ast'
|
/// use rhai::{Engine, Func}; // use 'Func' for 'create_from_ast'
|
||||||
///
|
///
|
||||||
/// let engine = Engine::new(); // create a new 'Engine' just for this
|
/// let engine = Engine::new(); // create a new 'Engine' just for this
|
||||||
///
|
///
|
||||||
/// let ast = engine.compile("fn calc(x, y) { x + y.len() < 42 }")?;
|
/// let ast = engine.compile("fn calc(x, y) { x + y.len() < 42 }")?;
|
||||||
///
|
///
|
||||||
/// // AnonymousFn takes two type parameters:
|
/// // Func takes two type parameters:
|
||||||
/// // 1) a tuple made up of the types of the script function's parameters
|
/// // 1) a tuple made up of the types of the script function's parameters
|
||||||
/// // 2) the return type of the script function
|
/// // 2) the return type of the script function
|
||||||
/// //
|
/// //
|
||||||
/// // 'func' will have type Box<dyn Fn(i64, String) -> Result<bool, EvalAltResult>> and is callable!
|
/// // 'func' will have type Box<dyn Fn(i64, String) -> Result<bool, EvalAltResult>> and is callable!
|
||||||
/// let func = AnonymousFn::<(i64, String), bool>::create_from_ast(
|
/// let func = Func::<(i64, String), bool>::create_from_ast(
|
||||||
/// // ^^^^^^^^^^^^^ function parameter types in tuple
|
/// // ^^^^^^^^^^^^^ function parameter types in tuple
|
||||||
///
|
///
|
||||||
/// engine, // the 'Engine' is consumed into the closure
|
/// engine, // the 'Engine' is consumed into the closure
|
||||||
@ -51,18 +53,18 @@ pub trait AnonymousFn<ARGS, RET> {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
||||||
/// use rhai::{Engine, AnonymousFn}; // use 'AnonymousFn' for 'create_from_script'
|
/// use rhai::{Engine, Func}; // use 'Func' for 'create_from_script'
|
||||||
///
|
///
|
||||||
/// let engine = Engine::new(); // create a new 'Engine' just for this
|
/// let engine = Engine::new(); // create a new 'Engine' just for this
|
||||||
///
|
///
|
||||||
/// let script = "fn calc(x, y) { x + y.len() < 42 }";
|
/// let script = "fn calc(x, y) { x + y.len() < 42 }";
|
||||||
///
|
///
|
||||||
/// // AnonymousFn takes two type parameters:
|
/// // Func takes two type parameters:
|
||||||
/// // 1) a tuple made up of the types of the script function's parameters
|
/// // 1) a tuple made up of the types of the script function's parameters
|
||||||
/// // 2) the return type of the script function
|
/// // 2) the return type of the script function
|
||||||
/// //
|
/// //
|
||||||
/// // 'func' will have type Box<dyn Fn(i64, String) -> Result<bool, EvalAltResult>> and is callable!
|
/// // 'func' will have type Box<dyn Fn(i64, String) -> Result<bool, EvalAltResult>> and is callable!
|
||||||
/// let func = AnonymousFn::<(i64, String), bool>::create_from_script(
|
/// let func = Func::<(i64, String), bool>::create_from_script(
|
||||||
/// // ^^^^^^^^^^^^^ function parameter types in tuple
|
/// // ^^^^^^^^^^^^^ function parameter types in tuple
|
||||||
///
|
///
|
||||||
/// engine, // the 'Engine' is consumed into the closure
|
/// engine, // the 'Engine' is consumed into the closure
|
||||||
@ -86,7 +88,7 @@ macro_rules! def_anonymous_fn {
|
|||||||
def_anonymous_fn!(imp);
|
def_anonymous_fn!(imp);
|
||||||
};
|
};
|
||||||
(imp $($par:ident),*) => {
|
(imp $($par:ident),*) => {
|
||||||
impl<'e, $($par: Any + Clone,)* RET: Any + Clone> AnonymousFn<($($par,)*), RET> for Engine<'e>
|
impl<'e, $($par: Any + Clone,)* RET: Any + Clone> Func<($($par,)*), RET> for Engine<'e>
|
||||||
{
|
{
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
type Output = Box<dyn Fn($($par),*) -> Result<RET, EvalAltResult> + Send + Sync + 'e>;
|
type Output = Box<dyn Fn($($par),*) -> Result<RET, EvalAltResult> + Send + Sync + 'e>;
|
||||||
@ -98,13 +100,13 @@ macro_rules! def_anonymous_fn {
|
|||||||
let name = entry_point.to_string();
|
let name = entry_point.to_string();
|
||||||
|
|
||||||
Box::new(move |$($par: $par),*| {
|
Box::new(move |$($par: $par),*| {
|
||||||
self.call_fn::<_, RET>(&mut Scope::new(), &ast, &name, ($($par,)*))
|
self.call_fn(&mut Scope::new(), &ast, &name, ($($par,)*))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_from_script(self, script: &str, entry_point: &str) -> Result<Self::Output, ParseError> {
|
fn create_from_script(self, script: &str, entry_point: &str) -> Result<Self::Output, ParseError> {
|
||||||
let ast = self.compile(script)?;
|
let ast = self.compile(script)?;
|
||||||
Ok(AnonymousFn::<($($par,)*), RET>::create_from_ast(self, ast, entry_point))
|
Ok(Func::<($($par,)*), RET>::create_from_ast(self, ast, entry_point))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
22
src/lib.rs
22
src/lib.rs
@ -3,15 +3,19 @@
|
|||||||
//! Rhai is a tiny, simple and very fast embedded scripting language for Rust
|
//! Rhai is a tiny, simple and very fast embedded scripting language for Rust
|
||||||
//! that gives you a safe and easy way to add scripting to your applications.
|
//! that gives you a safe and easy way to add scripting to your applications.
|
||||||
//! It provides a familiar syntax based on JS and Rust and a simple Rust interface.
|
//! It provides a familiar syntax based on JS and Rust and a simple Rust interface.
|
||||||
//! Here is a quick example. First, the contents of `my_script.rhai`:
|
//! Here is a quick example.
|
||||||
|
//!
|
||||||
|
//! First, the contents of `my_script.rhai`:
|
||||||
//!
|
//!
|
||||||
//! ```,ignore
|
//! ```,ignore
|
||||||
|
//! // Brute force factorial function
|
||||||
//! fn factorial(x) {
|
//! fn factorial(x) {
|
||||||
//! if x == 1 { return 1; }
|
//! if x == 1 { return 1; }
|
||||||
//! x * factorial(x - 1)
|
//! x * factorial(x - 1)
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! compute_something(factorial(10))
|
//! // Calling an external function 'compute'
|
||||||
|
//! compute(factorial(10))
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! And the Rust part:
|
//! And the Rust part:
|
||||||
@ -21,16 +25,22 @@
|
|||||||
//!
|
//!
|
||||||
//! fn main() -> Result<(), EvalAltResult>
|
//! fn main() -> Result<(), EvalAltResult>
|
||||||
//! {
|
//! {
|
||||||
|
//! // Define external function
|
||||||
//! fn compute_something(x: i64) -> bool {
|
//! fn compute_something(x: i64) -> bool {
|
||||||
//! (x % 40) == 0
|
//! (x % 40) == 0
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
|
//! // Create scripting engine
|
||||||
//! let mut engine = Engine::new();
|
//! let mut engine = Engine::new();
|
||||||
//!
|
//!
|
||||||
//! engine.register_fn("compute_something", compute_something);
|
//! // Register external function as 'compute'
|
||||||
|
//! engine.register_fn("compute", compute_something);
|
||||||
//!
|
//!
|
||||||
//! # #[cfg(not(feature = "no_std"))]
|
//! # #[cfg(not(feature = "no_std"))]
|
||||||
//! assert_eq!(engine.eval_file::<bool>("my_script.rhai".into())?, true);
|
//! assert_eq!(
|
||||||
|
//! engine.eval_file::<bool>("my_script.rhai".into())?,
|
||||||
|
//! true
|
||||||
|
//! );
|
||||||
//!
|
//!
|
||||||
//! Ok(())
|
//! Ok(())
|
||||||
//! }
|
//! }
|
||||||
@ -63,8 +73,8 @@ mod api;
|
|||||||
mod builtin;
|
mod builtin;
|
||||||
mod engine;
|
mod engine;
|
||||||
mod error;
|
mod error;
|
||||||
mod fn_anonymous;
|
|
||||||
mod fn_call;
|
mod fn_call;
|
||||||
|
mod fn_func;
|
||||||
mod fn_register;
|
mod fn_register;
|
||||||
mod optimize;
|
mod optimize;
|
||||||
mod parser;
|
mod parser;
|
||||||
@ -82,7 +92,7 @@ pub use result::EvalAltResult;
|
|||||||
pub use scope::Scope;
|
pub use scope::Scope;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub use fn_anonymous::AnonymousFn;
|
pub use fn_func::Func;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
pub use engine::Array;
|
pub use engine::Array;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#![cfg(not(feature = "no_function"))]
|
#![cfg(not(feature = "no_function"))]
|
||||||
use rhai::{AnonymousFn, Engine, EvalAltResult, ParseErrorType, Scope, INT};
|
use rhai::{Engine, EvalAltResult, Func, ParseErrorType, Scope, INT};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fn() -> Result<(), EvalAltResult> {
|
fn test_fn() -> Result<(), EvalAltResult> {
|
||||||
@ -62,7 +62,10 @@ fn test_call_fn() -> Result<(), EvalAltResult> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_anonymous_fn() -> Result<(), EvalAltResult> {
|
fn test_anonymous_fn() -> Result<(), EvalAltResult> {
|
||||||
let calc_func = AnonymousFn::<(INT, INT, INT), INT>::create_from_script(
|
let calc_func: Box<dyn Fn(INT, INT, INT) -> Result<INT, EvalAltResult>> =
|
||||||
|
Engine::new().create_from_script("fn calc() { 42 }", "calc")?;
|
||||||
|
|
||||||
|
let calc_func = Func::<(INT, INT, INT), INT>::create_from_script(
|
||||||
Engine::new(),
|
Engine::new(),
|
||||||
"fn calc(x, y, z) { (x + y) * z }",
|
"fn calc(x, y, z) { (x + y) * z }",
|
||||||
"calc",
|
"calc",
|
||||||
|
Loading…
Reference in New Issue
Block a user