Make Engine Send+Sync.

This commit is contained in:
Stephen Chung 2020-04-03 17:17:00 +08:00
parent 9d7091ad9d
commit a79f2a209c
5 changed files with 108 additions and 25 deletions

View File

@ -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_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`. | | `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. | | `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. 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. Excluding unneeded functionalities can result in smaller, faster builds as well as less bugs due to a more restricted language.

View File

@ -22,6 +22,44 @@ use crate::stdlib::{
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
use crate::stdlib::{fs::File, io::prelude::*, path::PathBuf}; use crate::stdlib::{fs::File, io::prelude::*, path::PathBuf};
// Define callback function types
#[cfg(feature = "sync")]
pub trait ObjectGetCallback<T, U>: Fn(&mut T) -> U + Send + Sync + 'static {}
#[cfg(feature = "sync")]
impl<F: Fn(&mut T) -> U + Send + Sync + 'static, T, U> ObjectGetCallback<T, U> for F {}
#[cfg(not(feature = "sync"))]
pub trait ObjectGetCallback<T, U>: Fn(&mut T) -> U + 'static {}
#[cfg(not(feature = "sync"))]
impl<F: Fn(&mut T) -> U + 'static, T, U> ObjectGetCallback<T, U> for F {}
#[cfg(feature = "sync")]
pub trait ObjectSetCallback<T, U>: Fn(&mut T, U) + Send + Sync + 'static {}
#[cfg(feature = "sync")]
impl<F: Fn(&mut T, U) + Send + Sync + 'static, T, U> ObjectSetCallback<T, U> for F {}
#[cfg(not(feature = "sync"))]
pub trait ObjectSetCallback<T, U>: Fn(&mut T, U) + 'static {}
#[cfg(not(feature = "sync"))]
impl<F: Fn(&mut T, U) + 'static, T, U> ObjectSetCallback<T, U> for F {}
#[cfg(feature = "sync")]
pub trait IteratorCallback:
Fn(&Dynamic) -> Box<dyn Iterator<Item = Dynamic>> + Send + Sync + 'static
{
}
#[cfg(feature = "sync")]
impl<F: Fn(&Dynamic) -> Box<dyn Iterator<Item = Dynamic>> + Send + Sync + 'static> IteratorCallback
for F
{
}
#[cfg(not(feature = "sync"))]
pub trait IteratorCallback: Fn(&Dynamic) -> Box<dyn Iterator<Item = Dynamic>> + 'static {}
#[cfg(not(feature = "sync"))]
impl<F: Fn(&Dynamic) -> Box<dyn Iterator<Item = Dynamic>> + 'static> IteratorCallback for F {}
/// Engine public API
impl<'e> Engine<'e> { impl<'e> Engine<'e> {
/// Register a custom function. /// Register a custom function.
pub(crate) fn register_fn_raw(&mut self, fn_name: &str, args: Vec<TypeId>, f: Box<FnAny>) { pub(crate) fn register_fn_raw(&mut self, fn_name: &str, args: Vec<TypeId>, f: Box<FnAny>) {
@ -126,10 +164,7 @@ impl<'e> Engine<'e> {
/// Register an iterator adapter for a type with the `Engine`. /// Register an iterator adapter for a type with the `Engine`.
/// This is an advanced feature. /// This is an advanced feature.
pub fn register_iterator<T: Any, F>(&mut self, f: F) pub fn register_iterator<T: Any, F: IteratorCallback>(&mut self, f: F) {
where
F: Fn(&Dynamic) -> Box<dyn Iterator<Item = Dynamic>> + 'static,
{
self.type_iterators.insert(TypeId::of::<T>(), Box::new(f)); self.type_iterators.insert(TypeId::of::<T>(), Box::new(f));
} }
@ -170,11 +205,12 @@ impl<'e> Engine<'e> {
/// # } /// # }
/// ``` /// ```
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
pub fn register_get<T: Any + Clone, U: Any + Clone>( pub fn register_get<T, U, F>(&mut self, name: &str, callback: F)
&mut self, where
name: &str, T: Any + Clone,
callback: impl Fn(&mut T) -> U + 'static, U: Any + Clone,
) { F: ObjectGetCallback<T, U>,
{
self.register_fn(&make_getter(name), callback); self.register_fn(&make_getter(name), callback);
} }
@ -215,11 +251,12 @@ impl<'e> Engine<'e> {
/// # } /// # }
/// ``` /// ```
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
pub fn register_set<T: Any + Clone, U: Any + Clone>( pub fn register_set<T, U, F>(&mut self, name: &str, callback: F)
&mut self, where
name: &str, T: Any + Clone,
callback: impl Fn(&mut T, U) -> () + 'static, U: Any + Clone,
) { F: ObjectSetCallback<T, U>,
{
self.register_fn(&make_setter(name), callback); self.register_fn(&make_setter(name), callback);
} }
@ -262,12 +299,13 @@ impl<'e> Engine<'e> {
/// # } /// # }
/// ``` /// ```
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
pub fn register_get_set<T: Any + Clone, U: Any + Clone>( pub fn register_get_set<T, U, G, S>(&mut self, name: &str, get_fn: G, set_fn: S)
&mut self, where
name: &str, T: Any + Clone,
get_fn: impl Fn(&mut T) -> U + 'static, U: Any + Clone,
set_fn: impl Fn(&mut T, U) -> () + 'static, G: ObjectGetCallback<T, U>,
) { S: ObjectSetCallback<T, U>,
{
self.register_get(name, get_fn); self.register_get(name, get_fn);
self.register_set(name, set_fn); self.register_set(name, set_fn);
} }
@ -925,6 +963,11 @@ impl<'e> Engine<'e> {
/// # Ok(()) /// # 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) { pub fn on_print(&mut self, callback: impl FnMut(&str) + 'e) {
self.on_print = Box::new(callback); self.on_print = Box::new(callback);
} }
@ -949,6 +992,11 @@ impl<'e> Engine<'e> {
/// # Ok(()) /// # 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) { pub fn on_debug(&mut self, callback: impl FnMut(&str) + 'e) {
self.on_debug = Box::new(callback); self.on_debug = Box::new(callback);
} }

