Add event handler examples.
This commit is contained in:
parent
3667761340
commit
d843baca12
153
examples/event_handler_js/main.rs
Normal file
153
examples/event_handler_js/main.rs
Normal file
@ -0,0 +1,153 @@
|
||||
//! Implementation of the Event Handler With State Pattern - JS Style
|
||||
use rhai::{Dynamic, Engine, Map, Scope, AST};
|
||||
|
||||
use std::io::{stdin, stdout, Write};
|
||||
|
||||
const SCRIPT_FILE: &str = "event_handler_js/script.rhai";
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Handler {
|
||||
pub engine: Engine,
|
||||
pub scope: Scope<'static>,
|
||||
pub states: Dynamic,
|
||||
pub ast: AST,
|
||||
}
|
||||
|
||||
fn print_scope(scope: &Scope) {
|
||||
scope
|
||||
.iter_raw()
|
||||
.enumerate()
|
||||
.for_each(|(i, (name, constant, value))| {
|
||||
println!(
|
||||
"[{}] {}{}{} = {:?}",
|
||||
i + 1,
|
||||
if constant { "const " } else { "" },
|
||||
name,
|
||||
if value.is_shared() { " (shared)" } else { "" },
|
||||
*value.read_lock::<Dynamic>().unwrap(),
|
||||
)
|
||||
});
|
||||
println!();
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
println!("Events Handler Example - JS Style");
|
||||
println!("==================================");
|
||||
|
||||
let mut input = String::new();
|
||||
|
||||
// Read script file
|
||||
print!("Script file [{}]: ", SCRIPT_FILE);
|
||||
stdout().flush().expect("flush stdout");
|
||||
|
||||
input.clear();
|
||||
|
||||
stdin().read_line(&mut input).expect("read input");
|
||||
|
||||
let path = match input.trim() {
|
||||
"" => SCRIPT_FILE,
|
||||
path => path,
|
||||
};
|
||||
|
||||
// Create Engine
|
||||
let engine = Engine::new();
|
||||
|
||||
// Use an object map to hold state
|
||||
let mut states = Map::new();
|
||||
|
||||
// Default states can be added
|
||||
states.insert("bool_state".into(), Dynamic::FALSE);
|
||||
|
||||
// Convert the object map into 'Dynamic'
|
||||
let mut states: Dynamic = states.into();
|
||||
|
||||
// Create a custom 'Scope' to hold state
|
||||
let mut scope = Scope::new();
|
||||
|
||||
// Add any system-provided state into the custom 'Scope'.
|
||||
// Constants can be used to optimize the script.
|
||||
scope.push_constant("MY_CONSTANT", 42_i64);
|
||||
|
||||
// Compile the handler script.
|
||||
println!("> Loading script file: {}", path);
|
||||
|
||||
let ast = match engine.compile_file_with_scope(&mut scope, path.into()) {
|
||||
Ok(ast) => ast,
|
||||
Err(err) => {
|
||||
eprintln!("! Error: {}", err);
|
||||
println!("Cannot continue. Bye!");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
println!("> Script file loaded.");
|
||||
println!();
|
||||
println!("quit = exit program");
|
||||
println!("scope = print scope");
|
||||
println!("states = print states");
|
||||
println!("event arg = run function with argument");
|
||||
println!();
|
||||
|
||||
// Run the 'init' function to initialize the state, retaining variables.
|
||||
let result = engine.call_fn_raw(&mut scope, &ast, false, true, "init", Some(&mut states), []);
|
||||
|
||||
if let Err(err) = result {
|
||||
eprintln!("! {}", err)
|
||||
}
|
||||
|
||||
// Create handler instance
|
||||
let mut handler = Handler {
|
||||
engine,
|
||||
scope,
|
||||
states,
|
||||
ast,
|
||||
};
|
||||
|
||||
// Events loop
|
||||
loop {
|
||||
print!("event> ");
|
||||
stdout().flush().expect("flush stdout");
|
||||
|
||||
// Read event
|
||||
input.clear();
|
||||
stdin().read_line(&mut input).expect("read input");
|
||||
|
||||
let mut fields = input.trim().splitn(2, ' ');
|
||||
|
||||
let event = fields.next().expect("event").trim();
|
||||
let arg = fields.next().unwrap_or("");
|
||||
|
||||
// Process event
|
||||
match event {
|
||||
"quit" => break,
|
||||
|
||||
"scope" => {
|
||||
print_scope(&handler.scope);
|
||||
continue;
|
||||
}
|
||||
|
||||
"states" => {
|
||||
println!("{:?}", handler.states);
|
||||
println!();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Map all other events to function calls
|
||||
_ => {
|
||||
let engine = &handler.engine;
|
||||
let scope = &mut handler.scope;
|
||||
let ast = &handler.ast;
|
||||
let this_ptr = Some(&mut handler.states);
|
||||
|
||||
let result =
|
||||
engine.call_fn_raw(scope, ast, false, true, event, this_ptr, [arg.into()]);
|
||||
|
||||
if let Err(err) = result {
|
||||
eprintln!("! {}", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("Bye!");
|
||||
}
|
49
examples/event_handler_js/script.rhai
Normal file
49
examples/event_handler_js/script.rhai
Normal file
@ -0,0 +1,49 @@
|
||||
// Implementation of the Event Handler With State Pattern - JS Style
|
||||
|
||||
/// Initialize user-provided state.
|
||||
fn init() {
|
||||
// Can detect system-provided default states!
|
||||
// Add 'bool_state' as new state variable if one does not exist
|
||||
if !("bool_state" in this) {
|
||||
this.bool_state = false;
|
||||
}
|
||||
// Add 'value' as new state variable (overwrites any existing)
|
||||
this.value = 0;
|
||||
|
||||
// Can also add OOP-style functions!
|
||||
this.log = |x| print(`State = ${this.value}, data = ${x}`);
|
||||
}
|
||||
|
||||
/// 'start' event handler
|
||||
fn start(data) {
|
||||
if this.bool_state {
|
||||
throw "Already started!";
|
||||
}
|
||||
if this.value <= 0 {
|
||||
throw "Conditions not yet ready to start!";
|
||||
}
|
||||
this.bool_state = true;
|
||||
this.value += parse_int(data);
|
||||
|
||||
// Constant 'MY_CONSTANT' in custom scope is also visible!
|
||||
print(`MY_CONSTANT = ${MY_CONSTANT}`);
|
||||
}
|
||||
|
||||
/// 'end' event handler
|
||||
fn end(data) {
|
||||
if !this.bool_state {
|
||||
throw "Not yet started!";
|
||||
}
|
||||
if this.value > 0 {
|
||||
throw "Conditions not yet ready to end!";
|
||||
}
|
||||
this.bool_state = false;
|
||||
this.value = parse_int(data);
|
||||
}
|
||||
|
||||
/// 'update' event handler
|
||||
fn update(data) {
|
||||
let data = parse_int(data);
|
||||
this.value += data;
|
||||
this.log(data);
|
||||
}
|
129
examples/event_handler_main/main.rs
Normal file
129
examples/event_handler_main/main.rs
Normal file
@ -0,0 +1,129 @@
|
||||
//! Implementation of the Event Handler With State Pattern - Main Style
|
||||
use rhai::{Dynamic, Engine, Scope, AST};
|
||||
|
||||
use std::io::{stdin, stdout, Write};
|
||||
|
||||
const SCRIPT_FILE: &str = "event_handler_main/script.rhai";
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Handler {
|
||||
pub engine: Engine,
|
||||
pub scope: Scope<'static>,
|
||||
pub ast: AST,
|
||||
}
|
||||
|
||||
fn print_scope(scope: &Scope) {
|
||||
scope
|
||||
.iter_raw()
|
||||
.enumerate()
|
||||
.for_each(|(i, (name, constant, value))| {
|
||||
println!(
|
||||
"[{}] {}{}{} = {:?}",
|
||||
i + 1,
|
||||
if constant { "const " } else { "" },
|
||||
name,
|
||||
if value.is_shared() { " (shared)" } else { "" },
|
||||
*value.read_lock::<Dynamic>().unwrap(),
|
||||
)
|
||||
});
|
||||
println!();
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
println!("Events Handler Example - Main Style");
|
||||
println!("===================================");
|
||||
|
||||
let mut input = String::new();
|
||||
|
||||
// Read script file
|
||||
print!("Script file [{}]: ", SCRIPT_FILE);
|
||||
stdout().flush().expect("flush stdout");
|
||||
|
||||
input.clear();
|
||||
|
||||
stdin().read_line(&mut input).expect("read input");
|
||||
|
||||
let path = match input.trim() {
|
||||
"" => SCRIPT_FILE,
|
||||
path => path,
|
||||
};
|
||||
|
||||
// Create Engine
|
||||
let engine = Engine::new();
|
||||
|
||||
// Create a custom 'Scope' to hold state
|
||||
let mut scope = Scope::new();
|
||||
|
||||
// Add any system-provided state into the custom 'Scope'.
|
||||
// Constants can be used to optimize the script.
|
||||
scope.push_constant("MY_CONSTANT", 42_i64);
|
||||
|
||||
// Compile the handler script.
|
||||
println!("> Loading script file: {}", path);
|
||||
|
||||
let ast = match engine.compile_file_with_scope(&mut scope, path.into()) {
|
||||
Ok(ast) => ast,
|
||||
Err(err) => {
|
||||
eprintln!("! Error: {}", err);
|
||||
println!("Cannot continue. Bye!");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
println!("> Script file loaded.");
|
||||
println!();
|
||||
println!("quit = exit program");
|
||||
println!("scope = print scope");
|
||||
println!("event arg = run function with argument");
|
||||
println!();
|
||||
|
||||
// Run the 'init' function to initialize the state, retaining variables.
|
||||
let result = engine.call_fn_raw(&mut scope, &ast, false, false, "init", None, []);
|
||||
|
||||
if let Err(err) = result {
|
||||
eprintln!("! {}", err)
|
||||
}
|
||||
|
||||
// Create handler instance
|
||||
let mut handler = Handler { engine, scope, ast };
|
||||
|
||||
// Events loop
|
||||
loop {
|
||||
print!("event> ");
|
||||
stdout().flush().expect("flush stdout");
|
||||
|
||||
// Read event
|
||||
input.clear();
|
||||
stdin().read_line(&mut input).expect("read input");
|
||||
|
||||
let mut fields = input.trim().splitn(2, ' ');
|
||||
|
||||
let event = fields.next().expect("event").trim();
|
||||
let arg = fields.next().unwrap_or("");
|
||||
|
||||
// Process event
|
||||
match event {
|
||||
"quit" => break,
|
||||
|
||||
"scope" => {
|
||||
print_scope(&handler.scope);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Map all other events to function calls
|
||||
_ => {
|
||||
let engine = &handler.engine;
|
||||
let scope = &mut handler.scope;
|
||||
let ast = &handler.ast;
|
||||
|
||||
let result: Result<(), _> = engine.call_fn(scope, ast, event, (arg.to_string(),));
|
||||
|
||||
if let Err(err) = result {
|
||||
eprintln!("! {}", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("Bye!");
|
||||
}
|
56
examples/event_handler_main/script.rhai
Normal file
56
examples/event_handler_main/script.rhai
Normal file
@ -0,0 +1,56 @@
|
||||
// Implementation of the Event Handler With State Pattern - Main Style
|
||||
|
||||
/// Initialize user-provided state (shadows system-provided state, if any).
|
||||
fn init() {
|
||||
// Add 'bool_state' and 'obj_state' as new state variables
|
||||
let bool_state = false;
|
||||
let value = 0;
|
||||
|
||||
// Constants can also be added!
|
||||
const EXTRA_CONSTANT = "hello, world!";
|
||||
}
|
||||
|
||||
/// Without 'OOP' support, the can only be a function.
|
||||
fn log(value, data) {
|
||||
print(`State = ${value}, data = ${data}`);
|
||||
}
|
||||
|
||||
/// 'start' event handler
|
||||
fn start(data) {
|
||||
if bool_state {
|
||||
throw "Already started!";
|
||||
}
|
||||
if value <= 0 {
|
||||
throw "Conditions not yet ready to start!";
|
||||
}
|
||||
bool_state = true;
|
||||
|
||||
// Constants 'MY_CONSTANT' and 'EXTRA_CONSTANT'
|
||||
// in custom scope are also visible!
|
||||
print(`MY_CONSTANT = ${MY_CONSTANT}`);
|
||||
print(`EXTRA_CONSTANT = ${EXTRA_CONSTANT}`);
|
||||
|
||||
value += parse_int(data);
|
||||
}
|
||||
|
||||
/// 'end' event handler
|
||||
fn end(data) {
|
||||
if !bool_state {
|
||||
throw "Not yet started!";
|
||||
}
|
||||
if value > 0 {
|
||||
throw "Conditions not yet ready to end!";
|
||||
}
|
||||
bool_state = false;
|
||||
value = parse_int(data);
|
||||
}
|
||||
|
||||
/// 'update' event handler
|
||||
fn update(data) {
|
||||
let data = parse_int(data);
|
||||
|
||||
value += data;
|
||||
|
||||
// Without OOP support, can only call function
|
||||
log(value, data);
|
||||
}
|
138
examples/event_handler_map/main.rs
Normal file
138
examples/event_handler_map/main.rs
Normal file
@ -0,0 +1,138 @@
|
||||
//! Implementation of the Event Handler With State Pattern - Map Style
|
||||
use rhai::{Dynamic, Engine, Map, Scope, AST};
|
||||
|
||||
use std::io::{stdin, stdout, Write};
|
||||
|
||||
const SCRIPT_FILE: &str = "event_handler_map/script.rhai";
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Handler {
|
||||
pub engine: Engine,
|
||||
pub scope: Scope<'static>,
|
||||
pub ast: AST,
|
||||
}
|
||||
|
||||
fn print_scope(scope: &Scope) {
|
||||
scope
|
||||
.iter_raw()
|
||||
.enumerate()
|
||||
.for_each(|(i, (name, constant, value))| {
|
||||
println!(
|
||||
"[{}] {}{}{} = {:?}",
|
||||
i + 1,
|
||||
if constant { "const " } else { "" },
|
||||
name,
|
||||
if value.is_shared() { " (shared)" } else { "" },
|
||||
*value.read_lock::<Dynamic>().unwrap(),
|
||||
)
|
||||
});
|
||||
println!();
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
println!("Events Handler Example - Map Style");
|
||||
println!("==================================");
|
||||
|
||||
let mut input = String::new();
|
||||
|
||||
// Read script file
|
||||
print!("Script file [{}]: ", SCRIPT_FILE);
|
||||
stdout().flush().expect("flush stdout");
|
||||
|
||||
input.clear();
|
||||
|
||||
stdin().read_line(&mut input).expect("read input");
|
||||
|
||||
let path = match input.trim() {
|
||||
"" => SCRIPT_FILE,
|
||||
path => path,
|
||||
};
|
||||
|
||||
// Create Engine
|
||||
let engine = Engine::new();
|
||||
|
||||
// Create a custom 'Scope' to hold state
|
||||
let mut scope = Scope::new();
|
||||
|
||||
// Add any system-provided state into the custom 'Scope'.
|
||||
// Constants can be used to optimize the script.
|
||||
scope.push_constant("MY_CONSTANT", 42_i64);
|
||||
|
||||
// Use an object map to hold state
|
||||
let mut states = Map::new();
|
||||
|
||||
// Default states can be added
|
||||
states.insert("bool_state".into(), Dynamic::FALSE);
|
||||
|
||||
// Add the main states-holding object map and call it 'state'
|
||||
scope.push("state", Map::new());
|
||||
|
||||
// Compile the handler script.
|
||||
println!("> Loading script file: {}", path);
|
||||
|
||||
let ast = match engine.compile_file_with_scope(&mut scope, path.into()) {
|
||||
Ok(ast) => ast,
|
||||
Err(err) => {
|
||||
eprintln!("! Error: {}", err);
|
||||
println!("Cannot continue. Bye!");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
println!("> Script file loaded.");
|
||||
println!();
|
||||
println!("quit = exit program");
|
||||
println!("scope = print scope");
|
||||
println!("event arg = run function with argument");
|
||||
println!();
|
||||
|
||||
// Run the 'init' function to initialize the state, retaining variables.
|
||||
let result: Result<(), _> = engine.call_fn(&mut scope, &ast, "init", ());
|
||||
|
||||
if let Err(err) = result {
|
||||
eprintln!("! {}", err)
|
||||
}
|
||||
|
||||
// Create handler instance
|
||||
let mut handler = Handler { engine, scope, ast };
|
||||
|
||||
// Events loop
|
||||
loop {
|
||||
print!("event> ");
|
||||
stdout().flush().expect("flush stdout");
|
||||
|
||||
// Read event
|
||||
input.clear();
|
||||
stdin().read_line(&mut input).expect("read input");
|
||||
|
||||
let mut fields = input.trim().splitn(2, ' ');
|
||||
|
||||
let event = fields.next().expect("event").trim();
|
||||
let arg = fields.next().unwrap_or("");
|
||||
|
||||
// Process event
|
||||
match event {
|
||||
"quit" => break,
|
||||
|
||||
"scope" => {
|
||||
print_scope(&handler.scope);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Map all other events to function calls
|
||||
_ => {
|
||||
let engine = &handler.engine;
|
||||
let scope = &mut handler.scope;
|
||||
let ast = &handler.ast;
|
||||
|
||||
let result: Result<(), _> = engine.call_fn(scope, ast, event, (arg.to_string(),));
|
||||
|
||||
if let Err(err) = result {
|
||||
eprintln!("! {}", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("Bye!");
|
||||
}
|
57
examples/event_handler_map/script.rhai
Normal file
57
examples/event_handler_map/script.rhai
Normal file
@ -0,0 +1,57 @@
|
||||
// Implementation of the Event Handler With State Pattern - Map Style
|
||||
|
||||
/// Initialize user-provided state.
|
||||
/// State is stored inside an object map bound to 'state'.
|
||||
fn init() {
|
||||
// Add 'bool_state' as new state variable if one does not exist
|
||||
if !("bool_state" in state) {
|
||||
state.bool_state = false;
|
||||
}
|
||||
// Add 'obj_state' as new state variable (overwrites any existing)
|
||||
state.value = 0;
|
||||
|
||||
// Can also add OOP-style functions!
|
||||
state.log = |x| print(`State = ${this.value}, data = ${x}`);
|
||||
}
|
||||
|
||||
/// 'start' event handler
|
||||
fn start(data) {
|
||||
// Can detect system-provided default states!
|
||||
// Access state variables in 'state'
|
||||
if state.bool_state {
|
||||
throw "Already started!";
|
||||
}
|
||||
|
||||
// New values can be added to the state
|
||||
state.start_mode = data;
|
||||
|
||||
if state.value <= 0 {
|
||||
throw "Conditions not yet ready to start!";
|
||||
}
|
||||
state.bool_state = true;
|
||||
state.value = parse_int(data);
|
||||
|
||||
// Constant 'MY_CONSTANT' in custom scope is also visible!
|
||||
print(`MY_CONSTANT = ${MY_CONSTANT}`);
|
||||
}
|
||||
|
||||
/// 'end' event handler
|
||||
fn end(data) {
|
||||
if !state.bool_state || !("start_mode" in state) {
|
||||
throw "Not yet started!";
|
||||
}
|
||||
if state.value > 0 {
|
||||
throw "Conditions not yet ready to end!";
|
||||
}
|
||||
state.bool_state = false;
|
||||
state.value = parse_int(data);
|
||||
}
|
||||
|
||||
/// 'update' event handler
|
||||
fn update(data) {
|
||||
let data = parse_int(data);
|
||||
state.value += data;
|
||||
|
||||
// Call user-defined function OOP-style!
|
||||
state.log(data);
|
||||
}
|
Loading…
Reference in New Issue
Block a user