2020-03-22 03:18:16 +01:00
|
|
|
///! This test simulates an external command object that is driven by a script.
|
|
|
|
use rhai::{Engine, EvalAltResult, RegisterFn, Scope, INT};
|
2020-04-02 13:40:02 +02:00
|
|
|
use std::sync::{Arc, Mutex};
|
2020-03-20 12:27:02 +01:00
|
|
|
|
2020-03-22 03:18:16 +01:00
|
|
|
/// External command.
|
|
|
|
struct Command {
|
|
|
|
state: i64,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Command {
|
|
|
|
/// Do some action.
|
|
|
|
pub fn action(&mut self, val: i64) {
|
|
|
|
self.state = val;
|
|
|
|
}
|
|
|
|
/// Get current value.
|
|
|
|
pub fn get(&self) -> i64 {
|
|
|
|
self.state
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Wrapper object to wrap a command object.
|
|
|
|
#[derive(Clone)]
|
2020-03-20 12:27:02 +01:00
|
|
|
struct CommandWrapper {
|
2020-04-02 13:40:02 +02:00
|
|
|
command: Arc<Mutex<Command>>,
|
2020-03-20 12:27:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl CommandWrapper {
|
2020-03-22 03:18:16 +01:00
|
|
|
/// Delegate command action.
|
|
|
|
pub fn do_action(&mut self, x: i64) {
|
2020-04-02 13:40:02 +02:00
|
|
|
let mut command = self.command.lock().unwrap();
|
2020-03-22 03:18:16 +01:00
|
|
|
let val = command.get();
|
|
|
|
command.action(val + x);
|
|
|
|
}
|
|
|
|
/// Delegate get value action.
|
|
|
|
pub fn get_value(&mut self) -> i64 {
|
2020-04-02 13:40:02 +02:00
|
|
|
let command = self.command.lock().unwrap();
|
2020-03-22 03:18:16 +01:00
|
|
|
command.get()
|
2020-03-20 12:27:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-07 07:23:06 +02:00
|
|
|
#[cfg(not(feature = "no_object"))]
|
2020-03-20 12:27:02 +01:00
|
|
|
#[test]
|
2020-04-07 07:23:06 +02:00
|
|
|
fn test_side_effects_command() -> Result<(), EvalAltResult> {
|
2020-03-20 12:27:02 +01:00
|
|
|
let mut engine = Engine::new();
|
|
|
|
let mut scope = Scope::new();
|
|
|
|
|
2020-03-22 03:18:16 +01:00
|
|
|
// Create the command object with initial state, handled by an `Rc`.
|
2020-04-02 13:40:02 +02:00
|
|
|
let command = Arc::new(Mutex::new(Command { state: 12 }));
|
|
|
|
assert_eq!(command.lock().unwrap().get(), 12);
|
2020-03-20 12:27:02 +01:00
|
|
|
|
2020-03-22 03:18:16 +01:00
|
|
|
// Create the wrapper.
|
|
|
|
let wrapper = CommandWrapper {
|
|
|
|
command: command.clone(), // Notice this clones the `Rc` only
|
2020-03-20 12:27:02 +01:00
|
|
|
};
|
|
|
|
|
2020-03-22 03:18:16 +01:00
|
|
|
// Make the wrapper a singleton in the script environment.
|
|
|
|
scope.push_constant("Command", wrapper);
|
2020-03-20 12:27:02 +01:00
|
|
|
|
2020-03-22 03:18:16 +01:00
|
|
|
// Register type.
|
2020-03-20 12:27:02 +01:00
|
|
|
engine.register_type_with_name::<CommandWrapper>("CommandType");
|
2020-03-22 03:18:16 +01:00
|
|
|
engine.register_fn("action", CommandWrapper::do_action);
|
|
|
|
engine.register_get("value", CommandWrapper::get_value);
|
2020-03-20 12:27:02 +01:00
|
|
|
|
2020-03-22 03:18:16 +01:00
|
|
|
assert_eq!(
|
|
|
|
engine.eval_with_scope::<INT>(
|
|
|
|
&mut scope,
|
|
|
|
r"
|
|
|
|
// Drive the command object via the wrapper
|
|
|
|
Command.action(30);
|
|
|
|
Command.value
|
|
|
|
"
|
|
|
|
)?,
|
|
|
|
42
|
|
|
|
);
|
2020-03-20 12:27:02 +01:00
|
|
|
|
2020-03-22 03:18:16 +01:00
|
|
|
// Make sure the actions are properly performed
|
2020-04-02 13:40:02 +02:00
|
|
|
assert_eq!(command.lock().unwrap().get(), 42);
|
2020-03-20 12:27:02 +01:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2020-04-07 07:23:06 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_side_effects_print() -> Result<(), EvalAltResult> {
|
|
|
|
use std::sync::RwLock;
|
|
|
|
|
|
|
|
let result = RwLock::new(String::from(""));
|
|
|
|
|
|
|
|
{
|
|
|
|
let mut engine = Engine::new();
|
|
|
|
|
|
|
|
// Override action of 'print' function
|
|
|
|
engine.on_print(|s| result.write().unwrap().push_str(s));
|
|
|
|
|
|
|
|
engine.consume("print(40 + 2);")?;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_eq!(*result.read().unwrap(), "42");
|
|
|
|
Ok(())
|
|
|
|
}
|