View File

@ -1,7 +1,7 @@
//! Helper module that allows registration of the _core library_ and //! Helper module that allows registration of the _core library_ and
//! _standard library_ of utility functions. //! _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::engine::{Engine, FUNC_TO_STRING, KEYWORD_DEBUG, KEYWORD_PRINT};
use crate::fn_register::{RegisterDynamicFn, RegisterFn, RegisterResultFn}; use crate::fn_register::{RegisterDynamicFn, RegisterFn, RegisterResultFn};
use crate::parser::{Position, INT}; use crate::parser::{Position, INT};
@ -612,8 +612,9 @@ impl Engine<'_> {
reg_fn1!(self, KEYWORD_DEBUG, to_debug, String, Array); reg_fn1!(self, KEYWORD_DEBUG, to_debug, String, Array);
// Register array iterator // Register array iterator
self.register_iterator::<Array, _>(|a| { self.register_iterator::<Array, _>(|a: &Dynamic| {
Box::new(a.downcast_ref::<Array>().unwrap().clone().into_iter()) Box::new(a.downcast_ref::<Array>().unwrap().clone().into_iter())
as Box<dyn Iterator<Item = Dynamic>>
}); });
} }
@ -636,13 +637,13 @@ impl Engine<'_> {
where where
Range<T>: Iterator<Item = T>, Range<T>: Iterator<Item = T>,
{ {
engine.register_iterator::<Range<T>, _>(|a| { engine.register_iterator::<Range<T>, _>(|a: &Dynamic| {
Box::new( Box::new(
a.downcast_ref::<Range<T>>() a.downcast_ref::<Range<T>>()
.unwrap() .unwrap()
.clone() .clone()
.map(|n| n.into_dynamic()), .map(|n| n.into_dynamic()),
) ) as Box<dyn Iterator<Item = Dynamic>>
}); });
} }

View File

