Add sync
feature to make Dynamic, Scope and AST Send + Sync
.
This commit is contained in:
parent
2c86abc58c
commit
0873bdc152
@ -32,6 +32,7 @@ no_optimize = [] # no script optimizer
|
|||||||
optimize_full = [] # set optimization level to Full (default is Simple) - this is a feature used only to simplify testing
|
optimize_full = [] # set optimization level to Full (default is Simple) - this is a feature used only to simplify testing
|
||||||
only_i32 = [] # set INT=i32 (useful for 32-bit systems)
|
only_i32 = [] # set INT=i32 (useful for 32-bit systems)
|
||||||
only_i64 = [] # set INT=i64 (default) and disable support for all other integer types
|
only_i64 = [] # set INT=i64 (default) and disable support for all other integer types
|
||||||
|
sync = [] # restrict to only types that implement Send + Sync
|
||||||
|
|
||||||
# compiling for no-std
|
# compiling for no-std
|
||||||
no_std = [ "num-traits/libm", "hashbrown", "core-error", "libm" ]
|
no_std = [ "num-traits/libm", "hashbrown", "core-error", "libm" ]
|
||||||
|
11
README.md
11
README.md
@ -68,6 +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`. |
|
||||||
|
|
||||||
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.
|
||||||
@ -82,6 +83,7 @@ Excluding unneeded functionalities can result in smaller, faster builds as well
|
|||||||
[`only_i32`]: #optional-features
|
[`only_i32`]: #optional-features
|
||||||
[`only_i64`]: #optional-features
|
[`only_i64`]: #optional-features
|
||||||
[`no_std`]: #optional-features
|
[`no_std`]: #optional-features
|
||||||
|
[`sync`]: #optional-features
|
||||||
|
|
||||||
Related
|
Related
|
||||||
-------
|
-------
|
||||||
@ -312,12 +314,12 @@ if type_of(x) == "string" {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Dynamic values
|
`Dynamic` values
|
||||||
--------------
|
----------------
|
||||||
|
|
||||||
[`Dynamic`]: #dynamic-values
|
[`Dynamic`]: #dynamic-values
|
||||||
|
|
||||||
A `Dynamic` value can be _any_ type.
|
A `Dynamic` value can be _any_ type. However, if the [`sync`] feature is used, then all types must be `Send + Sync`.
|
||||||
|
|
||||||
Because [`type_of()`] a `Dynamic` value returns the type of the actual value, it is usually used to perform type-specific
|
Because [`type_of()`] a `Dynamic` value returns the type of the actual value, it is usually used to perform type-specific
|
||||||
actions based on the actual value's type.
|
actions based on the actual value's type.
|
||||||
@ -704,6 +706,9 @@ By default, Rhai treats each [`Engine`] invocation as a fresh one, persisting on
|
|||||||
This gives each evaluation a clean starting slate. In order to continue using the same global state from one invocation to the next,
|
This gives each evaluation a clean starting slate. In order to continue using the same global state from one invocation to the next,
|
||||||
such a state must be manually created and passed in.
|
such a state must be manually created and passed in.
|
||||||
|
|
||||||
|
All `Scope` variables are [`Dynamic`], meaning they can store values of any type. If the [`sync`] feature is used, however, then only types
|
||||||
|
that are `Send + Sync` are supported, and the entire `Scope` itself will also be `Send + Sync`. This is extremely useful in multi-threaded applications.
|
||||||
|
|
||||||
In this example, a global state object (a `Scope`) is created with a few initialized variables, then the same state is threaded through multiple invocations:
|
In this example, a global state object (a `Scope`) is created with a few initialized variables, then the same state is threaded through multiple invocations:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
43
src/any.rs
43
src/any.rs
@ -1,7 +1,7 @@
|
|||||||
//! Helper module which defines the `Any` trait to to allow dynamic value handling.
|
//! Helper module which defines the `Any` trait to to allow dynamic value handling.
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::{type_name, Any as StdAny, TypeId},
|
any::{type_name, TypeId},
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
fmt,
|
fmt,
|
||||||
};
|
};
|
||||||
@ -13,7 +13,8 @@ pub type Variant = dyn Any;
|
|||||||
pub type Dynamic = Box<Variant>;
|
pub type Dynamic = Box<Variant>;
|
||||||
|
|
||||||
/// A trait covering any type.
|
/// A trait covering any type.
|
||||||
pub trait Any: StdAny {
|
#[cfg(feature = "sync")]
|
||||||
|
pub trait Any: crate::stdlib::any::Any + Send + Sync {
|
||||||
/// Get the `TypeId` of this type.
|
/// Get the `TypeId` of this type.
|
||||||
fn type_id(&self) -> TypeId;
|
fn type_id(&self) -> TypeId;
|
||||||
|
|
||||||
@ -28,7 +29,43 @@ pub trait Any: StdAny {
|
|||||||
fn _closed(&self) -> _Private;
|
fn _closed(&self) -> _Private;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone + StdAny + ?Sized> Any for T {
|
#[cfg(feature = "sync")]
|
||||||
|
impl<T: crate::stdlib::any::Any + Clone + Send + Sync + ?Sized> Any for T {
|
||||||
|
fn type_id(&self) -> TypeId {
|
||||||
|
TypeId::of::<T>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_name(&self) -> &'static str {
|
||||||
|
type_name::<T>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_dynamic(&self) -> Dynamic {
|
||||||
|
Box::new(self.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _closed(&self) -> _Private {
|
||||||
|
_Private
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "sync"))]
|
||||||
|
pub trait Any: crate::stdlib::any::Any {
|
||||||
|
/// Get the `TypeId` of this type.
|
||||||
|
fn type_id(&self) -> TypeId;
|
||||||
|
|
||||||
|
/// Get the name of this type.
|
||||||
|
fn type_name(&self) -> &'static str;
|
||||||
|
|
||||||
|
/// Convert into `Dynamic`.
|
||||||
|
fn into_dynamic(&self) -> Dynamic;
|
||||||
|
|
||||||
|
/// This trait may only be implemented by `rhai`.
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn _closed(&self) -> _Private;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "sync"))]
|
||||||
|
impl<T: crate::stdlib::any::Any + Clone + ?Sized> Any for T {
|
||||||
fn type_id(&self) -> TypeId {
|
fn type_id(&self) -> TypeId {
|
||||||
TypeId::of::<T>()
|
TypeId::of::<T>()
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
///! This test simulates an external command object that is driven by a script.
|
///! This test simulates an external command object that is driven by a script.
|
||||||
use rhai::{Engine, EvalAltResult, RegisterFn, Scope, INT};
|
use rhai::{Engine, EvalAltResult, RegisterFn, Scope, INT};
|
||||||
use std::cell::RefCell;
|
use std::sync::{Arc, Mutex};
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
/// External command.
|
/// External command.
|
||||||
struct Command {
|
struct Command {
|
||||||
@ -24,19 +23,19 @@ impl Command {
|
|||||||
/// Wrapper object to wrap a command object.
|
/// Wrapper object to wrap a command object.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct CommandWrapper {
|
struct CommandWrapper {
|
||||||
command: Rc<RefCell<Command>>,
|
command: Arc<Mutex<Command>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommandWrapper {
|
impl CommandWrapper {
|
||||||
/// Delegate command action.
|
/// Delegate command action.
|
||||||
pub fn do_action(&mut self, x: i64) {
|
pub fn do_action(&mut self, x: i64) {
|
||||||
let mut command = self.command.borrow_mut();
|
let mut command = self.command.lock().unwrap();
|
||||||
let val = command.get();
|
let val = command.get();
|
||||||
command.action(val + x);
|
command.action(val + x);
|
||||||
}
|
}
|
||||||
/// Delegate get value action.
|
/// Delegate get value action.
|
||||||
pub fn get_value(&mut self) -> i64 {
|
pub fn get_value(&mut self) -> i64 {
|
||||||
let command = self.command.borrow();
|
let command = self.command.lock().unwrap();
|
||||||
command.get()
|
command.get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,8 +46,8 @@ fn test_side_effects() -> Result<(), EvalAltResult> {
|
|||||||
let mut scope = Scope::new();
|
let mut scope = Scope::new();
|
||||||
|
|
||||||
// Create the command object with initial state, handled by an `Rc`.
|
// Create the command object with initial state, handled by an `Rc`.
|
||||||
let command = Rc::new(RefCell::new(Command { state: 12 }));
|
let command = Arc::new(Mutex::new(Command { state: 12 }));
|
||||||
assert_eq!(command.borrow().get(), 12);
|
assert_eq!(command.lock().unwrap().get(), 12);
|
||||||
|
|
||||||
// Create the wrapper.
|
// Create the wrapper.
|
||||||
let wrapper = CommandWrapper {
|
let wrapper = CommandWrapper {
|
||||||
@ -76,7 +75,7 @@ fn test_side_effects() -> Result<(), EvalAltResult> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Make sure the actions are properly performed
|
// Make sure the actions are properly performed
|
||||||
assert_eq!(command.borrow().get(), 42);
|
assert_eq!(command.lock().unwrap().get(), 42);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user