diff --git a/README.md b/README.md index b8b58cf1..55acc262 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ Optional features | `only_i32` | Set the system integer type to `i32` and disable all other integer types. `INT` is set to `i32`. | | `only_i64` | Set the system integer type to `i64` and disable all other integer types. `INT` is set to `i64`. | | `no_std` | Build for `no-std`. Notice that additional dependencies will be pulled in to replace `std` features. | -| `sync` | Restrict all values types to those that are `Send + Sync`. Under this feature, [`Scope`] and `AST` are both `Send + Sync`. | +| `sync` | Restrict all values types to those that are `Send + Sync`. Under this feature, `Engine`, [`Scope`] and `AST` are all `Send + Sync`. | By default, Rhai includes all the standard functionalities in a small, tight package. Most features are here to opt-**out** of certain functionalities that are not needed. Excluding unneeded functionalities can result in smaller, faster builds as well as less bugs due to a more restricted language. diff --git a/src/api.rs b/src/api.rs index b3acfa79..6b6cf9bd 100644 --- a/src/api.rs +++ b/src/api.rs @@ -22,6 +22,44 @@ use crate::stdlib::{ #[cfg(not(feature = "no_std"))] use crate::stdlib::{fs::File, io::prelude::*, path::PathBuf}; +// Define callback function types +#[cfg(feature = "sync")] +pub trait ObjectGetCallback: Fn(&mut T) -> U + Send + Sync + 'static {} +#[cfg(feature = "sync")] +impl U + Send + Sync + 'static, T, U> ObjectGetCallback for F {} + +#[cfg(not(feature = "sync"))] +pub trait ObjectGetCallback: Fn(&mut T) -> U + 'static {} +#[cfg(not(feature = "sync"))] +impl U + 'static, T, U> ObjectGetCallback for F {} + +#[cfg(feature = "sync")] +pub trait ObjectSetCallback: Fn(&mut T, U) + Send + Sync + 'static {} +#[cfg(feature = "sync")] +impl ObjectSetCallback for F {} + +#[cfg(not(feature = "sync"))] +pub trait ObjectSetCallback: Fn(&mut T, U) + 'static {} +#[cfg(not(feature = "sync"))] +impl ObjectSetCallback for F {} + +#[cfg(feature = "sync")] +pub trait IteratorCallback: + Fn(&Dynamic) -> Box> + Send + Sync + 'static +{ +} +#[cfg(feature = "sync")] +impl Box> + Send + Sync + 'static> IteratorCallback + for F +{ +} + +#[cfg(not(feature = "sync"))] +pub trait IteratorCallback: Fn(&Dynamic) -> Box> + 'static {} +#[cfg(not(feature = "sync"))] +impl Box> + 'static> IteratorCallback for F {} + +/// Engine public API impl<'e> Engine<'e> { /// Register a custom function. pub(crate) fn register_fn_raw(&mut self, fn_name: &str, args: Vec, f: Box) { @@ -126,10 +164,7 @@ impl<'e> Engine<'e> { /// Register an iterator adapter for a type with the `Engine`. /// This is an advanced feature. - pub fn register_iterator(&mut self, f: F) - where - F: Fn(&Dynamic) -> Box> + 'static, - { + pub fn register_iterator(&mut self, f: F) { self.type_iterators.insert(TypeId::of::(), Box::new(f)); } @@ -170,11 +205,12 @@ impl<'e> Engine<'e> { /// # } /// ``` #[cfg(not(feature = "no_object"))] - pub fn register_get( - &mut self, - name: &str, - callback: impl Fn(&mut T) -> U + 'static, - ) { + pub fn register_get(&mut self, name: &str, callback: F) + where + T: Any + Clone, + U: Any + Clone, + F: ObjectGetCallback, + { self.register_fn(&make_getter(name), callback); } @@ -215,11 +251,12 @@ impl<'e> Engine<'e> { /// # } /// ``` #[cfg(not(feature = "no_object"))] - pub fn register_set( - &mut self, - name: &str, - callback: impl Fn(&mut T, U) -> () + 'static, - ) { + pub fn register_set(&mut self, name: &str, callback: F) + where + T: Any + Clone, + U: Any + Clone, + F: ObjectSetCallback, + { self.register_fn(&make_setter(name), callback); } @@ -262,12 +299,13 @@ impl<'e> Engine<'e> { /// # } /// ``` #[cfg(not(feature = "no_object"))] - pub fn register_get_set( - &mut self, - name: &str, - get_fn: impl Fn(&mut T) -> U + 'static, - set_fn: impl Fn(&mut T, U) -> () + 'static, - ) { + pub fn register_get_set(&mut self, name: &str, get_fn: G, set_fn: S) + where + T: Any + Clone, + U: Any + Clone, + G: ObjectGetCallback, + S: ObjectSetCallback, + { self.register_get(name, get_fn); self.register_set(name, set_fn); } @@ -925,6 +963,11 @@ impl<'e> Engine<'e> { /// # Ok(()) /// # } /// ``` + #[cfg(feature = "sync")] + pub fn on_print(&mut self, callback: impl FnMut(&str) + Send + Sync + 'e) { + self.on_print = Box::new(callback); + } + #[cfg(not(feature = "sync"))] pub fn on_print(&mut self, callback: impl FnMut(&str) + 'e) { self.on_print = Box::new(callback); } @@ -949,6 +992,11 @@ impl<'e> Engine<'e> { /// # Ok(()) /// # } /// ``` + #[cfg(feature = "sync")] + pub fn on_debug(&mut self, callback: impl FnMut(&str) + Send + Sync + 'e) { + self.on_debug = Box::new(callback); + } + #[cfg(not(feature = "sync"))] pub fn on_debug(&mut self, callback: impl FnMut(&str) + 'e) { self.on_debug = Box::new(callback); } diff --git a/src/builtin.rs b/src/builtin.rs index d7f5840e..db6b5345 100644 --- a/src/builtin.rs +++ b/src/builtin.rs @@ -1,7 +1,7 @@ //! Helper module that allows registration of the _core library_ and //! _standard library_ of utility functions. -use crate::any::Any; +use crate::any::{Any, Dynamic}; use crate::engine::{Engine, FUNC_TO_STRING, KEYWORD_DEBUG, KEYWORD_PRINT}; use crate::fn_register::{RegisterDynamicFn, RegisterFn, RegisterResultFn}; use crate::parser::{Position, INT}; @@ -612,8 +612,9 @@ impl Engine<'_> { reg_fn1!(self, KEYWORD_DEBUG, to_debug, String, Array); // Register array iterator - self.register_iterator::(|a| { + self.register_iterator::(|a: &Dynamic| { Box::new(a.downcast_ref::().unwrap().clone().into_iter()) + as Box> }); } @@ -636,13 +637,13 @@ impl Engine<'_> { where Range: Iterator, { - engine.register_iterator::, _>(|a| { + engine.register_iterator::, _>(|a: &Dynamic| { Box::new( a.downcast_ref::>() .unwrap() .clone() .map(|n| n.into_dynamic()), - ) + ) as Box> }); } diff --git a/src/engine.rs b/src/engine.rs index 5230f5b8..235068a2 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -32,8 +32,14 @@ pub type Map = HashMap; pub type FnCallArgs<'a> = [&'a mut Variant]; +#[cfg(feature = "sync")] +pub type FnAny = dyn Fn(&mut FnCallArgs, Position) -> Result + Send + Sync; +#[cfg(not(feature = "sync"))] pub type FnAny = dyn Fn(&mut FnCallArgs, Position) -> Result; +#[cfg(feature = "sync")] +type IteratorFn = dyn Fn(&Dynamic) -> Box> + Send + Sync; +#[cfg(not(feature = "sync"))] type IteratorFn = dyn Fn(&Dynamic) -> Box>; pub const MAX_CALL_STACK_DEPTH: usize = 64; @@ -193,8 +199,15 @@ pub struct Engine<'e> { pub(crate) type_names: HashMap, /// Closure for implementing the `print` command. + #[cfg(feature = "sync")] + pub(crate) on_print: Box, + #[cfg(not(feature = "sync"))] pub(crate) on_print: Box, + /// Closure for implementing the `debug` command. + #[cfg(feature = "sync")] + pub(crate) on_debug: Box, + #[cfg(not(feature = "sync"))] pub(crate) on_debug: Box, /// Optimize the AST after compilation. @@ -280,6 +293,11 @@ fn extract_prop_from_setter(fn_name: &str) -> Option<&str> { impl Engine<'_> { /// Create a new `Engine` pub fn new() -> Self { + // fn abc(f: F) { + // f(); + // } + // abc(|| ()); + Default::default() } diff --git a/src/fn_register.rs b/src/fn_register.rs index cfc1b345..7ff2cc28 100644 --- a/src/fn_register.rs +++ b/src/fn_register.rs @@ -138,7 +138,13 @@ macro_rules! def_register { // ^ dereferencing function impl< $($par: Any + Clone,)* + + #[cfg(feature = "sync")] + FN: Fn($($param),*) -> RET + Send + Sync + 'static, + + #[cfg(not(feature = "sync"))] FN: Fn($($param),*) -> RET + 'static, + RET: Any > RegisterFn for Engine<'_> { @@ -171,6 +177,11 @@ macro_rules! def_register { impl< $($par: Any + Clone,)* + + #[cfg(feature = "sync")] + FN: Fn($($param),*) -> Dynamic + Send + Sync + 'static, + + #[cfg(not(feature = "sync"))] FN: Fn($($param),*) -> Dynamic + 'static, > RegisterDynamicFn for Engine<'_> { @@ -202,7 +213,12 @@ macro_rules! def_register { impl< $($par: Any + Clone,)* + + #[cfg(feature = "sync")] + FN: Fn($($param),*) -> Result + Send + Sync + 'static, + #[cfg(not(feature = "sync"))] FN: Fn($($param),*) -> Result + 'static, + RET: Any > RegisterResultFn for Engine<'_> {