@ -32,8 +32,14 @@ pub type Map = HashMap<String, Dynamic>;
pub type FnCallArgs<'a> = [&'a mut Variant]; pub type FnCallArgs<'a> = [&'a mut Variant];
#[cfg(feature = "sync")]
pub type FnAny = dyn Fn(&mut FnCallArgs, Position) -> Result<Dynamic, EvalAltResult> + Send + Sync;
#[cfg(not(feature = "sync"))]
pub type FnAny = dyn Fn(&mut FnCallArgs, Position) -> Result<Dynamic, EvalAltResult>; pub type FnAny = dyn Fn(&mut FnCallArgs, Position) -> Result<Dynamic, EvalAltResult>;
#[cfg(feature = "sync")]
type IteratorFn = dyn Fn(&Dynamic) -> Box<dyn Iterator<Item = Dynamic>> + Send + Sync;
#[cfg(not(feature = "sync"))]
type IteratorFn = dyn Fn(&Dynamic) -> Box<dyn Iterator<Item = Dynamic>>; type IteratorFn = dyn Fn(&Dynamic) -> Box<dyn Iterator<Item = Dynamic>>;
pub const MAX_CALL_STACK_DEPTH: usize = 64; pub const MAX_CALL_STACK_DEPTH: usize = 64;
@ -193,8 +199,15 @@ pub struct Engine<'e> {
pub(crate) type_names: HashMap<String, String>, pub(crate) type_names: HashMap<String, String>,
/// Closure for implementing the `print` command. /// Closure for implementing the `print` command.
#[cfg(feature = "sync")]
pub(crate) on_print: Box<dyn FnMut(&str) + Send + Sync + 'e>,
#[cfg(not(feature = "sync"))]
pub(crate) on_print: Box<dyn FnMut(&str) + 'e>, pub(crate) on_print: Box<dyn FnMut(&str) + 'e>,
/// Closure for implementing the `debug` command. /// Closure for implementing the `debug` command.
#[cfg(feature = "sync")]
pub(crate) on_debug: Box<dyn FnMut(&str) + Send + Sync + 'e>,
#[cfg(not(feature = "sync"))]
pub(crate) on_debug: Box<dyn FnMut(&str) + 'e>, pub(crate) on_debug: Box<dyn FnMut(&str) + 'e>,
/// Optimize the AST after compilation. /// Optimize the AST after compilation.
@ -280,6 +293,11 @@ fn extract_prop_from_setter(fn_name: &str) -> Option<&str> {
impl Engine<'_> { impl Engine<'_> {
/// Create a new `Engine` /// Create a new `Engine`
pub fn new() -> Self { pub fn new() -> Self {
// fn abc<F: Fn() + Send + Sync>(f: F) {
// f();
// }
// abc(|| ());
Default::default() Default::default()
} }

View File

@ -138,7 +138,13 @@ macro_rules! def_register {
// ^ dereferencing function // ^ dereferencing function
impl< impl<
$($par: Any + Clone,)* $($par: Any + Clone,)*
#[cfg(feature = "sync")]
FN: Fn($($param),*) -> RET + Send + Sync + 'static,
#[cfg(not(feature = "sync"))]
FN: Fn($($param),*) -> RET + 'static, FN: Fn($($param),*) -> RET + 'static,
RET: Any RET: Any
> RegisterFn<FN, ($($mark,)*), RET> for Engine<'_> > RegisterFn<FN, ($($mark,)*), RET> for Engine<'_>
{ {
@ -171,6 +177,11 @@ macro_rules! def_register {
impl< impl<
$($par: Any + Clone,)* $($par: Any + Clone,)*
#[cfg(feature = "sync")]
FN: Fn($($param),*) -> Dynamic + Send + Sync + 'static,
#[cfg(not(feature = "sync"))]
FN: Fn($($param),*) -> Dynamic + 'static, FN: Fn($($param),*) -> Dynamic + 'static,
> RegisterDynamicFn<FN, ($($mark,)*)> for Engine<'_> > RegisterDynamicFn<FN, ($($mark,)*)> for Engine<'_>
{ {
@ -202,7 +213,12 @@ macro_rules! def_register {
impl< impl<
$($par: Any + Clone,)* $($par: Any + Clone,)*
#[cfg(feature = "sync")]
FN: Fn($($param),*) -> Result<RET, EvalAltResult> + Send + Sync + 'static,
#[cfg(not(feature = "sync"))]
FN: Fn($($param),*) -> Result<RET, EvalAltResult> + 'static, FN: Fn($($param),*) -> Result<RET, EvalAltResult> + 'static,
RET: Any RET: Any
> RegisterResultFn<FN, ($($mark,)*), RET> for Engine<'_> > RegisterResultFn<FN, ($($mark,)*), RET> for Engine<'_>
{ {