commit
fca908ef58
@ -6,11 +6,11 @@ members = [
|
||||
|
||||
[package]
|
||||
name = "rhai"
|
||||
version = "0.18.3"
|
||||
version = "0.19.0"
|
||||
edition = "2018"
|
||||
authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung", "jhwgh1968"]
|
||||
description = "Embedded scripting for Rust"
|
||||
homepage = "https://github.com/jonathandturner/rhai"
|
||||
homepage = "https://schungx.github.io/rhai"
|
||||
repository = "https://github.com/jonathandturner/rhai"
|
||||
readme = "README.md"
|
||||
license = "MIT OR Apache-2.0"
|
||||
@ -27,7 +27,6 @@ smallvec = { version = "1.4.2", default-features = false }
|
||||
rhai_codegen = { version = "0.1", path = "codegen" }
|
||||
|
||||
[features]
|
||||
#default = ["unchecked", "sync", "no_optimize", "no_float", "only_i32", "no_index", "no_object", "no_function", "no_module"]
|
||||
default = []
|
||||
unchecked = [] # unchecked arithmetic
|
||||
sync = [] # restrict to only types that implement Send + Sync
|
||||
|
@ -4,7 +4,7 @@ version = "0.1.0"
|
||||
edition = "2018"
|
||||
authors = ["jhwgh1968"]
|
||||
description = "Proceducral macro support package for Rhai, a scripting language for Rust"
|
||||
homepage = "https://github.com/jonathandturner/rhai"
|
||||
homepage = "https://schungx.github.io/rhai/plugins/index.html"
|
||||
repository = "https://github.com/jonathandturner/rhai"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
|
@ -580,7 +580,7 @@ impl ExportedFn {
|
||||
);
|
||||
quote! {
|
||||
pub fn #callable_fn_name() -> CallableFunction {
|
||||
CallableFunction::from_plugin(#token_name())
|
||||
#token_name().into()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -628,7 +628,7 @@ impl ExportedFn {
|
||||
arg_type.span()=> &mut args[0usize].write_lock::<#arg_type>().unwrap());
|
||||
unpack_stmts.push(
|
||||
syn::parse2::<syn::Stmt>(quote! {
|
||||
let #var: &mut _ = #downcast_span;
|
||||
let #var = #downcast_span;
|
||||
})
|
||||
.unwrap(),
|
||||
);
|
||||
@ -757,7 +757,7 @@ impl ExportedFn {
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { #is_method_call }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(#type_name()) }
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![#(#input_type_exprs),*].into_boxed_slice()
|
||||
|
@ -1,17 +1,14 @@
|
||||
//! This crate contains procedural macros to make creating Rhai plugin-modules much easier.
|
||||
//!
|
||||
//! This crate contains procedural macros to make creating Rhai modules much easier.
|
||||
//!
|
||||
//! # Exporting a Macro to Rhai
|
||||
//! # Export an Entire Rust Module to a Rhai `Module`
|
||||
//!
|
||||
//! ```
|
||||
//! use rhai::{EvalAltResult, FLOAT};
|
||||
//! use rhai::plugin::*;
|
||||
//! use rhai::module_resolvers::*;
|
||||
//!
|
||||
//! #[rhai::export_module]
|
||||
//! pub mod advanced_math {
|
||||
//! use rhai::FLOAT;
|
||||
//!
|
||||
//! #[export_module]
|
||||
//! mod advanced_math {
|
||||
//! pub const MYSTIC_NUMBER: FLOAT = 42.0 as FLOAT;
|
||||
//!
|
||||
//! pub fn euclidean_distance(x1: FLOAT, y1: FLOAT, x2: FLOAT, y2: FLOAT) -> FLOAT {
|
||||
@ -35,15 +32,15 @@
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! # Exporting a Function to a Rhai Module
|
||||
//! # Register a Rust Function with a Rhai `Module`
|
||||
//!
|
||||
//! ```
|
||||
//! use rhai::{EvalAltResult, FLOAT, Module, RegisterFn};
|
||||
//! use rhai::plugin::*;
|
||||
//! use rhai::module_resolvers::*;
|
||||
//!
|
||||
//! #[rhai::export_fn]
|
||||
//! pub fn distance_function(x1: FLOAT, y1: FLOAT, x2: FLOAT, y2: FLOAT) -> FLOAT {
|
||||
//! #[export_fn]
|
||||
//! fn distance_function(x1: FLOAT, y1: FLOAT, x2: FLOAT, y2: FLOAT) -> FLOAT {
|
||||
//! ((y2 - y1).abs().powf(2.0) + (x2 -x1).abs().powf(2.0)).sqrt()
|
||||
//! }
|
||||
//!
|
||||
@ -66,7 +63,7 @@
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! # Exporting a Function to an Engine
|
||||
//! # Register a Plugin Function with an `Engine`
|
||||
//!
|
||||
//! ```
|
||||
//! use rhai::{EvalAltResult, FLOAT, Module, RegisterFn};
|
||||
@ -105,6 +102,18 @@ mod rhai_module;
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
/// Attribute, when put on a Rust function, turns it into a _plugin function_.
|
||||
///
|
||||
/// # Usage
|
||||
///
|
||||
/// ```,ignore
|
||||
/// use rhai::plugin::*;
|
||||
///
|
||||
/// #[export_fn]
|
||||
/// fn my_plugin_function(...) {
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_attribute]
|
||||
pub fn export_fn(
|
||||
args: proc_macro::TokenStream,
|
||||
@ -125,6 +134,18 @@ pub fn export_fn(
|
||||
proc_macro::TokenStream::from(output)
|
||||
}
|
||||
|
||||
/// Attribute, when put on a Rust module, turns it into a _plugin module_.
|
||||
///
|
||||
/// # Usage
|
||||
///
|
||||
/// ```,ignore
|
||||
/// use rhai::plugin::*;
|
||||
///
|
||||
/// #[export_module]
|
||||
/// mod my_plugin_module {
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_attribute]
|
||||
pub fn export_module(
|
||||
args: proc_macro::TokenStream,
|
||||
@ -143,6 +164,20 @@ pub fn export_module(
|
||||
proc_macro::TokenStream::from(tokens)
|
||||
}
|
||||
|
||||
/// Macro to generate a Rhai `Module` from a _plugin module_.
|
||||
///
|
||||
/// # Usage
|
||||
///
|
||||
/// ```,ignore
|
||||
/// use rhai::plugin::*;
|
||||
///
|
||||
/// #[export_module]
|
||||
/// mod my_plugin_module {
|
||||
/// ...
|
||||
/// }
|
||||
///
|
||||
/// let module = exported_module!(my_plugin_module);
|
||||
/// ```
|
||||
#[proc_macro]
|
||||
pub fn exported_module(module_path: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let module_path = parse_macro_input!(module_path as syn::Path);
|
||||
@ -152,6 +187,34 @@ pub fn exported_module(module_path: proc_macro::TokenStream) -> proc_macro::Toke
|
||||
proc_macro::TokenStream::from(tokens)
|
||||
}
|
||||
|
||||
/// Macro to combine a _plugin module_ into an existing module.
|
||||
///
|
||||
/// Functions and variables in the plugin module overrides any existing similarly-named
|
||||
/// functions and variables in the target module.
|
||||
///
|
||||
/// This call is intended to be used within the `def_package!` macro to define a custom
|
||||
/// package based on a plugin module.
|
||||
///
|
||||
/// All sub-modules, if any, in the plugin module are _flattened_ and their functions/variables
|
||||
/// registered at the top level because packages require so.
|
||||
///
|
||||
/// The text string name in the second parameter can be anything and is reserved for future use;
|
||||
/// it is recommended to be an ID string that uniquely identifies the plugin module.
|
||||
///
|
||||
/// # Usage
|
||||
///
|
||||
/// ```,ignore
|
||||
/// use rhai::plugin::*;
|
||||
///
|
||||
/// #[export_module]
|
||||
/// mod my_plugin_module {
|
||||
/// ...
|
||||
/// }
|
||||
///
|
||||
/// let mut module = Module::new();
|
||||
///
|
||||
/// combine_with_exported_module!(&mut module, "my_plugin_module_ID", my_plugin_module);
|
||||
/// ```
|
||||
#[proc_macro]
|
||||
pub fn combine_with_exported_module(args: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let (module_expr, _export_name, module_path) = match crate::register::parse_register_macro(args)
|
||||
@ -165,6 +228,22 @@ pub fn combine_with_exported_module(args: proc_macro::TokenStream) -> proc_macro
|
||||
proc_macro::TokenStream::from(tokens)
|
||||
}
|
||||
|
||||
/// Macro to register a _plugin function_ into an `Engine`.
|
||||
///
|
||||
/// # Usage
|
||||
///
|
||||
/// ```,ignore
|
||||
/// use rhai::plugin::*;
|
||||
///
|
||||
/// #[export_fn]
|
||||
/// fn my_plugin_function(...) {
|
||||
/// ...
|
||||
/// }
|
||||
///
|
||||
/// let mut engine = Engine::new();
|
||||
///
|
||||
/// register_exported_fn!(engine, "calc", my_plugin_function);
|
||||
/// ```
|
||||
#[proc_macro]
|
||||
pub fn register_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let (engine_expr, export_name, rust_modpath) = match crate::register::parse_register_macro(args)
|
||||
@ -179,6 +258,22 @@ pub fn register_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenS
|
||||
proc_macro::TokenStream::from(tokens)
|
||||
}
|
||||
|
||||
/// Macro to register a _plugin function_ into a Rhai `Module`.
|
||||
///
|
||||
/// # Usage
|
||||
///
|
||||
/// ```,ignore
|
||||
/// use rhai::plugin::*;
|
||||
///
|
||||
/// #[export_fn]
|
||||
/// fn my_plugin_function(...) {
|
||||
/// ...
|
||||
/// }
|
||||
///
|
||||
/// let mut module = Module::new();
|
||||
///
|
||||
/// set_exported_fn!(module, "calc", my_plugin_function);
|
||||
/// ```
|
||||
#[proc_macro]
|
||||
pub fn set_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let (module_expr, export_name, rust_modpath) = match crate::register::parse_register_macro(args)
|
||||
|
@ -126,7 +126,7 @@ pub(crate) fn generate_body(
|
||||
set_fn_stmts.push(
|
||||
syn::parse2::<syn::Stmt>(quote! {
|
||||
m.set_fn(#fn_literal, FnAccess::Public, &[#(#fn_input_types),*],
|
||||
CallableFunction::from_plugin(#fn_token_name()));
|
||||
#fn_token_name().into());
|
||||
})
|
||||
.unwrap(),
|
||||
);
|
||||
|
@ -283,14 +283,14 @@ mod generate_tests {
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { false }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![].into_boxed_slice()
|
||||
}
|
||||
}
|
||||
pub fn token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(Token())
|
||||
Token().into()
|
||||
}
|
||||
pub fn token_input_types() -> Box<[TypeId]> {
|
||||
Token().input_types()
|
||||
@ -328,14 +328,14 @@ mod generate_tests {
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { false }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<usize>()].into_boxed_slice()
|
||||
}
|
||||
}
|
||||
pub fn token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(Token())
|
||||
Token().into()
|
||||
}
|
||||
pub fn token_input_types() -> Box<[TypeId]> {
|
||||
Token().input_types()
|
||||
@ -369,7 +369,7 @@ mod generate_tests {
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { false }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(MyType()) }
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<usize>()].into_boxed_slice()
|
||||
@ -404,7 +404,7 @@ mod generate_tests {
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { false }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<usize>(),
|
||||
@ -412,7 +412,7 @@ mod generate_tests {
|
||||
}
|
||||
}
|
||||
pub fn token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(Token())
|
||||
Token().into()
|
||||
}
|
||||
pub fn token_input_types() -> Box<[TypeId]> {
|
||||
Token().input_types()
|
||||
@ -446,12 +446,12 @@ mod generate_tests {
|
||||
debug_assert_eq!(args.len(), 2usize,
|
||||
"wrong arg count: {} != {}", args.len(), 2usize);
|
||||
let arg1 = mem::take(args[1usize]).cast::<usize>();
|
||||
let arg0: &mut _ = &mut args[0usize].write_lock::<usize>().unwrap();
|
||||
let arg0 = &mut args[0usize].write_lock::<usize>().unwrap();
|
||||
Ok(Dynamic::from(increment(arg0, arg1)))
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { true }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<usize>(),
|
||||
@ -459,7 +459,7 @@ mod generate_tests {
|
||||
}
|
||||
}
|
||||
pub fn token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(Token())
|
||||
Token().into()
|
||||
}
|
||||
pub fn token_input_types() -> Box<[TypeId]> {
|
||||
Token().input_types()
|
||||
@ -498,14 +498,14 @@ mod generate_tests {
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { false }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<ImmutableString>()].into_boxed_slice()
|
||||
}
|
||||
}
|
||||
pub fn token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(Token())
|
||||
Token().into()
|
||||
}
|
||||
pub fn token_input_types() -> Box<[TypeId]> {
|
||||
Token().input_types()
|
||||
|
@ -296,7 +296,7 @@ mod generate_tests {
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("get_mystic_number", FnAccess::Public, &[],
|
||||
CallableFunction::from_plugin(get_mystic_number_token()));
|
||||
get_mystic_number_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
#[allow(non_camel_case_types)]
|
||||
@ -311,7 +311,7 @@ mod generate_tests {
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { false }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(get_mystic_number_token())
|
||||
}
|
||||
@ -320,7 +320,7 @@ mod generate_tests {
|
||||
}
|
||||
}
|
||||
pub fn get_mystic_number_token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(get_mystic_number_token())
|
||||
get_mystic_number_token().into()
|
||||
}
|
||||
pub fn get_mystic_number_token_input_types() -> Box<[TypeId]> {
|
||||
get_mystic_number_token().input_types()
|
||||
@ -358,7 +358,7 @@ mod generate_tests {
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("add_one_to", FnAccess::Public, &[core::any::TypeId::of::<INT>()],
|
||||
CallableFunction::from_plugin(add_one_to_token()));
|
||||
add_one_to_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
#[allow(non_camel_case_types)]
|
||||
@ -374,7 +374,7 @@ mod generate_tests {
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { false }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(add_one_to_token())
|
||||
}
|
||||
@ -383,7 +383,7 @@ mod generate_tests {
|
||||
}
|
||||
}
|
||||
pub fn add_one_to_token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(add_one_to_token())
|
||||
add_one_to_token().into()
|
||||
}
|
||||
pub fn add_one_to_token_input_types() -> Box<[TypeId]> {
|
||||
add_one_to_token().input_types()
|
||||
@ -432,10 +432,10 @@ mod generate_tests {
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("add_n", FnAccess::Public, &[core::any::TypeId::of::<INT>()],
|
||||
CallableFunction::from_plugin(add_one_to_token()));
|
||||
add_one_to_token().into());
|
||||
m.set_fn("add_n", FnAccess::Public, &[core::any::TypeId::of::<INT>(),
|
||||
core::any::TypeId::of::<INT>()],
|
||||
CallableFunction::from_plugin(add_n_to_token()));
|
||||
add_n_to_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
#[allow(non_camel_case_types)]
|
||||
@ -451,7 +451,7 @@ mod generate_tests {
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { false }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(add_one_to_token())
|
||||
}
|
||||
@ -460,7 +460,7 @@ mod generate_tests {
|
||||
}
|
||||
}
|
||||
pub fn add_one_to_token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(add_one_to_token())
|
||||
add_one_to_token().into()
|
||||
}
|
||||
pub fn add_one_to_token_input_types() -> Box<[TypeId]> {
|
||||
add_one_to_token().input_types()
|
||||
@ -480,7 +480,7 @@ mod generate_tests {
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { false }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(add_n_to_token())
|
||||
}
|
||||
@ -490,7 +490,7 @@ mod generate_tests {
|
||||
}
|
||||
}
|
||||
pub fn add_n_to_token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(add_n_to_token())
|
||||
add_n_to_token().into()
|
||||
}
|
||||
pub fn add_n_to_token_input_types() -> Box<[TypeId]> {
|
||||
add_n_to_token().input_types()
|
||||
@ -529,7 +529,7 @@ mod generate_tests {
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("add_together", FnAccess::Public, &[core::any::TypeId::of::<INT>(),
|
||||
core::any::TypeId::of::<INT>()],
|
||||
CallableFunction::from_plugin(add_together_token()));
|
||||
add_together_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
#[allow(non_camel_case_types)]
|
||||
@ -546,7 +546,7 @@ mod generate_tests {
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { false }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(add_together_token())
|
||||
}
|
||||
@ -556,7 +556,7 @@ mod generate_tests {
|
||||
}
|
||||
}
|
||||
pub fn add_together_token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(add_together_token())
|
||||
add_together_token().into()
|
||||
}
|
||||
pub fn add_together_token_input_types() -> Box<[TypeId]> {
|
||||
add_together_token().input_types()
|
||||
@ -596,13 +596,13 @@ mod generate_tests {
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("add", FnAccess::Public, &[core::any::TypeId::of::<INT>(),
|
||||
core::any::TypeId::of::<INT>()],
|
||||
CallableFunction::from_plugin(add_together_token()));
|
||||
add_together_token().into());
|
||||
m.set_fn("+", FnAccess::Public, &[core::any::TypeId::of::<INT>(),
|
||||
core::any::TypeId::of::<INT>()],
|
||||
CallableFunction::from_plugin(add_together_token()));
|
||||
add_together_token().into());
|
||||
m.set_fn("add_together", FnAccess::Public, &[core::any::TypeId::of::<INT>(),
|
||||
core::any::TypeId::of::<INT>()],
|
||||
CallableFunction::from_plugin(add_together_token()));
|
||||
add_together_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
#[allow(non_camel_case_types)]
|
||||
@ -619,7 +619,7 @@ mod generate_tests {
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { false }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(add_together_token())
|
||||
}
|
||||
@ -629,7 +629,7 @@ mod generate_tests {
|
||||
}
|
||||
}
|
||||
pub fn add_together_token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(add_together_token())
|
||||
add_together_token().into()
|
||||
}
|
||||
pub fn add_together_token_input_types() -> Box<[TypeId]> {
|
||||
add_together_token().input_types()
|
||||
@ -844,7 +844,7 @@ mod generate_tests {
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("get_mystic_number", FnAccess::Public, &[],
|
||||
CallableFunction::from_plugin(get_mystic_number_token()));
|
||||
get_mystic_number_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
#[allow(non_camel_case_types)]
|
||||
@ -859,7 +859,7 @@ mod generate_tests {
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { false }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(get_mystic_number_token())
|
||||
}
|
||||
@ -868,7 +868,7 @@ mod generate_tests {
|
||||
}
|
||||
}
|
||||
pub fn get_mystic_number_token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(get_mystic_number_token())
|
||||
get_mystic_number_token().into()
|
||||
}
|
||||
pub fn get_mystic_number_token_input_types() -> Box<[TypeId]> {
|
||||
get_mystic_number_token().input_types()
|
||||
@ -937,7 +937,7 @@ mod generate_tests {
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("print_out_to", FnAccess::Public,
|
||||
&[core::any::TypeId::of::<ImmutableString>()],
|
||||
CallableFunction::from_plugin(print_out_to_token()));
|
||||
print_out_to_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
#[allow(non_camel_case_types)]
|
||||
@ -953,7 +953,7 @@ mod generate_tests {
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { false }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(print_out_to_token())
|
||||
}
|
||||
@ -962,7 +962,7 @@ mod generate_tests {
|
||||
}
|
||||
}
|
||||
pub fn print_out_to_token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(print_out_to_token())
|
||||
print_out_to_token().into()
|
||||
}
|
||||
pub fn print_out_to_token_input_types() -> Box<[TypeId]> {
|
||||
print_out_to_token().input_types()
|
||||
@ -1001,7 +1001,7 @@ mod generate_tests {
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("print_out_to", FnAccess::Public,
|
||||
&[core::any::TypeId::of::<ImmutableString>()],
|
||||
CallableFunction::from_plugin(print_out_to_token()));
|
||||
print_out_to_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
#[allow(non_camel_case_types)]
|
||||
@ -1017,7 +1017,7 @@ mod generate_tests {
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { false }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(print_out_to_token())
|
||||
}
|
||||
@ -1026,7 +1026,7 @@ mod generate_tests {
|
||||
}
|
||||
}
|
||||
pub fn print_out_to_token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(print_out_to_token())
|
||||
print_out_to_token().into()
|
||||
}
|
||||
pub fn print_out_to_token_input_types() -> Box<[TypeId]> {
|
||||
print_out_to_token().input_types()
|
||||
@ -1065,7 +1065,7 @@ mod generate_tests {
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("increment", FnAccess::Public,
|
||||
&[core::any::TypeId::of::<FLOAT>()],
|
||||
CallableFunction::from_plugin(increment_token()));
|
||||
increment_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
#[allow(non_camel_case_types)]
|
||||
@ -1076,12 +1076,12 @@ mod generate_tests {
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
debug_assert_eq!(args.len(), 1usize,
|
||||
"wrong arg count: {} != {}", args.len(), 1usize);
|
||||
let arg0: &mut _ = &mut args[0usize].write_lock::<FLOAT>().unwrap();
|
||||
let arg0 = &mut args[0usize].write_lock::<FLOAT>().unwrap();
|
||||
Ok(Dynamic::from(increment(arg0)))
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { true }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(increment_token())
|
||||
}
|
||||
@ -1090,7 +1090,7 @@ mod generate_tests {
|
||||
}
|
||||
}
|
||||
pub fn increment_token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(increment_token())
|
||||
increment_token().into()
|
||||
}
|
||||
pub fn increment_token_input_types() -> Box<[TypeId]> {
|
||||
increment_token().input_types()
|
||||
@ -1132,7 +1132,7 @@ mod generate_tests {
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("increment", FnAccess::Public,
|
||||
&[core::any::TypeId::of::<FLOAT>()],
|
||||
CallableFunction::from_plugin(increment_token()));
|
||||
increment_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
#[allow(non_camel_case_types)]
|
||||
@ -1143,12 +1143,12 @@ mod generate_tests {
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
debug_assert_eq!(args.len(), 1usize,
|
||||
"wrong arg count: {} != {}", args.len(), 1usize);
|
||||
let arg0: &mut _ = &mut args[0usize].write_lock::<FLOAT>().unwrap();
|
||||
let arg0 = &mut args[0usize].write_lock::<FLOAT>().unwrap();
|
||||
Ok(Dynamic::from(increment(arg0)))
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { true }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(increment_token())
|
||||
}
|
||||
@ -1157,7 +1157,7 @@ mod generate_tests {
|
||||
}
|
||||
}
|
||||
pub fn increment_token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(increment_token())
|
||||
increment_token().into()
|
||||
}
|
||||
pub fn increment_token_input_types() -> Box<[TypeId]> {
|
||||
increment_token().input_types()
|
||||
@ -1219,7 +1219,7 @@ mod generate_tests {
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("increment", FnAccess::Public,
|
||||
&[core::any::TypeId::of::<FLOAT>()],
|
||||
CallableFunction::from_plugin(increment_token()));
|
||||
increment_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
#[allow(non_camel_case_types)]
|
||||
@ -1230,12 +1230,12 @@ mod generate_tests {
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
debug_assert_eq!(args.len(), 1usize,
|
||||
"wrong arg count: {} != {}", args.len(), 1usize);
|
||||
let arg0: &mut _ = &mut args[0usize].write_lock::<FLOAT>().unwrap();
|
||||
let arg0 = &mut args[0usize].write_lock::<FLOAT>().unwrap();
|
||||
Ok(Dynamic::from(increment(arg0)))
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { true }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(increment_token())
|
||||
}
|
||||
@ -1244,7 +1244,7 @@ mod generate_tests {
|
||||
}
|
||||
}
|
||||
pub fn increment_token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(increment_token())
|
||||
increment_token().into()
|
||||
}
|
||||
pub fn increment_token_input_types() -> Box<[TypeId]> {
|
||||
increment_token().input_types()
|
||||
@ -1304,7 +1304,7 @@ mod generate_tests {
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("get$square", FnAccess::Public, &[core::any::TypeId::of::<u64>()],
|
||||
CallableFunction::from_plugin(int_foo_token()));
|
||||
int_foo_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
#[allow(non_camel_case_types)]
|
||||
@ -1315,12 +1315,12 @@ mod generate_tests {
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
debug_assert_eq!(args.len(), 1usize,
|
||||
"wrong arg count: {} != {}", args.len(), 1usize);
|
||||
let arg0: &mut _ = &mut args[0usize].write_lock::<u64>().unwrap();
|
||||
let arg0 = &mut args[0usize].write_lock::<u64>().unwrap();
|
||||
Ok(Dynamic::from(int_foo(arg0)))
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { true }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(int_foo_token())
|
||||
}
|
||||
@ -1329,7 +1329,7 @@ mod generate_tests {
|
||||
}
|
||||
}
|
||||
pub fn int_foo_token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(int_foo_token())
|
||||
int_foo_token().into()
|
||||
}
|
||||
pub fn int_foo_token_input_types() -> Box<[TypeId]> {
|
||||
int_foo_token().input_types()
|
||||
@ -1368,9 +1368,9 @@ mod generate_tests {
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("square", FnAccess::Public, &[core::any::TypeId::of::<u64>()],
|
||||
CallableFunction::from_plugin(int_foo_token()));
|
||||
int_foo_token().into());
|
||||
m.set_fn("get$square", FnAccess::Public, &[core::any::TypeId::of::<u64>()],
|
||||
CallableFunction::from_plugin(int_foo_token()));
|
||||
int_foo_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
#[allow(non_camel_case_types)]
|
||||
@ -1381,12 +1381,12 @@ mod generate_tests {
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
debug_assert_eq!(args.len(), 1usize,
|
||||
"wrong arg count: {} != {}", args.len(), 1usize);
|
||||
let arg0: &mut _ = &mut args[0usize].write_lock::<u64>().unwrap();
|
||||
let arg0 = &mut args[0usize].write_lock::<u64>().unwrap();
|
||||
Ok(Dynamic::from(int_foo(arg0)))
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { true }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(int_foo_token())
|
||||
}
|
||||
@ -1395,7 +1395,7 @@ mod generate_tests {
|
||||
}
|
||||
}
|
||||
pub fn int_foo_token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(int_foo_token())
|
||||
int_foo_token().into()
|
||||
}
|
||||
pub fn int_foo_token_input_types() -> Box<[TypeId]> {
|
||||
int_foo_token().input_types()
|
||||
@ -1436,7 +1436,7 @@ mod generate_tests {
|
||||
m.set_fn("set$squared", FnAccess::Public,
|
||||
&[core::any::TypeId::of::<u64>(),
|
||||
core::any::TypeId::of::<u64>()],
|
||||
CallableFunction::from_plugin(int_foo_token()));
|
||||
int_foo_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
#[allow(non_camel_case_types)]
|
||||
@ -1448,12 +1448,12 @@ mod generate_tests {
|
||||
debug_assert_eq!(args.len(), 2usize,
|
||||
"wrong arg count: {} != {}", args.len(), 2usize);
|
||||
let arg1 = mem::take(args[1usize]).cast::<u64>();
|
||||
let arg0: &mut _ = &mut args[0usize].write_lock::<u64>().unwrap();
|
||||
let arg0 = &mut args[0usize].write_lock::<u64>().unwrap();
|
||||
Ok(Dynamic::from(int_foo(arg0, arg1)))
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { true }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(int_foo_token())
|
||||
}
|
||||
@ -1462,7 +1462,7 @@ mod generate_tests {
|
||||
}
|
||||
}
|
||||
pub fn int_foo_token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(int_foo_token())
|
||||
int_foo_token().into()
|
||||
}
|
||||
pub fn int_foo_token_input_types() -> Box<[TypeId]> {
|
||||
int_foo_token().input_types()
|
||||
@ -1503,11 +1503,11 @@ mod generate_tests {
|
||||
m.set_fn("set_sq", FnAccess::Public,
|
||||
&[core::any::TypeId::of::<u64>(),
|
||||
core::any::TypeId::of::<u64>()],
|
||||
CallableFunction::from_plugin(int_foo_token()));
|
||||
int_foo_token().into());
|
||||
m.set_fn("set$squared", FnAccess::Public,
|
||||
&[core::any::TypeId::of::<u64>(),
|
||||
core::any::TypeId::of::<u64>()],
|
||||
CallableFunction::from_plugin(int_foo_token()));
|
||||
int_foo_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
#[allow(non_camel_case_types)]
|
||||
@ -1519,12 +1519,12 @@ mod generate_tests {
|
||||
debug_assert_eq!(args.len(), 2usize,
|
||||
"wrong arg count: {} != {}", args.len(), 2usize);
|
||||
let arg1 = mem::take(args[1usize]).cast::<u64>();
|
||||
let arg0: &mut _ = &mut args[0usize].write_lock::<u64>().unwrap();
|
||||
let arg0 = &mut args[0usize].write_lock::<u64>().unwrap();
|
||||
Ok(Dynamic::from(int_foo(arg0, arg1)))
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { true }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(int_foo_token())
|
||||
}
|
||||
@ -1533,7 +1533,7 @@ mod generate_tests {
|
||||
}
|
||||
}
|
||||
pub fn int_foo_token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(int_foo_token())
|
||||
int_foo_token().into()
|
||||
}
|
||||
pub fn int_foo_token_input_types() -> Box<[TypeId]> {
|
||||
int_foo_token().input_types()
|
||||
@ -1574,7 +1574,7 @@ mod generate_tests {
|
||||
m.set_fn("index$get$", FnAccess::Public,
|
||||
&[core::any::TypeId::of::<MyCollection>(),
|
||||
core::any::TypeId::of::<u64>()],
|
||||
CallableFunction::from_plugin(get_by_index_token()));
|
||||
get_by_index_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
#[allow(non_camel_case_types)]
|
||||
@ -1586,12 +1586,12 @@ mod generate_tests {
|
||||
debug_assert_eq!(args.len(), 2usize,
|
||||
"wrong arg count: {} != {}", args.len(), 2usize);
|
||||
let arg1 = mem::take(args[1usize]).cast::<u64>();
|
||||
let arg0: &mut _ = &mut args[0usize].write_lock::<MyCollection>().unwrap();
|
||||
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap();
|
||||
Ok(Dynamic::from(get_by_index(arg0, arg1)))
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { true }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(get_by_index_token())
|
||||
}
|
||||
@ -1601,7 +1601,7 @@ mod generate_tests {
|
||||
}
|
||||
}
|
||||
pub fn get_by_index_token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(get_by_index_token())
|
||||
get_by_index_token().into()
|
||||
}
|
||||
pub fn get_by_index_token_input_types() -> Box<[TypeId]> {
|
||||
get_by_index_token().input_types()
|
||||
@ -1642,11 +1642,11 @@ mod generate_tests {
|
||||
m.set_fn("get", FnAccess::Public,
|
||||
&[core::any::TypeId::of::<MyCollection>(),
|
||||
core::any::TypeId::of::<u64>()],
|
||||
CallableFunction::from_plugin(get_by_index_token()));
|
||||
get_by_index_token().into());
|
||||
m.set_fn("index$get$", FnAccess::Public,
|
||||
&[core::any::TypeId::of::<MyCollection>(),
|
||||
core::any::TypeId::of::<u64>()],
|
||||
CallableFunction::from_plugin(get_by_index_token()));
|
||||
get_by_index_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
#[allow(non_camel_case_types)]
|
||||
@ -1658,12 +1658,12 @@ mod generate_tests {
|
||||
debug_assert_eq!(args.len(), 2usize,
|
||||
"wrong arg count: {} != {}", args.len(), 2usize);
|
||||
let arg1 = mem::take(args[1usize]).cast::<u64>();
|
||||
let arg0: &mut _ = &mut args[0usize].write_lock::<MyCollection>().unwrap();
|
||||
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap();
|
||||
Ok(Dynamic::from(get_by_index(arg0, arg1)))
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { true }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(get_by_index_token())
|
||||
}
|
||||
@ -1673,7 +1673,7 @@ mod generate_tests {
|
||||
}
|
||||
}
|
||||
pub fn get_by_index_token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(get_by_index_token())
|
||||
get_by_index_token().into()
|
||||
}
|
||||
pub fn get_by_index_token_input_types() -> Box<[TypeId]> {
|
||||
get_by_index_token().input_types()
|
||||
@ -1715,7 +1715,7 @@ mod generate_tests {
|
||||
&[core::any::TypeId::of::<MyCollection>(),
|
||||
core::any::TypeId::of::<u64>(),
|
||||
core::any::TypeId::of::<FLOAT>()],
|
||||
CallableFunction::from_plugin(set_by_index_token()));
|
||||
set_by_index_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
#[allow(non_camel_case_types)]
|
||||
@ -1728,12 +1728,12 @@ mod generate_tests {
|
||||
"wrong arg count: {} != {}", args.len(), 3usize);
|
||||
let arg1 = mem::take(args[1usize]).cast::<u64>();
|
||||
let arg2 = mem::take(args[2usize]).cast::<FLOAT>();
|
||||
let arg0: &mut _ = &mut args[0usize].write_lock::<MyCollection>().unwrap();
|
||||
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap();
|
||||
Ok(Dynamic::from(set_by_index(arg0, arg1, arg2)))
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { true }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(set_by_index_token())
|
||||
}
|
||||
@ -1744,7 +1744,7 @@ mod generate_tests {
|
||||
}
|
||||
}
|
||||
pub fn set_by_index_token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(set_by_index_token())
|
||||
set_by_index_token().into()
|
||||
}
|
||||
pub fn set_by_index_token_input_types() -> Box<[TypeId]> {
|
||||
set_by_index_token().input_types()
|
||||
@ -1786,12 +1786,12 @@ mod generate_tests {
|
||||
&[core::any::TypeId::of::<MyCollection>(),
|
||||
core::any::TypeId::of::<u64>(),
|
||||
core::any::TypeId::of::<FLOAT>()],
|
||||
CallableFunction::from_plugin(set_by_index_token()));
|
||||
set_by_index_token().into());
|
||||
m.set_fn("index$set$", FnAccess::Public,
|
||||
&[core::any::TypeId::of::<MyCollection>(),
|
||||
core::any::TypeId::of::<u64>(),
|
||||
core::any::TypeId::of::<FLOAT>()],
|
||||
CallableFunction::from_plugin(set_by_index_token()));
|
||||
set_by_index_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
#[allow(non_camel_case_types)]
|
||||
@ -1804,12 +1804,12 @@ mod generate_tests {
|
||||
"wrong arg count: {} != {}", args.len(), 3usize);
|
||||
let arg1 = mem::take(args[1usize]).cast::<u64>();
|
||||
let arg2 = mem::take(args[2usize]).cast::<FLOAT>();
|
||||
let arg0: &mut _ = &mut args[0usize].write_lock::<MyCollection>().unwrap();
|
||||
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap();
|
||||
Ok(Dynamic::from(set_by_index(arg0, arg1, arg2)))
|
||||
}
|
||||
|
||||
fn is_method_call(&self) -> bool { true }
|
||||
fn is_varadic(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(set_by_index_token())
|
||||
}
|
||||
@ -1820,7 +1820,7 @@ mod generate_tests {
|
||||
}
|
||||
}
|
||||
pub fn set_by_index_token_callable() -> CallableFunction {
|
||||
CallableFunction::from_plugin(set_by_index_token())
|
||||
set_by_index_token().into()
|
||||
}
|
||||
pub fn set_by_index_token_input_types() -> Box<[TypeId]> {
|
||||
set_by_index_token().input_types()
|
||||
|
@ -14,8 +14,8 @@ Easy
|
||||
|
||||
* Easily [call a script-defined function]({{rootUrl}}/engine/call-fn.md) from Rust.
|
||||
|
||||
* Very few additional dependencies (right now only [`smallvec`](https://crates.io/crates/smallvec/));
|
||||
for [`no-std`] builds, a number of additional dependencies are pulled in to provide for functionalities that used to be in `std`.
|
||||
* Very few additional dependencies - right now only [`smallvec`](https://crates.io/crates/smallvec/) plus crates for procedural macros;
|
||||
for [`no-std`] and `WASM` builds, a number of additional dependencies are pulled in to provide for missing functionalities.
|
||||
|
||||
Fast
|
||||
----
|
||||
|
@ -3,6 +3,8 @@ What is Rhai
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
![Rhai Logo]({{rootUrl}}/images/rhai_logo.png)
|
||||
|
||||
Rhai is an embedded scripting language and evaluation engine for Rust that gives a safe and easy way
|
||||
to add scripting to any application.
|
||||
|
||||
@ -13,3 +15,27 @@ Versions
|
||||
This Book is for version **{{version}}** of Rhai.
|
||||
|
||||
For the latest development version, see [here]({{rootUrl}}/vnext/).
|
||||
|
||||
|
||||
Etymology of the name "Rhai"
|
||||
---------------------------
|
||||
|
||||
### As per Rhai's author Johnathan Turner
|
||||
|
||||
In the beginning there was [ChaiScript](http://chaiscript.com),
|
||||
which is an embedded scripting language for C++.
|
||||
Originally it was intended to be a scripting language similar to **JavaScript**.
|
||||
|
||||
With java being a kind of hot beverage, the new language was named after
|
||||
another hot beverage - **Chai**, which is the word for "tea" in many world languages
|
||||
and, in particular, a popular kind of milk tea consumed in India.
|
||||
|
||||
Later, when the novel implementation technique behind ChaiScript was ported from C++ to Rust,
|
||||
logically the `C` was changed to an `R` to make it "RhaiScript", or just "Rhai".
|
||||
|
||||
### On the origin of the temporary Rhai logo
|
||||
|
||||
One of Rhai's maintainers, Stephen Chung, was thinking about a logo when he accidentally
|
||||
came across a copy of _Catcher in the Rye_ in a restaurant. The rest was history.
|
||||
|
||||
It is temporary until it becomes official, that is...
|
||||
|
@ -3,13 +3,11 @@ Licensing
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
Rhai is licensed under either:
|
||||
Rhai is licensed under either of the following, at your choice:
|
||||
|
||||
* [Apache License, Version 2.0]({{repoHome}}/LICENSE-APACHE.txt), or
|
||||
|
||||
* [MIT license]({{repoHome}}/LICENSE-MIT.txt)
|
||||
|
||||
at your choice.
|
||||
* [MIT license]({{repoHome}}/LICENSE-MIT.txt).
|
||||
|
||||
Unless explicitly stated otherwise, any contribution intentionally submitted for inclusion in this crate,
|
||||
as defined in the Apache-2.0 license, shall be dual-licensed as above,
|
||||
|
@ -14,7 +14,7 @@ It doesn't attempt to be a new language. For example:
|
||||
|
||||
There is, however, a built-in [object map] type which is adequate for most uses.
|
||||
It is possible to simulate [object-oriented programming (OOP)][OOP] by storing [function pointers]
|
||||
in [object map] properties, turning them into _methods_.
|
||||
or [closures] in [object map] properties, turning them into _methods_.
|
||||
|
||||
* No first-class functions - Code your functions in Rust instead, and register them with Rhai.
|
||||
|
||||
@ -22,22 +22,32 @@ It doesn't attempt to be a new language. For example:
|
||||
|
||||
* No garbage collection - this should be expected, so...
|
||||
|
||||
* No closures - do your closure magic in Rust instead; [turn a Rhai scripted function into a Rust closure]({{rootUrl}}/engine/call-fn.md).
|
||||
* No first-class closures - do your closure magic in Rust instead: [turn a Rhai scripted function into a Rust closure]({{rootUrl}}/engine/call-fn.md).
|
||||
|
||||
But you can [curry][currying] a [function pointer] with arguments to simulate it somewhat.
|
||||
There is, however, support for simulated [closures] via [currying] a [function pointer] with
|
||||
captured shared variables.
|
||||
|
||||
* No byte-codes/JIT - Rhai has an AST-walking interpreter which will not win any speed races. The purpose of Rhai is not
|
||||
to be extremely _fast_, but to make it as easy as possible to integrate with native Rust applications.
|
||||
* No byte-codes/JIT - Rhai has an AST-walking interpreter which will not win any speed races.
|
||||
The purpose of Rhai is not to be extremely _fast_, but to make it as easy as possible to
|
||||
integrate with native Rust applications.
|
||||
|
||||
* No formal language grammar - Rhai uses a hand-coded lexer, a hand-coded top-down recursive-descent parser
|
||||
for statements and a Pratt parser for expressions.
|
||||
|
||||
This lack of formalism allows the parser itself to be exposed as a service in order to support
|
||||
[disabling keywords/operators][disable keywords and operators], adding [custom operators],
|
||||
and defining [custom syntax].
|
||||
|
||||
|
||||
Do Not Write The Next 4D VR Game in Rhai
|
||||
---------------------------------------
|
||||
|
||||
Due to this intended usage, Rhai deliberately keeps the language simple and small by omitting advanced language features
|
||||
such as classes, inheritance, first-class functions, closures, concurrency, byte-codes, JIT etc.
|
||||
Due to this intended usage, Rhai deliberately keeps the language simple and small by omitting
|
||||
advanced language features such as classes, inheritance, first-class functions, closures,
|
||||
concurrency, byte-codes VM, JIT etc.
|
||||
|
||||
Avoid the temptation to write full-fledge application logic entirely in Rhai - that use case is best fulfilled by
|
||||
more complete languages such as JavaScript or Lua.
|
||||
Avoid the temptation to write full-fledge application logic entirely in Rhai -
|
||||
that use case is best fulfilled by more complete languages such as JavaScript or Lua.
|
||||
|
||||
|
||||
Thin Dynamic Wrapper Layer Over Rust Code
|
||||
@ -47,7 +57,8 @@ In actual practice, it is usually best to expose a Rust API into Rhai for script
|
||||
|
||||
All the core functionalities should be written in Rust, with Rhai being the dynamic _control_ layer.
|
||||
|
||||
This is similar to some dynamic languages where most of the core functionalities reside in a C/C++ standard library.
|
||||
This is similar to some dynamic languages where most of the core functionalities reside in a C/C++
|
||||
standard library.
|
||||
|
||||
Another similar scenario is a web front-end driving back-end services written in a systems language.
|
||||
In this case, JavaScript takes the role of Rhai while the back-end language, well... it can actually also be Rust.
|
||||
|
@ -5,7 +5,7 @@ Related Resources
|
||||
|
||||
Other online documentation resources for Rhai:
|
||||
|
||||
* [`crates.io`](https://crates.io/crates/rhai/) - Rhai crate
|
||||
* [`crates.io`](https://crates.io/crates/rhai) - Rhai crate
|
||||
|
||||
* [`DOCS.RS`](https://docs.rs/rhai) - Rhai API documentation
|
||||
|
||||
@ -15,6 +15,6 @@ Other online documentation resources for Rhai:
|
||||
|
||||
Other cool projects to check out:
|
||||
|
||||
* [ChaiScript](http://chaiscript.com/) - A strong inspiration for Rhai. An embedded scripting language for C++ that I helped created many moons ago, now being led by my cousin.
|
||||
* [ChaiScript](http://chaiscript.com) - A strong inspiration for Rhai. An embedded scripting language for C++.
|
||||
|
||||
* Check out the list of [scripting languages for Rust](https://github.com/rust-unofficial/awesome-rust#scripting) on [awesome-rust](https://github.com/rust-unofficial/awesome-rust)
|
||||
|
@ -10,3 +10,9 @@ The following targets and builds are support by Rhai:
|
||||
* WebAssembly ([WASM])
|
||||
|
||||
* [`no-std`]
|
||||
|
||||
|
||||
Minimum Rust Version
|
||||
--------------------
|
||||
|
||||
The minimum version of Rust required to compile Rhai is `1.45.0`.
|
||||
|
@ -13,8 +13,6 @@ This section covers advanced features such as:
|
||||
|
||||
* [Script optimization].
|
||||
|
||||
* [Domain-Specific Languages][DSL].
|
||||
|
||||
* Low-level [function registration API]({{rootUrl}}/rust/register-raw.md)
|
||||
|
||||
* The dreaded (or beloved for those with twisted tastes) [`eval`] statement.
|
||||
* [Domain-Specific Languages][DSL].
|
||||
|
@ -65,7 +65,7 @@ anything that implements `AsMut<Dynamic>` (such as a simple array or a `Vec<Dyna
|
||||
```rust
|
||||
let result = engine.call_fn_dynamic(
|
||||
&mut scope, // scope to use
|
||||
ast.into(), // get 'Module' from 'AST'
|
||||
&ast, // AST containing the functions
|
||||
"hello", // function entry-point
|
||||
None, // 'this' pointer, if any
|
||||
[ String::from("abc").into(), 123_i64.into() ] // arguments
|
||||
@ -85,7 +85,7 @@ let mut value: Dynamic = 1_i64.into();
|
||||
|
||||
let result = engine.call_fn_dynamic(
|
||||
&mut scope,
|
||||
ast.into(),
|
||||
&ast,
|
||||
"action",
|
||||
Some(&mut value), // binding the 'this' pointer
|
||||
[ 41_i64.into() ]
|
||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
@ -49,8 +49,8 @@ f.call!(41); // <- syntax error: capturing is not allowed in method-c
|
||||
No Mutations
|
||||
------------
|
||||
|
||||
Variables in the calling scope are captured as copies.
|
||||
Changes to them do not reflect back to the calling scope.
|
||||
Variables in the calling scope are captured as cloned copies.
|
||||
Changes to them do **not** reflect back to the calling scope.
|
||||
|
||||
Rhai functions remain _pure_ in the sense that they can never mutate their environment.
|
||||
|
||||
|
@ -15,10 +15,10 @@ forming a new, combined, group of functions.
|
||||
|
||||
In general, there are two types of _namespaces_ where functions are looked up:
|
||||
|
||||
| Namespace | Source | Lookup method | How Many |
|
||||
| --------- | ---------------------------------------------------------------------- | --------------------------------- | :----------------------: |
|
||||
| Global | `Engine::register_XXX` API, [`AST`] being evaluated, [packages] loaded | simple function name | one |
|
||||
| Module | [`Module`] | namespace-qualified function name | as many as [`import`]-ed |
|
||||
| Namespace | Source | Lookup method | Sub-modules? | Variables? |
|
||||
| --------- | ------------------------------------------------------------------------------------- | ------------------------------ | :----------: | :--------: |
|
||||
| Global | 1) `Engine::register_XXX` API<br/>2) [`AST`] being evaluated<br/>3) [packages] loaded | simple function name | ignored | ignored |
|
||||
| Module | [`Module`] | module-qualified function name | yes | yes |
|
||||
|
||||
|
||||
Global Namespace
|
||||
|
@ -15,9 +15,10 @@ Built-in methods
|
||||
The following standard methods (mostly defined in the [`BasicFnPackage`][packages] but excluded if
|
||||
using a [raw `Engine`]) operate on [strings]:
|
||||
|
||||
| Function | Parameter(s) | Description |
|
||||
| -------------------------- | ------------ | --------------------------------------------------------------------- |
|
||||
| `name` method and property | _none_ | returns the name of the function encapsulated by the function pointer |
|
||||
| Function | Parameter(s) | Description |
|
||||
| -------------------------- | ------------ | ---------------------------------------------------------------------------- |
|
||||
| `name` method and property | _none_ | returns the name of the function encapsulated by the function pointer |
|
||||
| `call` | _arguments_ | calls the function matching the function pointer's name with the _arguments_ |
|
||||
|
||||
|
||||
Examples
|
||||
@ -143,7 +144,9 @@ to a function call while binding the object in the method call to the `this` poi
|
||||
To achieve this, pass the `FnPtr` value as the _first_ argument to `call`:
|
||||
|
||||
```rust
|
||||
fn add(x) { this += x; } // define function which uses 'this'
|
||||
fn add(x) { // define function which uses 'this'
|
||||
this += x;
|
||||
}
|
||||
|
||||
let func = Fn("add"); // function pointer to 'add'
|
||||
|
||||
|
@ -12,8 +12,13 @@ Like C, `continue` can be used to skip to the next iteration, by-passing all fol
|
||||
To loop through a number sequence (with or without steps), use the `range` function to
|
||||
return a numeric iterator.
|
||||
|
||||
|
||||
Iterate Through Strings
|
||||
-----------------------
|
||||
|
||||
Iterating through a [string] yields characters.
|
||||
|
||||
```rust
|
||||
// Iterate through string, yielding characters
|
||||
let s = "hello, world!";
|
||||
|
||||
for ch in s {
|
||||
@ -23,8 +28,15 @@ for ch in s {
|
||||
|
||||
if x == '@' { break; } // break out of for loop
|
||||
}
|
||||
```
|
||||
|
||||
// Iterate through array
|
||||
|
||||
Iterate Through Arrays
|
||||
----------------------
|
||||
|
||||
Iterating through an [array] yields cloned _copies_ of each element.
|
||||
|
||||
```rust
|
||||
let array = [1, 3, 5, 7, 9, 42];
|
||||
|
||||
for x in array {
|
||||
@ -34,8 +46,17 @@ for x in array {
|
||||
|
||||
if x == 42 { break; } // break out of for loop
|
||||
}
|
||||
```
|
||||
|
||||
// The 'range' function allows iterating from first to last-1
|
||||
|
||||
Iterate Through Numeric Ranges
|
||||
-----------------------------
|
||||
|
||||
The `range` function allows iterating through a range of numbers
|
||||
(not including the last number).
|
||||
|
||||
```rust
|
||||
// Iterate starting from 0 and stopping at 49.
|
||||
for x in range(0, 50) {
|
||||
if x > 10 { continue; } // skip to the next iteration
|
||||
|
||||
@ -44,7 +65,7 @@ for x in range(0, 50) {
|
||||
if x == 42 { break; } // break out of for loop
|
||||
}
|
||||
|
||||
// The 'range' function also takes a step
|
||||
// The 'range' function also takes a step.
|
||||
for x in range(0, 50, 3) { // step by 3
|
||||
if x > 10 { continue; } // skip to the next iteration
|
||||
|
||||
@ -52,8 +73,18 @@ for x in range(0, 50, 3) { // step by 3
|
||||
|
||||
if x == 42 { break; } // break out of for loop
|
||||
}
|
||||
```
|
||||
|
||||
// Iterate through object map
|
||||
|
||||
Iterate Through Object Maps
|
||||
--------------------------
|
||||
|
||||
Two functions, `keys` and `values`, return [arrays] containing cloned _copies_
|
||||
of all property names and values of an [object map], respectively.
|
||||
|
||||
These [arrays] can be iterated.
|
||||
|
||||
```rust
|
||||
let map = #{a:1, b:3, c:5, d:7, e:9};
|
||||
|
||||
// Property names are returned in unsorted, random order
|
||||
|
@ -42,19 +42,6 @@ add2(42) == 44;
|
||||
```
|
||||
|
||||
|
||||
No Access to External Scope
|
||||
--------------------------
|
||||
|
||||
Functions are not _closures_. They do not capture the calling environment and can only access their own parameters.
|
||||
They cannot access variables external to the function itself.
|
||||
|
||||
```rust
|
||||
let x = 42;
|
||||
|
||||
fn foo() { x } // <- syntax error: variable 'x' doesn't exist
|
||||
```
|
||||
|
||||
|
||||
Global Definitions Only
|
||||
----------------------
|
||||
|
||||
@ -77,24 +64,52 @@ fn do_addition(x) {
|
||||
```
|
||||
|
||||
|
||||
Use Before Definition
|
||||
--------------------
|
||||
No Access to External Scope
|
||||
--------------------------
|
||||
|
||||
Functions are not _closures_. They do not capture the calling environment
|
||||
and can only access their own parameters.
|
||||
They cannot access variables external to the function itself.
|
||||
|
||||
```rust
|
||||
let x = 42;
|
||||
|
||||
fn foo() { x } // <- syntax error: variable 'x' doesn't exist
|
||||
```
|
||||
|
||||
|
||||
But Can Call Other Functions
|
||||
---------------------------
|
||||
|
||||
All functions in the same [`AST`] can call each other.
|
||||
|
||||
```rust
|
||||
fn foo(x) { x + 1 } // function defined in the global namespace
|
||||
|
||||
fn bar(x) { foo(x) } // OK! function 'foo' can be called
|
||||
```
|
||||
|
||||
|
||||
Use Before Definition Allowed
|
||||
----------------------------
|
||||
|
||||
Unlike C/C++, functions in Rhai can be defined _anywhere_ at 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, such as JavaScript's `function` keyword.
|
||||
|
||||
|
||||
Arguments Passed by Value
|
||||
------------------------
|
||||
Arguments are Passed by Value
|
||||
----------------------------
|
||||
|
||||
Functions defined in script always take [`Dynamic`] parameters (i.e. the parameter can be of any type).
|
||||
Functions defined in script always take [`Dynamic`] parameters (i.e. they can be of any types).
|
||||
Therefore, functions with the same name and same _number_ of parameters are equivalent.
|
||||
|
||||
It is important to remember that all arguments are passed by _value_, so all Rhai script-defined functions
|
||||
are _pure_ (i.e. they never modify their arguments).
|
||||
All arguments are passed by _value_, so all Rhai script-defined functions are _pure_
|
||||
(i.e. they never modify their arguments).
|
||||
|
||||
Any update to an argument will **not** be reflected back to the caller.
|
||||
|
||||
```rust
|
||||
@ -113,8 +128,8 @@ x == 500; // 'x' is NOT changed!
|
||||
`this` - Simulating an Object Method
|
||||
-----------------------------------
|
||||
|
||||
Functions can also be called in method-call style. When this is the case, the keyword '`this`'
|
||||
binds to the object in the method call and can be changed.
|
||||
Script-defined functions can also be called in method-call style.
|
||||
When this happens, the keyword '`this`' binds to the object in the method call and can be changed.
|
||||
|
||||
```rust
|
||||
fn change() { // not that the object does not need a parameter
|
||||
|
@ -39,8 +39,8 @@ array[0].update(); // <- call in method-call style will update 'a'
|
||||
**IMPORTANT: Rhai does NOT support normal references (i.e. `&T`) as parameters.**
|
||||
|
||||
|
||||
Number of Parameters
|
||||
--------------------
|
||||
Number of Parameters in Methods
|
||||
------------------------------
|
||||
|
||||
Native Rust methods registered with an [`Engine`] take _one additional parameter_ more than
|
||||
an equivalent method coded in script, where the object is accessed via the `this` pointer instead.
|
||||
@ -53,15 +53,43 @@ The following table illustrates the differences:
|
||||
| Rhai script | _N_ | `this` (of type `&mut T`) | `Fn(x: U, y: V)` |
|
||||
|
||||
|
||||
`&mut` is Efficient, Except for `ImmutableString`
|
||||
-----------------------------------------------
|
||||
`&mut` is Efficient, Except for `&mut ImmutableString`
|
||||
----------------------------------------------------
|
||||
|
||||
Using a `&mut` first parameter is highly encouraged when using types that are expensive to clone,
|
||||
even when the intention is not to mutate that argument, because it avoids cloning that argument value.
|
||||
|
||||
For example, the `len` method of an [array] has the signature: `Fn(&mut Array) -> INT`.
|
||||
The array itself is not modified in any way, but using a `&mut` parameter avoids a cloning that would
|
||||
otherwise have happened if the signature were `Fn(Array) -> INT`.
|
||||
Even when a function is never intended to be a method - for example an operator,
|
||||
it is still sometimes beneficial to make it method-like (i.e. with a first `&mut` parameter)
|
||||
if the first parameter is not modified.
|
||||
|
||||
For types that are expensive to clone (remember, all function calls are passed cloned
|
||||
copies of argument values), this may result in a significant performance boost.
|
||||
|
||||
For primary types that are cheap to clone (e.g. those that implement `Copy`), including `ImmutableString`,
|
||||
this is not necessary.
|
||||
|
||||
```rust
|
||||
// This is a type that is very expensive to clone.
|
||||
#[derive(Debug, Clone)]
|
||||
struct VeryComplexType { ... }
|
||||
|
||||
// Calculate some value by adding 'VeryComplexType' with an integer number.
|
||||
fn do_add(obj: &VeryComplexType, offset: i64) -> i64 {
|
||||
...
|
||||
}
|
||||
|
||||
engine
|
||||
.register_type::<VeryComplexType>()
|
||||
.register_fn("+", add_pure /* or add_method*/);
|
||||
|
||||
// Very expensive to call, as the 'VeryComplexType' is cloned before each call.
|
||||
fn add_pure(obj: VeryComplexType, offset: i64) -> i64 {
|
||||
do_add(obj, offset)
|
||||
}
|
||||
|
||||
// Efficient to call, as only a reference to the 'VeryComplexType' is passed.
|
||||
fn add_method(obj: &mut VeryComplexType, offset: i64) -> i64 {
|
||||
do_add(obj, offset)
|
||||
}
|
||||
```
|
||||
|
@ -29,7 +29,15 @@ Modifying an `ImmutableString` causes it first to be cloned, and then the modifi
|
||||
`ImmutableString` should be used in place of `String` for function parameters because using
|
||||
`String` is very inefficient (the `String` argument is cloned during every call).
|
||||
|
||||
A alternative is to use `&str` which maps straight to `ImmutableString`.
|
||||
A alternative is to use `&str` which de-sugars to `ImmutableString`.
|
||||
|
||||
```rust
|
||||
fn slow(s: String) -> i64 { ... } // string is cloned each call
|
||||
|
||||
fn fast1(s: ImmutableString) -> i64 { ... } // cloning 'ImmutableString' is cheap
|
||||
|
||||
fn fast2(s: &str) -> i64 { ... } // de-sugars to above
|
||||
```
|
||||
|
||||
|
||||
String and Character Literals
|
||||
|
@ -16,8 +16,9 @@ if some_bad_condition_has_happened {
|
||||
throw; // defaults to empty exception text: ""
|
||||
```
|
||||
|
||||
Exceptions thrown via `throw` in the script can be captured by matching `Err(Box<EvalAltResult::ErrorRuntime(` _reason_ `,` _position_ `)>)`
|
||||
with the exception text captured by the first parameter.
|
||||
Exceptions thrown via `throw` in the script can be captured in Rust by matching
|
||||
`Err(Box<EvalAltResult::ErrorRuntime(reason, position)>)` with the exception text
|
||||
captured by `reason`.
|
||||
|
||||
```rust
|
||||
let result = engine.eval::<i64>(r#"
|
||||
|
@ -46,15 +46,22 @@ struct Config {
|
||||
### Make Shared Object
|
||||
|
||||
```rust
|
||||
let config: Rc<RefCell<Config>> = Rc::new(RefCell::new(Default::default()));
|
||||
pub type SharedConfig = Rc<RefCell<Config>>;
|
||||
```
|
||||
|
||||
Note: Use `Arc<Mutex<T>>` or `Arc<RwLock<T>>` when using the [`sync`] feature because the function
|
||||
must then be `Send + Sync`.
|
||||
|
||||
```rust
|
||||
let config: SharedConfig = Rc::new(RefCell::new(Default::default()));
|
||||
```
|
||||
|
||||
### Register Config API
|
||||
|
||||
The trick to building a Config API is to clone the shared configuration object and
|
||||
move it into each function registration as a closure.
|
||||
move it into each function registration via a closure.
|
||||
|
||||
It is not possible to use a [plugin module] to achieve this, so each function must
|
||||
Therefore, it is not possible to use a [plugin module] to achieve this, and each function must
|
||||
be registered one after another.
|
||||
|
||||
```rust
|
||||
|
@ -35,7 +35,7 @@ but only through exposing an abstract API primarily made up of functions.
|
||||
|
||||
Use this when the API is relatively simple and clean, and the number of functions is small enough.
|
||||
|
||||
For a complex API involving lots of functions, or an API that is object-based,
|
||||
For a complex API involving lots of functions, or an API that has a clear object structure,
|
||||
use the [Singleton Command Object]({{rootUrl}}/patterns/singleton.md) pattern instead.
|
||||
|
||||
|
||||
@ -59,15 +59,22 @@ impl EnergizerBunny {
|
||||
### Wrap API in Shared Object
|
||||
|
||||
```rust
|
||||
let bunny: Rc<RefCell<EnergizerBunny>> = Rc::new(RefCell::(EnergizerBunny::new()));
|
||||
pub type SharedBunny = Rc<RefCell<EnergizerBunny>>;
|
||||
```
|
||||
|
||||
Note: Use `Arc<Mutex<T>>` or `Arc<RwLock<T>>` when using the [`sync`] feature because the function
|
||||
must then be `Send + Sync`.
|
||||
|
||||
```rust
|
||||
let bunny: SharedBunny = Rc::new(RefCell::(EnergizerBunny::new()));
|
||||
```
|
||||
|
||||
### Register Control API
|
||||
|
||||
The trick to building a Control API is to clone the shared API object and
|
||||
move it into each function registration as a closure.
|
||||
move it into each function registration via a closure.
|
||||
|
||||
It is not possible to use a [plugin module] to achieve this, so each function must
|
||||
Therefore, it is not possible to use a [plugin module] to achieve this, and each function must
|
||||
be registered one after another.
|
||||
|
||||
```rust
|
||||
|
@ -41,7 +41,7 @@ wrapping the system in a shared, interior-mutated object.
|
||||
This is the other way which involves directly exposing the data structures of the external system
|
||||
as a name singleton object in the scripting space.
|
||||
|
||||
Use this when the API is complex and clearly object-based.
|
||||
Use this when the API is complex but has a clear object structure.
|
||||
|
||||
For a relatively simple API that is action-based and not object-based,
|
||||
use the [Control Layer]({{rootUrl}}/patterns/control.md) pattern instead.
|
||||
@ -68,13 +68,16 @@ impl EnergizerBunny {
|
||||
### Wrap Command Object Type as Shared
|
||||
|
||||
```rust
|
||||
let SharedBunnyType = Rc<RefCell<EnergizerBunny>>;
|
||||
pub type SharedBunny = Rc<RefCell<EnergizerBunny>>;
|
||||
```
|
||||
|
||||
Note: Use `Arc<Mutex<T>>` or `Arc<RwLock<T>>` when using the [`sync`] feature because the function
|
||||
must then be `Send + Sync`.
|
||||
|
||||
### Register the Custom Type
|
||||
|
||||
```rust
|
||||
engine.register_type_with_name::<SharedBunnyType>("EnergizerBunny");
|
||||
engine.register_type_with_name::<SharedBunny>("EnergizerBunny");
|
||||
```
|
||||
|
||||
### Develop a Plugin with Methods and Getters/Setters
|
||||
@ -82,18 +85,18 @@ engine.register_type_with_name::<SharedBunnyType>("EnergizerBunny");
|
||||
The easiest way to develop a complete set of API for a [custom type] is via a [plugin module].
|
||||
|
||||
```rust
|
||||
use rhai::plugins::*;
|
||||
use rhai::plugin::*;
|
||||
|
||||
#[export_module]
|
||||
pub mod bunny_api {
|
||||
pub const MAX_SPEED: i64 = 100;
|
||||
|
||||
#[rhai_fn(get = "power")]
|
||||
pub fn get_power(bunny: &mut SharedBunnyType) -> bool {
|
||||
pub fn get_power(bunny: &mut SharedBunny) -> bool {
|
||||
bunny.borrow().is_going()
|
||||
}
|
||||
#[rhai_fn(set = "power")]
|
||||
pub fn set_power(bunny: &mut SharedBunnyType, on: bool) {
|
||||
pub fn set_power(bunny: &mut SharedBunny, on: bool) {
|
||||
if on {
|
||||
if bunny.borrow().is_going() {
|
||||
println!("Still going...");
|
||||
@ -109,7 +112,7 @@ pub mod bunny_api {
|
||||
}
|
||||
}
|
||||
#[rhai_fn(get = "speed")]
|
||||
pub fn get_speed(bunny: &mut SharedBunnyType) -> i64 {
|
||||
pub fn get_speed(bunny: &mut SharedBunny) -> i64 {
|
||||
if bunny.borrow().is_going() {
|
||||
bunny.borrow().get_speed()
|
||||
} else {
|
||||
@ -117,7 +120,7 @@ pub mod bunny_api {
|
||||
}
|
||||
}
|
||||
#[rhai_fn(set = "speed", return_raw)]
|
||||
pub fn set_speed(bunny: &mut SharedBunnyType, speed: i64)
|
||||
pub fn set_speed(bunny: &mut SharedBunny, speed: i64)
|
||||
-> Result<Dynamic, Box<EvalAltResult>>
|
||||
{
|
||||
if speed <= 0 {
|
||||
@ -131,12 +134,12 @@ pub mod bunny_api {
|
||||
Ok(().into())
|
||||
}
|
||||
}
|
||||
pub fn turn_left(bunny: &mut SharedBunnyType) {
|
||||
pub fn turn_left(bunny: &mut SharedBunny) {
|
||||
if bunny.borrow().is_going() {
|
||||
bunny.borrow_mut().turn(true);
|
||||
}
|
||||
}
|
||||
pub fn turn_right(bunny: &mut SharedBunnyType) {
|
||||
pub fn turn_right(bunny: &mut SharedBunny) {
|
||||
if bunny.borrow().is_going() {
|
||||
bunny.borrow_mut().turn(false);
|
||||
}
|
||||
@ -149,7 +152,7 @@ engine.load_package(exported_module!(bunny_api));
|
||||
### Push Constant Command Object into Custom Scope
|
||||
|
||||
```rust
|
||||
let bunny: SharedBunnyType = Rc::new(RefCell::(EnergizerBunny::new()));
|
||||
let bunny: SharedBunny = Rc::new(RefCell::(EnergizerBunny::new()));
|
||||
|
||||
let mut scope = Scope::new();
|
||||
|
||||
|
@ -29,7 +29,7 @@ To register the plugin function, simply call `register_exported_fn!`. The name
|
||||
any text string, so it is possible to register _overloaded_ functions as well as operators.
|
||||
|
||||
```rust
|
||||
use rhai::plugins::*; // import macros
|
||||
use rhai::plugin::*; // import macros
|
||||
|
||||
#[export_fn]
|
||||
fn increment(num: &mut i64) {
|
||||
@ -55,7 +55,7 @@ A syntax error is generated if the function with `#[rhai_fn(return_raw)]` does n
|
||||
have the appropriate return type.
|
||||
|
||||
```rust
|
||||
use rhai::plugins::*; // import macros
|
||||
use rhai::plugin::*; // a "prelude" import for macros
|
||||
|
||||
#[export_fn]
|
||||
#[rhai_fn(return_raw)]
|
||||
|
@ -9,5 +9,5 @@ functionality.
|
||||
Instead of using the large `Engine::register_XXX` API or the parallel `Module::set_fn_XXX` API,
|
||||
a _plugin_ simplifies the work of creating and registering new functionality in an [`Engine`].
|
||||
|
||||
Plugins are processed via a set of procedural macros under the `rhai::plugins` module. These
|
||||
Plugins are processed via a set of procedural macros under the `rhai::plugin` module. These
|
||||
allow registering Rust functions directly in the Engine, or adding Rust modules as packages.
|
||||
|
@ -4,6 +4,20 @@ Export a Rust Module to Rhai
|
||||
{{#include ../links.md}}
|
||||
|
||||
|
||||
Prelude
|
||||
-------
|
||||
|
||||
When using the plugins system, the entire `rhai::plugin` module must be imported as a prelude
|
||||
because code generated will these imports.
|
||||
|
||||
```rust
|
||||
use rhai::plugin::*;
|
||||
```
|
||||
|
||||
|
||||
`#[export_module]` and `exported_module!`
|
||||
----------------------------------------
|
||||
|
||||
When applied to a Rust module, the `#[export_module]` attribute generates the necessary
|
||||
code and metadata to allow Rhai access to its public (i.e. marked `pub`) functions, constants
|
||||
and sub-modules.
|
||||
@ -14,18 +28,11 @@ and is custom fit to each exported item.
|
||||
This Rust module can then either be loaded into an [`Engine`] as a normal [module] or
|
||||
registered as a [custom package]. This is done by using the `exported_module!` macro.
|
||||
|
||||
|
||||
`#[export_module]` and `exported_module!`
|
||||
----------------------------------------
|
||||
|
||||
Apply `#[export_module]` onto a Rust module to register automatically construct a Rhai [module],
|
||||
which can then be loaded into an [`Engine`].
|
||||
|
||||
All `pub` functions become registered functions, all `pub` constants become [module] constant variables,
|
||||
and all sub-modules become Rhai sub-modules.
|
||||
|
||||
```rust
|
||||
use rhai::plugins::*; // a "prelude" import for macros
|
||||
use rhai::plugin::*; // a "prelude" import for macros
|
||||
|
||||
#[export_module]
|
||||
mod my_module {
|
||||
@ -117,7 +124,7 @@ Operators (which require function names that are not valid for Rust) can also be
|
||||
Registering the same function name with the same parameter types will cause a parsing error.
|
||||
|
||||
```rust
|
||||
use rhai::plugins::*; // a "prelude" import for macros
|
||||
use rhai::plugin::*; // a "prelude" import for macros
|
||||
|
||||
#[export_module]
|
||||
mod my_module {
|
||||
@ -147,7 +154,7 @@ Functions can be marked as [getters/setters] and [indexers] for [custom types] v
|
||||
attribute, which is applied on a function level.
|
||||
|
||||
```rust
|
||||
use rhai::plugins::*; // a "prelude" import for macros
|
||||
use rhai::plugin::*; // a "prelude" import for macros
|
||||
|
||||
#[export_module]
|
||||
mod my_module {
|
||||
@ -188,7 +195,7 @@ This is especially useful for the `name = "..."`, `get = "..."` and `set = "..."
|
||||
to give multiple alternative names to the same function.
|
||||
|
||||
```rust
|
||||
use rhai::plugins::*; // a "prelude" import for macros
|
||||
use rhai::plugin::*; // a "prelude" import for macros
|
||||
|
||||
#[export_module]
|
||||
mod my_module {
|
||||
@ -221,7 +228,7 @@ A syntax error is generated if the function with `#[rhai_fn(return_raw)]` does n
|
||||
have the appropriate return type.
|
||||
|
||||
```rust
|
||||
use rhai::plugins::*; // a "prelude" import for macros
|
||||
use rhai::plugin::*; // a "prelude" import for macros
|
||||
|
||||
#[export_module]
|
||||
mod my_module {
|
||||
|
@ -3,8 +3,16 @@ Disable Custom Types
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
|
||||
`no_object` Feature
|
||||
-------------------
|
||||
|
||||
The custom types API `register_type`, `register_type_with_name`, `register_get`, `register_get_result`,
|
||||
`register_set`, `register_set_result` and `register_get_set` are not available under [`no_object`].
|
||||
|
||||
|
||||
`no_index` Feature
|
||||
------------------
|
||||
|
||||
The indexers API `register_indexer_get`, `register_indexer_get_result`, `register_indexer_set`,
|
||||
`register_indexer_set_result`, and `register_indexer_get_set` are also not available under [`no_index`].
|
||||
|
@ -11,7 +11,7 @@ Getters and setters are disabled when the [`no_object`] feature is used.
|
||||
|
||||
| `Engine` API | Description | Return Value of Function |
|
||||
| --------------------- | ------------------------------------------------- | :-----------------------------------: |
|
||||
| `register_get` | register a getter | _any_ |
|
||||
| `register_get` | register a getter | _any_ `T: Clone` |
|
||||
| `register_set` | register a setter | _none_ |
|
||||
| `register_get_set` | short-hand to register both a getter and a setter | _none_ |
|
||||
| `register_get_result` | register a getter | `Result<Dynamic, Box<EvalAltResult>>` |
|
||||
|
@ -15,7 +15,7 @@ Indexers are disabled when the [`no_index`] feature is used.
|
||||
|
||||
| `Engine` API | Description | Return Value of Function |
|
||||
| ----------------------------- | -------------------------------------------------------- | :-----------------------------------: |
|
||||
| `register_indexer_get` | register an index getter | _any_ |
|
||||
| `register_indexer_get` | register an index getter | _any_ `T: Clone` |
|
||||
| `register_indexer_set` | register an index setter | _none_ |
|
||||
| `register_indexer_get_set` | short-hand to register both an index getter and a setter | _none_ |
|
||||
| `register_indexer_get_result` | register an index getter | `Result<Dynamic, Box<EvalAltResult>>` |
|
||||
|
@ -6,16 +6,23 @@ Operator Overloading
|
||||
In Rhai, a lot of functionalities are actually implemented as functions, including basic operations
|
||||
such as arithmetic calculations.
|
||||
|
||||
For example, in the expression "`a + b`", the `+` operator is _not_ built in, but calls a function named "`+`" instead!
|
||||
For example, in the expression "`a + b`", the `+` operator calls a function named "`+`"!
|
||||
|
||||
```rust
|
||||
let x = a + b;
|
||||
|
||||
let x = +(a, b); // <- the above is equivalent to this function call
|
||||
```
|
||||
|
||||
Similarly, comparison operators including `==`, `!=` etc. are all implemented as functions,
|
||||
with the stark exception of `&&` and `||`. Because they [_short-circuit_]({{rootUrl}}/language/logic.md#boolean-operators),
|
||||
`&&` and `||` are handled specially and _not_ via a function; as a result, overriding them has no effect at all.
|
||||
with the stark exception of `&&` and `||`.
|
||||
|
||||
|
||||
`&&` and `||` Cannot Be Overloaded
|
||||
---------------------------------
|
||||
|
||||
Because they [_short-circuit_]({{rootUrl}}/language/logic.md#boolean-operators), `&&` and `||` are
|
||||
handled specially and _not_ via a function; as a result, overriding them has no effect at all.
|
||||
|
||||
|
||||
Overload Operator via Rust Function
|
||||
|
@ -60,7 +60,7 @@ def_package!(rhai:MyPackage:"My own personal super package", module, {
|
||||
Create a Custom Package from a Plugin Module
|
||||
-------------------------------------------
|
||||
|
||||
By far the easiest way to create a custom module is to call `rhai::plugins::combine_with_exported_module!`
|
||||
By far the easiest way to create a custom module is to call `rhai::plugin::combine_with_exported_module!`
|
||||
from within `rhai::def_package!` which simply merges in all the functions defined within a [plugin module].
|
||||
|
||||
In fact, this exactly is how Rhai's built-in packages, such as `BasicMathPackage`, are implemented.
|
||||
@ -113,8 +113,8 @@ def_package!(rhai:MyPackage:"My own personal super package", module, {
|
||||
//
|
||||
// The sub-module 'my_sub_module' is flattened and its functions registered at the top level.
|
||||
//
|
||||
// The text string name in the middle parameter can be anything and is reserved for future use;
|
||||
// it is recommended to be an ID string that uniquely identifies the module.
|
||||
// The text string name in the second parameter can be anything and is reserved for future use;
|
||||
// it is recommended to be an ID string that uniquely identifies the plugin module.
|
||||
//
|
||||
// The constant variable, 'MY_NUMBER', is ignored.
|
||||
//
|
||||
|
@ -3,7 +3,8 @@ Load a Plugin Module as a Package
|
||||
|
||||
{{#include ../../links.md}}
|
||||
|
||||
[Plugin modules] can be loaded as a package just like a normal [module].
|
||||
[Plugin modules] can be loaded as a package just like a normal [module]
|
||||
via the `exported_module!` macro.
|
||||
|
||||
```rust
|
||||
use rhai::Engine;
|
||||
|
@ -35,13 +35,12 @@ engine.register_raw_fn(
|
||||
// Therefore, get a '&mut' reference to the first argument _last_.
|
||||
// Alternatively, use `args.split_first_mut()` etc. to split the slice first.
|
||||
|
||||
let y: i64 = *args[1].read_lock::<i64>() // get a reference to the second argument
|
||||
.unwrap(); // then copying it because it is a primary type
|
||||
let y = *args[1].read_lock::<i64>().unwrap(); // get a reference to the second argument
|
||||
// then copy it because it is a primary type
|
||||
|
||||
let y: i64 = std::mem::take(args[1]).cast::<i64>(); // alternatively, directly 'consume' it
|
||||
let y = std::mem::take(args[1]).cast::<i64>(); // alternatively, directly 'consume' it
|
||||
|
||||
let x: &mut i64 = args[0].write_lock::<i64>() // get a '&mut' reference to the
|
||||
.unwrap(); // first argument
|
||||
let x = args[0].write_lock::<i64>().unwrap(); // get a '&mut' reference to the first argument
|
||||
|
||||
*x += y; // perform the action
|
||||
|
||||
@ -51,7 +50,7 @@ engine.register_raw_fn(
|
||||
|
||||
// The above is the same as (in fact, internally they are equivalent):
|
||||
|
||||
engine.register_fn("increment_by", |x: &mut i64, y: i64| x += y);
|
||||
engine.register_fn("increment_by", |x: &mut i64, y: i64| *x += y);
|
||||
```
|
||||
|
||||
|
||||
@ -153,7 +152,8 @@ is a _shared value_ created by [capturing][automatic currying] variables from [c
|
||||
Shared values are implemented as `Rc<RefCell<Dynamic>>` (`Arc<RwLock<Dynamic>>` under [`sync`]).
|
||||
|
||||
If the value is _not_ a shared value, or if running under [`no_closure`] where there is
|
||||
no [capturing][automatic currying], this API de-sugars to a simple `downcast_ref` and `downcast_mut`.
|
||||
no [capturing][automatic currying], this API de-sugars to a simple `Dynamic::downcast_ref` and
|
||||
`Dynamic::downcast_mut`.
|
||||
|
||||
If the value is a shared value, then it is first locked and the returned lock guard
|
||||
then allows access to the underlying value in the specified type.
|
||||
@ -171,9 +171,9 @@ to partition the slice:
|
||||
let (first, rest) = args.split_first_mut().unwrap();
|
||||
|
||||
// Mutable reference to the first parameter
|
||||
let this_ptr: &mut A = &mut *first.write_lock::<A>().unwrap();
|
||||
let this_ptr = &mut *first.write_lock::<A>().unwrap();
|
||||
|
||||
// Immutable reference to the second value parameter
|
||||
// This can be mutable but there is no point because the parameter is passed by value
|
||||
let value_ref: &B = &*rest[0].read_lock::<B>().unwrap();
|
||||
let value_ref = &*rest[0].read_lock::<B>().unwrap();
|
||||
```
|
||||
|
@ -5,9 +5,10 @@ Traits
|
||||
|
||||
A number of traits, under the `rhai::` module namespace, provide additional functionalities.
|
||||
|
||||
| Trait | Description | Methods |
|
||||
| ------------------ | ---------------------------------------------------------------------------------------- | --------------------------------------- |
|
||||
| `RegisterFn` | trait for registering functions | `register_fn` |
|
||||
| `RegisterResultFn` | trait for registering fallible functions returning `Result<Dynamic, Box<EvalAltResult>>` | `register_result_fn` |
|
||||
| `Func` | trait for creating Rust closures from script | `create_from_ast`, `create_from_script` |
|
||||
| `ModuleResolver` | trait implemented by module resolution services | `resolve` |
|
||||
| Trait | Description | Methods |
|
||||
| ------------------------ | ------------------------------------------------------------------ | --------------------------------------------------------------------- |
|
||||
| `RegisterFn` | trait for registering functions | `register_fn` |
|
||||
| `RegisterResultFn` | trait for registering [fallible functions] | `register_result_fn` |
|
||||
| `Func` | trait for creating Rust closures from script | `create_from_ast`, `create_from_script` |
|
||||
| `ModuleResolver` | trait implemented by [module resolution][module resolver] services | `resolve` |
|
||||
| `plugin::PluginFunction` | trait implemented by [plugin] functions | `call`, `is_method_call`, `is_variadic`, `clone_boxed`, `input_types` |
|
||||
|
@ -1504,7 +1504,7 @@ impl Engine {
|
||||
let mut arg_values = args.into_vec();
|
||||
let mut args: StaticVec<_> = arg_values.as_mut().iter_mut().collect();
|
||||
|
||||
let result = self.call_fn_dynamic_raw(scope, ast, name, &mut None, args.as_mut())?;
|
||||
let result = self.call_fn_dynamic_raw(scope, ast.lib(), name, &mut None, args.as_mut())?;
|
||||
|
||||
let typ = self.map_type_name(result.type_name());
|
||||
|
||||
@ -1578,7 +1578,7 @@ impl Engine {
|
||||
) -> FuncReturn<Dynamic> {
|
||||
let mut args: StaticVec<_> = arg_values.as_mut().iter_mut().collect();
|
||||
|
||||
self.call_fn_dynamic_raw(scope, lib, name, &mut this_ptr, args.as_mut())
|
||||
self.call_fn_dynamic_raw(scope, lib.as_ref(), name, &mut this_ptr, args.as_mut())
|
||||
}
|
||||
|
||||
/// Call a script function defined in an `AST` with multiple `Dynamic` arguments.
|
||||
@ -1593,12 +1593,11 @@ impl Engine {
|
||||
pub(crate) fn call_fn_dynamic_raw(
|
||||
&self,
|
||||
scope: &mut Scope,
|
||||
lib: impl AsRef<Module>,
|
||||
lib: &Module,
|
||||
name: &str,
|
||||
this_ptr: &mut Option<&mut Dynamic>,
|
||||
args: &mut [&mut Dynamic],
|
||||
) -> FuncReturn<Dynamic> {
|
||||
let lib = lib.as_ref();
|
||||
let fn_def = get_script_function_by_signature(lib, name, args.len(), true)
|
||||
.ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::none()))?;
|
||||
|
||||
|
@ -199,10 +199,10 @@ pub type FnAny =
|
||||
/// A standard function that gets an iterator from a type.
|
||||
pub type IteratorFn = fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>>;
|
||||
|
||||
#[cfg(feature = "sync")]
|
||||
pub type SharedPluginFunction = Arc<dyn PluginFunction + Send + Sync>;
|
||||
#[cfg(not(feature = "sync"))]
|
||||
pub type SharedPluginFunction = Rc<dyn PluginFunction>;
|
||||
pub type FnPlugin = dyn PluginFunction;
|
||||
#[cfg(feature = "sync")]
|
||||
pub type FnPlugin = dyn PluginFunction + Send + Sync;
|
||||
|
||||
/// A standard callback function.
|
||||
#[cfg(not(feature = "sync"))]
|
||||
@ -221,8 +221,8 @@ pub enum CallableFunction {
|
||||
Method(Shared<FnAny>),
|
||||
/// An iterator function.
|
||||
Iterator(IteratorFn),
|
||||
/// A plugin-defined function,
|
||||
Plugin(SharedPluginFunction),
|
||||
/// A plugin function,
|
||||
Plugin(Shared<FnPlugin>),
|
||||
/// A script-defined function.
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
Script(Shared<ScriptFnDef>),
|
||||
@ -300,7 +300,7 @@ impl CallableFunction {
|
||||
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) | Self::Plugin(_) => false,
|
||||
}
|
||||
}
|
||||
/// Is this a plugin-defined function?
|
||||
/// Is this a plugin function?
|
||||
pub fn is_plugin_fn(&self) -> bool {
|
||||
match self {
|
||||
Self::Plugin(_) => true,
|
||||
@ -389,9 +389,9 @@ impl CallableFunction {
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the `CallableFunction` is not `Plugin`.
|
||||
pub fn get_plugin_fn<'s>(&'s self) -> SharedPluginFunction {
|
||||
pub fn get_plugin_fn<'s>(&'s self) -> &FnPlugin {
|
||||
match self {
|
||||
Self::Plugin(f) => f.clone(),
|
||||
Self::Plugin(f) => f.as_ref(),
|
||||
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => unreachable!(),
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
@ -406,17 +406,9 @@ impl CallableFunction {
|
||||
pub fn from_method(func: Box<FnAny>) -> Self {
|
||||
Self::Method(func.into())
|
||||
}
|
||||
|
||||
#[cfg(feature = "sync")]
|
||||
/// Create a new `CallableFunction::Plugin`.
|
||||
pub fn from_plugin(plugin: impl PluginFunction + 'static + Send + Sync) -> Self {
|
||||
Self::Plugin(Arc::new(plugin))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "sync"))]
|
||||
/// Create a new `CallableFunction::Plugin`.
|
||||
pub fn from_plugin(plugin: impl PluginFunction + 'static) -> Self {
|
||||
Self::Plugin(Rc::new(plugin))
|
||||
pub fn from_plugin(func: impl PluginFunction + 'static + SendSync) -> Self {
|
||||
Self::Plugin((Box::new(func) as Box<FnPlugin>).into())
|
||||
}
|
||||
}
|
||||
|
||||
@ -445,3 +437,15 @@ impl From<Shared<ScriptFnDef>> for CallableFunction {
|
||||
Self::Script(_func)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PluginFunction + 'static + SendSync> From<T> for CallableFunction {
|
||||
fn from(func: T) -> Self {
|
||||
Self::from_plugin(func)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Shared<FnPlugin>> for CallableFunction {
|
||||
fn from(func: Shared<FnPlugin>) -> Self {
|
||||
Self::Plugin(func.into())
|
||||
}
|
||||
}
|
||||
|
@ -7,118 +7,12 @@ use crate::engine::Engine;
|
||||
use crate::fn_native::{CallableFunction, FnAny, FnCallArgs, SendSync};
|
||||
use crate::module::Module;
|
||||
use crate::parser::FnAccess;
|
||||
use crate::plugin::Plugin;
|
||||
use crate::r#unsafe::unsafe_cast_box;
|
||||
use crate::result::EvalAltResult;
|
||||
use crate::utils::ImmutableString;
|
||||
|
||||
use crate::stdlib::{any::TypeId, boxed::Box, mem, string::String};
|
||||
|
||||
/// A trait to register custom plugins with the `Engine`.
|
||||
///
|
||||
/// A plugin consists of a number of functions. All functions will be registered with the engine.
|
||||
pub trait RegisterPlugin<PL: crate::plugin::Plugin> {
|
||||
/// Allow extensions of the engine's behavior.
|
||||
///
|
||||
/// This can include importing modules, registering functions to the global name space, and
|
||||
/// more.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # #[cfg(not(feature = "no_float"))]
|
||||
/// use rhai::FLOAT as NUMBER;
|
||||
/// # #[cfg(feature = "no_float")]
|
||||
/// use rhai::INT as NUMBER;
|
||||
/// # #[cfg(not(feature = "no_module"))]
|
||||
/// use rhai::{Module, ModuleResolver, RegisterFn, RegisterPlugin};
|
||||
/// # #[cfg(not(feature = "no_module"))]
|
||||
/// use rhai::plugin::*;
|
||||
/// # #[cfg(not(feature = "no_module"))]
|
||||
/// use rhai::module_resolvers::*;
|
||||
///
|
||||
/// // A function we want to expose to Rhai.
|
||||
/// #[derive(Copy, Clone)]
|
||||
/// struct DistanceFunction();
|
||||
///
|
||||
/// # #[cfg(not(feature = "no_module"))]
|
||||
/// impl PluginFunction for DistanceFunction {
|
||||
/// fn is_method_call(&self) -> bool { false }
|
||||
/// fn is_varadic(&self) -> bool { false }
|
||||
///
|
||||
/// fn call(&self, args: &mut[&mut Dynamic]) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
/// let x1: NUMBER = std::mem::take(args[0]).clone().cast::<NUMBER>();
|
||||
/// let y1: NUMBER = std::mem::take(args[1]).clone().cast::<NUMBER>();
|
||||
/// let x2: NUMBER = std::mem::take(args[2]).clone().cast::<NUMBER>();
|
||||
/// let y2: NUMBER = std::mem::take(args[3]).clone().cast::<NUMBER>();
|
||||
/// # #[cfg(not(feature = "no_float"))]
|
||||
/// let square_sum = (y2 - y1).abs().powf(2.0) + (x2 -x1).abs().powf(2.0);
|
||||
/// # #[cfg(feature = "no_float")]
|
||||
/// let square_sum = (y2 - y1).abs().pow(2) + (x2 -x1).abs().pow(2);
|
||||
/// Ok(Dynamic::from(square_sum))
|
||||
/// }
|
||||
///
|
||||
/// fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
/// Box::new(DistanceFunction())
|
||||
/// }
|
||||
///
|
||||
/// fn input_types(&self) -> Box<[std::any::TypeId]> {
|
||||
/// vec![std::any::TypeId::of::<NUMBER>(),
|
||||
/// std::any::TypeId::of::<NUMBER>(),
|
||||
/// std::any::TypeId::of::<NUMBER>(),
|
||||
/// std::any::TypeId::of::<NUMBER>()].into_boxed_slice()
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // A simple custom plugin. This should not usually be done with hand-written code.
|
||||
/// #[derive(Copy, Clone)]
|
||||
/// pub struct AdvancedMathPlugin();
|
||||
///
|
||||
/// # #[cfg(not(feature = "no_module"))]
|
||||
/// impl Plugin for AdvancedMathPlugin {
|
||||
/// fn register_contents(self, engine: &mut Engine) {
|
||||
/// // Plugins are allowed to have side-effects on the engine.
|
||||
/// engine.register_fn("get_mystic_number", || { 42 as NUMBER });
|
||||
///
|
||||
/// // Main purpose: create a module to expose the functions to Rhai.
|
||||
/// //
|
||||
/// // This is currently a hack. There needs to be a better API here for "plugin"
|
||||
/// // modules.
|
||||
/// let mut m = Module::new();
|
||||
/// m.set_fn("euclidean_distance".to_string(), FnAccess::Public,
|
||||
/// &[std::any::TypeId::of::<NUMBER>(),
|
||||
/// std::any::TypeId::of::<NUMBER>(),
|
||||
/// std::any::TypeId::of::<NUMBER>(),
|
||||
/// std::any::TypeId::of::<NUMBER>()],
|
||||
/// CallableFunction::from_plugin(DistanceFunction()));
|
||||
/// let mut r = StaticModuleResolver::new();
|
||||
/// r.insert("Math::Advanced".to_string(), m);
|
||||
/// engine.set_module_resolver(Some(r));
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
///
|
||||
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||
///
|
||||
/// # #[cfg(not(feature = "no_module"))] {
|
||||
/// let mut engine = Engine::new();
|
||||
/// engine.register_plugin(AdvancedMathPlugin());
|
||||
///
|
||||
/// # #[cfg(feature = "no_float")]
|
||||
/// assert_eq!(engine.eval::<NUMBER>(
|
||||
/// r#"import "Math::Advanced" as math;
|
||||
/// let x = math::euclidean_distance(0, 1, 0, get_mystic_number()); x"#)?, 1681);
|
||||
/// # #[cfg(not(feature = "no_float"))]
|
||||
/// assert_eq!(engine.eval::<NUMBER>(
|
||||
/// r#"import "Math::Advanced" as math;
|
||||
/// let x = math::euclidean_distance(0.0, 1.0, 0.0, get_mystic_number()); x"#)?, 1681.0);
|
||||
/// # } // end cfg
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
fn register_plugin(&mut self, plugin: PL);
|
||||
}
|
||||
|
||||
/// Trait to register custom functions with the `Engine`.
|
||||
pub trait RegisterFn<FN, ARGS, RET> {
|
||||
/// Register a custom function with the `Engine`.
|
||||
@ -223,12 +117,6 @@ pub fn by_value<T: Variant + Clone>(data: &mut Dynamic) -> T {
|
||||
}
|
||||
}
|
||||
|
||||
impl<PL: Plugin> RegisterPlugin<PL> for Engine {
|
||||
fn register_plugin(&mut self, plugin: PL) {
|
||||
plugin.register_contents(self);
|
||||
}
|
||||
}
|
||||
|
||||
/// This macro creates a closure wrapping a registered function.
|
||||
macro_rules! make_func {
|
||||
($fn:ident : $map:expr ; $($par:ident => $let:stmt => $convert:expr => $arg:expr),*) => {
|
||||
|
@ -86,7 +86,7 @@ pub use any::Dynamic;
|
||||
pub use engine::Engine;
|
||||
pub use error::{ParseError, ParseErrorType};
|
||||
pub use fn_native::{FnPtr, IteratorFn};
|
||||
pub use fn_register::{RegisterFn, RegisterPlugin, RegisterResultFn};
|
||||
pub use fn_register::{RegisterFn, RegisterResultFn};
|
||||
pub use module::Module;
|
||||
pub use parser::{ImmutableString, AST, INT};
|
||||
pub use result::EvalAltResult;
|
||||
|
@ -154,6 +154,25 @@ impl Module {
|
||||
}
|
||||
}
|
||||
|
||||
/// Is the module empty?
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use rhai::Module;
|
||||
///
|
||||
/// let module = Module::new();
|
||||
/// assert!(module.is_empty());
|
||||
/// ```
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.functions.is_empty()
|
||||
&& self.all_functions.is_empty()
|
||||
&& self.variables.is_empty()
|
||||
&& self.all_variables.is_empty()
|
||||
&& self.modules.is_empty()
|
||||
&& self.type_iterators.is_empty()
|
||||
}
|
||||
|
||||
/// Clone the module, optionally skipping the index.
|
||||
fn do_clone(&self, clone_index: bool) -> Self {
|
||||
Self {
|
||||
@ -1078,10 +1097,18 @@ impl Module {
|
||||
/// Combine another module into this module.
|
||||
/// The other module is consumed to merge into this module.
|
||||
pub fn combine(&mut self, other: Self) -> &mut Self {
|
||||
self.modules.extend(other.modules.into_iter());
|
||||
self.variables.extend(other.variables.into_iter());
|
||||
self.functions.extend(other.functions.into_iter());
|
||||
self.type_iterators.extend(other.type_iterators.into_iter());
|
||||
if !other.modules.is_empty() {
|
||||
self.modules.extend(other.modules.into_iter());
|
||||
}
|
||||
if !other.variables.is_empty() {
|
||||
self.variables.extend(other.variables.into_iter());
|
||||
}
|
||||
if !other.functions.is_empty() {
|
||||
self.functions.extend(other.functions.into_iter());
|
||||
}
|
||||
if !other.type_iterators.is_empty() {
|
||||
self.type_iterators.extend(other.type_iterators.into_iter());
|
||||
}
|
||||
self.all_functions.clear();
|
||||
self.all_variables.clear();
|
||||
self.indexed = false;
|
||||
@ -1092,13 +1119,20 @@ impl Module {
|
||||
/// The other module is consumed to merge into this module.
|
||||
/// Sub-modules are flattened onto the root module, with higher level overriding lower level.
|
||||
pub fn combine_flatten(&mut self, other: Self) -> &mut Self {
|
||||
other.modules.into_iter().for_each(|(_, m)| {
|
||||
self.combine_flatten(m);
|
||||
});
|
||||
|
||||
self.variables.extend(other.variables.into_iter());
|
||||
self.functions.extend(other.functions.into_iter());
|
||||
self.type_iterators.extend(other.type_iterators.into_iter());
|
||||
if !other.modules.is_empty() {
|
||||
other.modules.into_iter().for_each(|(_, m)| {
|
||||
self.combine_flatten(m);
|
||||
});
|
||||
}
|
||||
if !other.variables.is_empty() {
|
||||
self.variables.extend(other.variables.into_iter());
|
||||
}
|
||||
if !other.functions.is_empty() {
|
||||
self.functions.extend(other.functions.into_iter());
|
||||
}
|
||||
if !other.type_iterators.is_empty() {
|
||||
self.type_iterators.extend(other.type_iterators.into_iter());
|
||||
}
|
||||
self.all_functions.clear();
|
||||
self.all_variables.clear();
|
||||
self.indexed = false;
|
||||
@ -1117,36 +1151,42 @@ impl Module {
|
||||
mut _filter: &mut impl FnMut(FnAccess, &str, usize) -> bool,
|
||||
) -> &mut Self {
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
for (k, v) in &other.modules {
|
||||
let mut m = Self::new();
|
||||
m.merge_filtered(v, _filter);
|
||||
self.modules.insert(k.clone(), m);
|
||||
if !other.modules.is_empty() {
|
||||
for (k, v) in &other.modules {
|
||||
let mut m = Self::new();
|
||||
m.merge_filtered(v, _filter);
|
||||
self.modules.insert(k.clone(), m);
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "no_function")]
|
||||
if !other.modules.is_empty() {
|
||||
self.modules
|
||||
.extend(other.modules.iter().map(|(k, v)| (k.clone(), v.clone())));
|
||||
}
|
||||
if !other.variables.is_empty() {
|
||||
self.variables
|
||||
.extend(other.variables.iter().map(|(k, v)| (k.clone(), v.clone())));
|
||||
}
|
||||
if !other.functions.is_empty() {
|
||||
self.functions.extend(
|
||||
other
|
||||
.functions
|
||||
.iter()
|
||||
.filter(|(_, (_, _, _, _, v))| match v {
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
CallableFunction::Script(f) => {
|
||||
_filter(f.access, f.name.as_str(), f.params.len())
|
||||
}
|
||||
_ => true,
|
||||
})
|
||||
.map(|(&k, v)| (k, v.clone())),
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "no_function")]
|
||||
self.modules
|
||||
.extend(other.modules.iter().map(|(k, v)| (k.clone(), v.clone())));
|
||||
|
||||
self.variables
|
||||
.extend(other.variables.iter().map(|(k, v)| (k.clone(), v.clone())));
|
||||
|
||||
self.functions.extend(
|
||||
other
|
||||
.functions
|
||||
.iter()
|
||||
.filter(|(_, (_, _, _, _, v))| match v {
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
CallableFunction::Script(f) => {
|
||||
_filter(f.access, f.name.as_str(), f.params.len())
|
||||
}
|
||||
_ => true,
|
||||
})
|
||||
.map(|(&k, v)| (k, v.clone())),
|
||||
);
|
||||
|
||||
self.type_iterators
|
||||
.extend(other.type_iterators.iter().map(|(&k, v)| (k, v.clone())));
|
||||
|
||||
if !other.type_iterators.is_empty() {
|
||||
self.type_iterators
|
||||
.extend(other.type_iterators.iter().map(|(&k, v)| (k, v.clone())));
|
||||
}
|
||||
self.all_functions.clear();
|
||||
self.all_variables.clear();
|
||||
self.indexed = false;
|
||||
@ -1280,13 +1320,21 @@ impl Module {
|
||||
name,
|
||||
num_args,
|
||||
move |engine: &Engine, lib: &Module, args: &mut [&mut Dynamic]| {
|
||||
let mut lib_merged = lib.clone();
|
||||
lib_merged.merge(&ast_lib);
|
||||
let mut lib_merged;
|
||||
|
||||
let unified_lib = if lib.is_empty() {
|
||||
// In the special case of the main script not defining any function
|
||||
&ast_lib
|
||||
} else {
|
||||
lib_merged = lib.clone();
|
||||
lib_merged.merge(&ast_lib);
|
||||
&lib_merged
|
||||
};
|
||||
|
||||
engine
|
||||
.call_fn_dynamic_raw(
|
||||
&mut Scope::new(),
|
||||
&lib_merged,
|
||||
&unified_lib,
|
||||
&fn_name,
|
||||
&mut None,
|
||||
args,
|
||||
|
@ -1,42 +1,38 @@
|
||||
//! Module defining plugins in Rhai for use by plugin authors.
|
||||
//! Module defining macros for developing _plugins_.
|
||||
|
||||
pub use crate::{
|
||||
fn_native::CallableFunction, stdlib::any::TypeId, stdlib::boxed::Box, stdlib::format,
|
||||
stdlib::mem, stdlib::string::ToString, stdlib::vec as new_vec, stdlib::vec::Vec, Dynamic,
|
||||
Engine, EvalAltResult, FnAccess, ImmutableString, Module, RegisterResultFn,
|
||||
};
|
||||
pub use crate::any::Dynamic;
|
||||
pub use crate::engine::Engine;
|
||||
pub use crate::fn_native::CallableFunction;
|
||||
pub use crate::fn_register::{RegisterFn, RegisterResultFn};
|
||||
pub use crate::module::Module;
|
||||
pub use crate::parser::FnAccess;
|
||||
pub use crate::result::EvalAltResult;
|
||||
pub use crate::utils::ImmutableString;
|
||||
|
||||
pub use crate::stdlib::{any::TypeId, boxed::Box, format, mem, string::ToString, vec as new_vec};
|
||||
|
||||
#[cfg(not(features = "no_module"))]
|
||||
pub use rhai_codegen::*;
|
||||
#[cfg(features = "no_module")]
|
||||
pub use rhai_codegen::{export_fn, register_exported_fn};
|
||||
|
||||
#[cfg(features = "sync")]
|
||||
/// Represents an externally-written plugin for the Rhai interpreter.
|
||||
/// Trait implemented by a _plugin function_.
|
||||
/// This trait should not be used directly.
|
||||
///
|
||||
/// This trait should not be used directly. Use the `#[plugin]` procedural attribute instead.
|
||||
pub trait Plugin: Send {
|
||||
fn register_contents(self, engine: &mut Engine);
|
||||
}
|
||||
|
||||
#[cfg(not(features = "sync"))]
|
||||
/// Represents an externally-written plugin for the Rhai interpreter.
|
||||
///
|
||||
/// This trait should not be used directly. Use the `#[plugin]` procedural attribute instead.
|
||||
pub trait Plugin: Send + Sync {
|
||||
fn register_contents(self, engine: &mut Engine);
|
||||
}
|
||||
|
||||
/// Represents a function that is statically defined within a plugin.
|
||||
///
|
||||
/// This trait should not be used directly. Use the `#[plugin]` procedural attribute instead.
|
||||
/// Use the `#[export_module]` and `#[export_fn]` procedural attributes instead.
|
||||
pub trait PluginFunction {
|
||||
fn is_method_call(&self) -> bool;
|
||||
fn is_varadic(&self) -> bool;
|
||||
|
||||
/// Call the plugin function with the arguments provided.
|
||||
fn call(&self, args: &mut [&mut Dynamic]) -> Result<Dynamic, Box<EvalAltResult>>;
|
||||
|
||||
/// Is this plugin function a method?
|
||||
fn is_method_call(&self) -> bool;
|
||||
|
||||
/// Is this plugin function variadic?
|
||||
fn is_variadic(&self) -> bool;
|
||||
|
||||
/// Convert a plugin function into a boxed trait object.
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction>;
|
||||
|
||||
/// Return a boxed slice of type ID's of the function's parameters.
|
||||
fn input_types(&self) -> Box<[TypeId]>;
|
||||
}
|
||||
|
@ -17,11 +17,6 @@ use crate::stdlib::{
|
||||
string::{String, ToString},
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "sync"))]
|
||||
use crate::stdlib::rc::Rc;
|
||||
#[cfg(feature = "sync")]
|
||||
use crate::stdlib::sync::Arc;
|
||||
|
||||
/// A general expression evaluation trait object.
|
||||
#[cfg(not(feature = "sync"))]
|
||||
pub type FnCustomSyntaxEval = dyn Fn(
|
||||
@ -175,10 +170,7 @@ impl Engine {
|
||||
|
||||
let syntax = CustomSyntax {
|
||||
segments,
|
||||
#[cfg(not(feature = "sync"))]
|
||||
func: Rc::new(func),
|
||||
#[cfg(feature = "sync")]
|
||||
func: Arc::new(func),
|
||||
func: (Box::new(func) as Box<FnCustomSyntaxEval>).into(),
|
||||
scope_delta,
|
||||
};
|
||||
|
||||
|
@ -61,7 +61,8 @@ impl BuildHasher for StraightHasherBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate a `u64` hash key from a module-qualified function name and parameter types.
|
||||
/// [INTERNALS] Calculate a `u64` hash key from a module-qualified function name and parameter types.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// Module names are passed in via `&str` references from an iterator.
|
||||
/// Parameter types are passed in via `TypeId` values from an iterator.
|
||||
|
@ -237,6 +237,9 @@ fn test_module_from_ast() -> Result<(), Box<EvalAltResult>> {
|
||||
fn add_len(x, y) {
|
||||
x + len(y)
|
||||
}
|
||||
fn cross_call(x) {
|
||||
calc(x)
|
||||
}
|
||||
private fn hidden() {
|
||||
throw "you shouldn't see me!";
|
||||
}
|
||||
@ -285,6 +288,10 @@ fn test_module_from_ast() -> Result<(), Box<EvalAltResult>> {
|
||||
engine.eval::<INT>(r#"import "testing" as ttt; ttt::calc(999)"#)?,
|
||||
1000
|
||||
);
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(r#"import "testing" as ttt; ttt::cross_call(999)"#)?,
|
||||
1000
|
||||
);
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(r#"import "testing" as ttt; ttt::add_len(ttt::foo, ttt::hello)"#)?,
|
||||
59
|
||||
|
Loading…
Reference in New Issue
Block a user