Rewrite Rhai function dispatching

This commit is contained in:
torkleyy 2017-12-20 12:16:14 +01:00
parent ecf143b649
commit f09545921f
11 changed files with 610 additions and 1351 deletions

View File

@ -3,7 +3,7 @@ use rhai::{Engine, FnRegister};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
struct TestStruct { struct TestStruct {
x: i64 x: i64,
} }
impl TestStruct { impl TestStruct {
@ -24,5 +24,8 @@ fn main() {
engine.register_fn("update", TestStruct::update); engine.register_fn("update", TestStruct::update);
engine.register_fn("new_ts", TestStruct::new); engine.register_fn("new_ts", TestStruct::new);
println!("{:?}", engine.eval::<TestStruct>("let x = [new_ts()]; x[0].update(); x[0]")); println!(
"{:?}",
engine.eval::<TestStruct>("let x = [new_ts()]; x[0].update(); x[0]")
);
} }

View File

@ -3,7 +3,7 @@ use rhai::{Engine, FnRegister};
#[derive(Clone)] #[derive(Clone)]
struct TestStruct { struct TestStruct {
x: i64 x: i64,
} }
impl TestStruct { impl TestStruct {

View File

@ -5,6 +5,6 @@ fn main() {
let mut engine = Engine::new(); let mut engine = Engine::new();
if let Ok(result) = engine.eval::<i64>("40 + 2") { if let Ok(result) = engine.eval::<i64>("40 + 2") {
println!("Answer: {}", result); // prints 42 println!("Answer: {}", result); // prints 42
} }
} }

View File

@ -3,38 +3,40 @@ extern crate rhai;
use std::fmt::Display; use std::fmt::Display;
use std::process::exit; use std::process::exit;
use std::io::{stdin, stdout, Write}; use std::io::{stdin, stdout, Write};
use rhai::{Engine, Scope, FnRegister}; use rhai::{Engine, FnRegister, Scope};
fn showit<T: Display>(x: &mut T) -> () { fn showit<T: Display>(x: &mut T) -> () {
println!("{}", x) println!("{}", x)
} }
fn quit() { exit(0); } fn quit() {
exit(0);
}
pub fn main() { pub fn main() {
let mut engine = Engine::new(); let mut engine = Engine::new();
let mut scope = Scope::new(); let mut scope = Scope::new();
engine.register_fn("print", showit as fn(x: &mut i32)->()); engine.register_fn("print", showit as fn(x: &mut i32) -> ());
engine.register_fn("print", showit as fn(x: &mut i64)->()); engine.register_fn("print", showit as fn(x: &mut i64) -> ());
engine.register_fn("print", showit as fn(x: &mut u32)->()); engine.register_fn("print", showit as fn(x: &mut u32) -> ());
engine.register_fn("print", showit as fn(x: &mut u64)->()); engine.register_fn("print", showit as fn(x: &mut u64) -> ());
engine.register_fn("print", showit as fn(x: &mut f32)->()); engine.register_fn("print", showit as fn(x: &mut f32) -> ());
engine.register_fn("print", showit as fn(x: &mut f64)->()); engine.register_fn("print", showit as fn(x: &mut f64) -> ());
engine.register_fn("print", showit as fn(x: &mut bool)->()); engine.register_fn("print", showit as fn(x: &mut bool) -> ());
engine.register_fn("print", showit as fn(x: &mut String)->()); engine.register_fn("print", showit as fn(x: &mut String) -> ());
engine.register_fn("exit", quit); engine.register_fn("exit", quit);
loop { loop {
print!("> "); print!("> ");
let mut input = String::new(); let mut input = String::new();
stdout().flush().expect("couldn't flush stdout"); stdout().flush().expect("couldn't flush stdout");
if let Err(e) = stdin().read_line(&mut input) { if let Err(e) = stdin().read_line(&mut input) {
println!("input error: {}", e); println!("input error: {}", e);
} }
if let Err(e) = engine.consume_with_scope(&mut scope, &input) { if let Err(e) = engine.consume_with_scope(&mut scope, &input) {
println!("error: {}", e); println!("error: {}", e);
} }
} }
} }

View File

@ -5,10 +5,14 @@ fn main() {
let mut engine = Engine::new(); let mut engine = Engine::new();
let mut scope: Scope = Vec::new(); let mut scope: Scope = Vec::new();
if !engine.eval_with_scope::<()>(&mut scope, "let x = 4 + 5").is_ok() { assert!(false); } if !engine
.eval_with_scope::<()>(&mut scope, "let x = 4 + 5")
.is_ok()
{
assert!(false);
}
if let Ok(result) = engine.eval_with_scope::<i64>(&mut scope, "x") { if let Ok(result) = engine.eval_with_scope::<i64>(&mut scope, "x") {
println!("result: {}", result); println!("result: {}", result);
} }
} }

View File

@ -12,19 +12,18 @@ fn main() {
for fname in env::args().skip(1) { for fname in env::args().skip(1) {
let mut engine = Engine::new(); let mut engine = Engine::new();
engine.register_fn("print", showit as fn(x: &mut i32)->()); engine.register_fn("print", showit as fn(x: &mut i32) -> ());
engine.register_fn("print", showit as fn(x: &mut i64)->()); engine.register_fn("print", showit as fn(x: &mut i64) -> ());
engine.register_fn("print", showit as fn(x: &mut u32)->()); engine.register_fn("print", showit as fn(x: &mut u32) -> ());
engine.register_fn("print", showit as fn(x: &mut u64)->()); engine.register_fn("print", showit as fn(x: &mut u64) -> ());
engine.register_fn("print", showit as fn(x: &mut f32)->()); engine.register_fn("print", showit as fn(x: &mut f32) -> ());
engine.register_fn("print", showit as fn(x: &mut f64)->()); engine.register_fn("print", showit as fn(x: &mut f64) -> ());
engine.register_fn("print", showit as fn(x: &mut bool)->()); engine.register_fn("print", showit as fn(x: &mut bool) -> ());
engine.register_fn("print", showit as fn(x: &mut String)->()); engine.register_fn("print", showit as fn(x: &mut String) -> ());
match engine.eval_file::<()>(&fname) { match engine.eval_file::<()>(&fname) {
Ok(_) => (), Ok(_) => (),
Err(e) => {println!("Error: {}", e)} Err(e) => println!("Error: {}", e),
} }
} }
} }

View File

@ -1,7 +1,9 @@
extern crate rhai; extern crate rhai;
use rhai::{Engine, FnRegister}; use rhai::{Any, Engine, RegisterFn};
fn add(x: i64, y: i64) -> i64 { fn add(x: i64, y: i64) -> i64 {
println!("Adding: {}", x + y);
x + y x + y
} }
@ -9,8 +11,17 @@ fn main() {
let mut engine = Engine::new(); let mut engine = Engine::new();
engine.register_fn("add", add); engine.register_fn("add", add);
engine
.call_fn_raw(
"add".to_owned(),
vec![
&mut (Box::new(3i64) as Box<Any>),
&mut (Box::new(5i64) as Box<Any>),
],
)
.expect("FAIL");
if let Ok(result) = engine.eval::<i64>("add(40, 2)") { //if let Ok(result) = engine.eval::<i64>("add(40, 2)") {
println!("Answer: {}", result); // prints 42 // println!("Answer: {}", result); // prints 42
} //}
} }

102
src/any.rs Normal file
View File

@ -0,0 +1,102 @@
use std::any::{Any as StdAny, TypeId};
use std::fmt;
pub trait Any: StdAny {
fn type_id(&self) -> TypeId;
fn box_clone(&self) -> Box<Any>;
/// This type may only be implemented by `rhai`.
#[doc(hidden)]
fn _closed(&self) -> _Private;
}
impl<T> Any for T
where
T: Clone + StdAny + ?Sized
{
#[inline]
fn type_id(&self) -> TypeId {
TypeId::of::<T>()
}
#[inline]
fn box_clone(&self) -> Box<Any> {
Box::new(self.clone())
}
fn _closed(&self) -> _Private {
_Private
}
}
impl Any {
#[inline]
fn box_clone(&self) -> Box<Any> {
Any::box_clone(self)
}
#[inline]
pub fn is<T: Any>(&self) -> bool {
let t = TypeId::of::<T>();
let boxed = self.type_id();
t == boxed
}
#[inline]
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
if self.is::<T>() {
unsafe {
Some(&*(self as *const Any as *const T))
}
} else {
None
}
}
#[inline]
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
if self.is::<T>() {
unsafe {
Some(&mut *(self as *mut Any as *mut T))
}
} else {
None
}
}
}
impl Clone for Box<Any> {
fn clone(&self) -> Self {
Any::box_clone(self.as_ref() as &Any)
}
}
impl fmt::Debug for Any {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("Any")
}
}
pub trait AnyExt: Sized {
fn downcast<T: Any + Clone>(self) -> Result<Box<T>, Self>;
}
impl AnyExt for Box<Any> {
fn downcast<T: Any + Clone>(self) -> Result<Box<T>, Self> {
if self.is::<T>() {
unsafe {
let raw: *mut Any = Box::into_raw(self);
Ok(Box::from_raw(raw as *mut T))
}
} else {
Err(self)
}
}
}
/// Private type which ensures that `rhai::Any` can only
/// be implemented by this crate.
#[doc(hidden)]
pub struct _Private;

File diff suppressed because it is too large Load Diff

View File

@ -1,421 +1,68 @@
use std::any::Any; use std::any::TypeId;
use std::boxed::Box;
use engine::{EvalAltResult, Engine, FnType}; use any::Any;
use engine::{Engine, EvalAltResult};
/// A trait used for registering functions to an Engine pub trait RegisterFn<FN, ARGS, RET> {
/// Currently, Rhai supports functions with up to 6 parameters fn register_fn(&mut self, name: &str, f: FN);
pub trait FnRegister<A, RetVal, Args> {
/// A method used for registering functions and methods to a Engine
fn register_fn(&mut self, name: &str, f: A);
} }
impl<'a, A, T, U, V, W, X, Y, Z> FnRegister<A, Z, (&'a mut T, U, V, W, X, Y)> for Engine pub struct Ref<A>(A);
where A: 'static + Fn(&mut T, U, V, W, X, Y) -> Z, pub struct Mut<A>(A);
T: Any,
U: Clone + Any,
V: Clone + Any,
W: Clone + Any,
X: Clone + Any,
Y: Clone + Any,
Z: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped: Box<Fn(&mut Box<Any>,
&mut Box<Any>,
&mut Box<Any>,
&mut Box<Any>,
&mut Box<Any>,
&mut Box<Any>)
-> Result<Box<Any>, EvalAltResult>> =
Box::new(move |arg1: &mut Box<Any>,
arg2: &mut Box<Any>,
arg3: &mut Box<Any>,
arg4: &mut Box<Any>,
arg5: &mut Box<Any>,
arg6: &mut Box<Any>| {
let inside1 = (*arg1).downcast_mut() as Option<&mut T>; macro_rules! count_args {
let inside2 = (*arg2).downcast_mut() as Option<&mut U>; () => {0usize};
let inside3 = (*arg3).downcast_mut() as Option<&mut V>; ($head:ident $($tail:ident)*) => {1usize + count_args!($($tail)*)};
let inside4 = (*arg4).downcast_mut() as Option<&mut W>; }
let inside5 = (*arg5).downcast_mut() as Option<&mut X>;
let inside6 = (*arg6).downcast_mut() as Option<&mut Y>;
match (inside1, inside2, inside3, inside4, inside5, inside6) { macro_rules! def_register {
(Some(b), Some(c), Some(d), Some(e), Some(f), Some(g)) => { () => {
Ok(Box::new(fun(b, def_register!(imp);
c.clone(), };
d.clone(), (imp $($par:ident => $mark:ty => $param:ty => $clone:expr),*) => {
e.clone(), impl<$($par,)* FN, RET> RegisterFn<FN, ($($mark,)*), RET> for Engine
f.clone(), where
g.clone())) as Box<Any>) $($par: Any + Clone,)*
FN: Fn($($param),*) -> RET + 'static,
RET: Any,
{
fn register_fn(&mut self, name: &str, f: FN) {
let fun = move |mut args: Vec<&mut Box<Any>>| {
// Check for length at the beginning to avoid
// per-element bound checks.
if args.len() != count_args!($($par)*) {
return Err(EvalAltResult::ErrorFunctionArgMismatch);
} }
_ => Err(EvalAltResult::ErrorFunctionArgMismatch),
}
});
let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new); let mut drain = args.drain(..);
(*ent).push(FnType::ExternalFn6(wrapped)); $(
} // Downcast every element, return in case of a type mismatch
let $par = ((*drain.next().unwrap()).downcast_mut() as Option<&mut $par>)
.ok_or(EvalAltResult::ErrorFunctionArgMismatch)?;
)*
// Call the user-supplied function using ($clone) to
// potentially clone the value, otherwise pass the reference.
Ok(Box::new(f($(($clone)($par)),*)) as Box<Any>)
};
self.register_fn_raw(name.to_owned(), vec![$(TypeId::of::<$par>()),*], Box::new(fun));
}
}
//def_register!(imp_pop $($par => $mark => $param),*);
};
($p0:ident $(, $p:ident)*) => {
def_register!(imp $p0 => $p0 => $p0 => Clone::clone $(, $p => $p => $p => Clone::clone)*);
def_register!(imp $p0 => Ref<$p0> => &$p0 => |x| { x } $(, $p => $p => $p => Clone::clone)*);
def_register!(imp $p0 => Mut<$p0> => &mut $p0 => |x| { x } $(, $p => $p => $p => Clone::clone)*);
def_register!($($p),*);
};
// (imp_pop) => {};
// (imp_pop $head:ident => $head_mark:ty => $head_param:ty $(,$tail:ident => $tail_mark:ty => $tp:ty)*) => {
// def_register!(imp $($tail => $tail_mark => $tp),*);
// };
} }
impl<'a, A, T, U, V, W, X, Y, Z> FnRegister<A, Z, (&'a T, U, V, W, X, Y)> for Engine #[cfg_attr(rustfmt, rustfmt_skip)]
where A: 'static + Fn(T, U, V, W, X, Y) -> Z, def_register!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z);
T: Clone + Any,
U: Clone + Any,
V: Clone + Any,
W: Clone + Any,
X: Clone + Any,
Y: Clone + Any,
Z: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped: Box<Fn(&mut Box<Any>,
&mut Box<Any>,
&mut Box<Any>,
&mut Box<Any>,
&mut Box<Any>,
&mut Box<Any>)
-> Result<Box<Any>, EvalAltResult>> =
Box::new(move |arg1: &mut Box<Any>,
arg2: &mut Box<Any>,
arg3: &mut Box<Any>,
arg4: &mut Box<Any>,
arg5: &mut Box<Any>,
arg6: &mut Box<Any>| {
let inside1 = (*arg1).downcast_mut() as Option<&mut T>;
let inside2 = (*arg2).downcast_mut() as Option<&mut U>;
let inside3 = (*arg3).downcast_mut() as Option<&mut V>;
let inside4 = (*arg4).downcast_mut() as Option<&mut W>;
let inside5 = (*arg5).downcast_mut() as Option<&mut X>;
let inside6 = (*arg6).downcast_mut() as Option<&mut Y>;
match (inside1, inside2, inside3, inside4, inside5, inside6) {
(Some(b), Some(c), Some(d), Some(e), Some(f), Some(g)) => {
Ok(Box::new(fun(b.clone(),
c.clone(),
d.clone(),
e.clone(),
f.clone(),
g.clone())) as Box<Any>)
}
_ => Err(EvalAltResult::ErrorFunctionArgMismatch),
}
});
let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new);
(*ent).push(FnType::ExternalFn6(wrapped));
}
}
impl<'a, A, T, U, V, W, X, Y> FnRegister<A, Y, (&'a mut T, U, V, W, X)> for Engine
where A: 'static + Fn(&mut T, U, V, W, X) -> Y,
T: Any,
U: Clone + Any,
V: Clone + Any,
W: Clone + Any,
X: Clone + Any,
Y: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped: Box<Fn(&mut Box<Any>,
&mut Box<Any>,
&mut Box<Any>,
&mut Box<Any>,
&mut Box<Any>)
-> Result<Box<Any>, EvalAltResult>> =
Box::new(move |arg1: &mut Box<Any>,
arg2: &mut Box<Any>,
arg3: &mut Box<Any>,
arg4: &mut Box<Any>,
arg5: &mut Box<Any>| {
let inside1 = (*arg1).downcast_mut() as Option<&mut T>;
let inside2 = (*arg2).downcast_mut() as Option<&mut U>;
let inside3 = (*arg3).downcast_mut() as Option<&mut V>;
let inside4 = (*arg4).downcast_mut() as Option<&mut W>;
let inside5 = (*arg5).downcast_mut() as Option<&mut X>;
match (inside1, inside2, inside3, inside4, inside5) {
(Some(b), Some(c), Some(d), Some(e), Some(f)) => {
Ok(Box::new(fun(b, c.clone(), d.clone(), e.clone(), f.clone())) as Box<Any>)
}
_ => Err(EvalAltResult::ErrorFunctionArgMismatch),
}
});
let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new);
(*ent).push(FnType::ExternalFn5(wrapped));
}
}
impl<'a, A, T, U, V, W, X, Y> FnRegister<A, Y, (&'a T, U, V, W, X)> for Engine
where A: 'static + Fn(T, U, V, W, X) -> Y,
T: Clone + Any,
U: Clone + Any,
V: Clone + Any,
W: Clone + Any,
X: Clone + Any,
Y: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped: Box<Fn(&mut Box<Any>,
&mut Box<Any>,
&mut Box<Any>,
&mut Box<Any>,
&mut Box<Any>)
-> Result<Box<Any>, EvalAltResult>> =
Box::new(move |arg1: &mut Box<Any>,
arg2: &mut Box<Any>,
arg3: &mut Box<Any>,
arg4: &mut Box<Any>,
arg5: &mut Box<Any>| {
let inside1 = (*arg1).downcast_mut() as Option<&mut T>;
let inside2 = (*arg2).downcast_mut() as Option<&mut U>;
let inside3 = (*arg3).downcast_mut() as Option<&mut V>;
let inside4 = (*arg4).downcast_mut() as Option<&mut W>;
let inside5 = (*arg5).downcast_mut() as Option<&mut X>;
match (inside1, inside2, inside3, inside4, inside5) {
(Some(b), Some(c), Some(d), Some(e), Some(f)) => {
Ok(Box::new(fun(b.clone(),
c.clone(),
d.clone(),
e.clone(),
f.clone())) as Box<Any>)
}
_ => Err(EvalAltResult::ErrorFunctionArgMismatch),
}
});
let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new);
(*ent).push(FnType::ExternalFn5(wrapped));
}
}
impl<'a, A, T, U, V, W, X> FnRegister<A, X, (&'a mut T, U, V, W)> for Engine
where A: 'static + Fn(&mut T, U, V, W) -> X,
T: Any,
U: Clone + Any,
V: Clone + Any,
W: Clone + Any,
X: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped: Box<Fn(&mut Box<Any>, &mut Box<Any>, &mut Box<Any>, &mut Box<Any>)
-> Result<Box<Any>, EvalAltResult>> =
Box::new(move |arg1: &mut Box<Any>,
arg2: &mut Box<Any>,
arg3: &mut Box<Any>,
arg4: &mut Box<Any>| {
let inside1 = (*arg1).downcast_mut() as Option<&mut T>;
let inside2 = (*arg2).downcast_mut() as Option<&mut U>;
let inside3 = (*arg3).downcast_mut() as Option<&mut V>;
let inside4 = (*arg4).downcast_mut() as Option<&mut W>;
match (inside1, inside2, inside3, inside4) {
(Some(b), Some(c), Some(d), Some(e)) => {
Ok(Box::new(fun(b, c.clone(), d.clone(), e.clone())) as Box<Any>)
}
_ => Err(EvalAltResult::ErrorFunctionArgMismatch),
}
});
let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new);
(*ent).push(FnType::ExternalFn4(wrapped));
}
}
impl<'a, A, T, U, V, W, X> FnRegister<A, X, (&'a T, U, V, W)> for Engine
where A: 'static + Fn(T, U, V, W) -> X,
T: Clone + Any,
U: Clone + Any,
V: Clone + Any,
W: Clone + Any,
X: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped: Box<Fn(&mut Box<Any>, &mut Box<Any>, &mut Box<Any>, &mut Box<Any>)
-> Result<Box<Any>, EvalAltResult>> =
Box::new(move |arg1: &mut Box<Any>,
arg2: &mut Box<Any>,
arg3: &mut Box<Any>,
arg4: &mut Box<Any>| {
let inside1 = (*arg1).downcast_mut() as Option<&mut T>;
let inside2 = (*arg2).downcast_mut() as Option<&mut U>;
let inside3 = (*arg3).downcast_mut() as Option<&mut V>;
let inside4 = (*arg4).downcast_mut() as Option<&mut W>;
match (inside1, inside2, inside3, inside4) {
(Some(b), Some(c), Some(d), Some(e)) => {
Ok(Box::new(fun(b.clone(), c.clone(), d.clone(), e.clone())) as Box<Any>)
}
_ => Err(EvalAltResult::ErrorFunctionArgMismatch),
}
});
let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new);
(*ent).push(FnType::ExternalFn4(wrapped));
}
}
impl<'a, A, T, U, V, W> FnRegister<A, W, (&'a mut T, U, V)> for Engine
where A: 'static + Fn(&mut T, U, V) -> W,
T: Any,
U: Clone + Any,
V: Clone + Any,
W: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped: Box<Fn(&mut Box<Any>, &mut Box<Any>, &mut Box<Any>)
-> Result<Box<Any>, EvalAltResult>> =
Box::new(move |arg1: &mut Box<Any>, arg2: &mut Box<Any>, arg3: &mut Box<Any>| {
let inside1 = (*arg1).downcast_mut() as Option<&mut T>;
let inside2 = (*arg2).downcast_mut() as Option<&mut U>;
let inside3 = (*arg3).downcast_mut() as Option<&mut V>;
match (inside1, inside2, inside3) {
(Some(b), Some(c), Some(d)) => {
Ok(Box::new(fun(b, c.clone(), d.clone())) as Box<Any>)
}
_ => Err(EvalAltResult::ErrorFunctionArgMismatch),
}
});
let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new);
(*ent).push(FnType::ExternalFn3(wrapped));
}
}
impl<'a, A, T, U, V, W> FnRegister<A, W, (&'a T, U, V)> for Engine
where A: 'static + Fn(T, U, V) -> W,
T: Clone + Any,
U: Clone + Any,
V: Clone + Any,
W: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped: Box<Fn(&mut Box<Any>, &mut Box<Any>, &mut Box<Any>)
-> Result<Box<Any>, EvalAltResult>> =
Box::new(move |arg1: &mut Box<Any>, arg2: &mut Box<Any>, arg3: &mut Box<Any>| {
let inside1 = (*arg1).downcast_mut() as Option<&mut T>;
let inside2 = (*arg2).downcast_mut() as Option<&mut U>;
let inside3 = (*arg3).downcast_mut() as Option<&mut V>;
match (inside1, inside2, inside3) {
(Some(b), Some(c), Some(d)) => {
Ok(Box::new(fun(b.clone(), c.clone(), d.clone())) as Box<Any>)
}
_ => Err(EvalAltResult::ErrorFunctionArgMismatch),
}
});
let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new);
(*ent).push(FnType::ExternalFn3(wrapped));
}
}
impl<'a, A, T, U, V> FnRegister<A, V, (&'a mut T, U)> for Engine
where A: 'static + Fn(&mut T, U) -> V,
T: Any,
U: Clone + Any,
V: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped: Box<Fn(&mut Box<Any>, &mut Box<Any>) -> Result<Box<Any>, EvalAltResult>> =
Box::new(move |arg1: &mut Box<Any>, arg2: &mut Box<Any>| {
let inside1 = (*arg1).downcast_mut() as Option<&mut T>;
let inside2 = (*arg2).downcast_mut() as Option<&mut U>;
match (inside1, inside2) {
(Some(b), Some(c)) => Ok(Box::new(fun(b, c.clone())) as Box<Any>),
_ => Err(EvalAltResult::ErrorFunctionArgMismatch),
}
});
let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new);
(*ent).push(FnType::ExternalFn2(wrapped));
}
}
impl<'a, A, T, U, V> FnRegister<A, V, (&'a T, U)> for Engine
where A: 'static + Fn(T, U) -> V,
T: Clone + Any,
U: Clone + Any,
V: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped: Box<Fn(&mut Box<Any>, &mut Box<Any>) -> Result<Box<Any>, EvalAltResult>> =
Box::new(move |arg1: &mut Box<Any>, arg2: &mut Box<Any>| {
let inside1 = (*arg1).downcast_mut() as Option<&mut T>;
let inside2 = (*arg2).downcast_mut() as Option<&mut U>;
match (inside1, inside2) {
(Some(b), Some(c)) => Ok(Box::new(fun(b.clone(), c.clone())) as Box<Any>),
_ => Err(EvalAltResult::ErrorFunctionArgMismatch),
}
});
let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new);
(*ent).push(FnType::ExternalFn2(wrapped));
}
}
impl<'a, A, T, U> FnRegister<A, U, (&'a mut T)> for Engine
where A: 'static + Fn(&mut T) -> U,
T: Any,
U: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped: Box<Fn(&mut Box<Any>) -> Result<Box<Any>, EvalAltResult>> =
Box::new(move |arg: &mut Box<Any>| {
let inside = (*arg).downcast_mut() as Option<&mut T>;
match inside {
Some(b) => Ok(Box::new(fun(b)) as Box<Any>),
None => Err(EvalAltResult::ErrorFunctionArgMismatch),
}
});
let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new);
(*ent).push(FnType::ExternalFn1(wrapped));
}
}
impl<'a, A, T, U> FnRegister<A, U, (&'a T)> for Engine
where A: 'static + Fn(T) -> U,
T: Clone + Any,
U: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped: Box<Fn(&mut Box<Any>) -> Result<Box<Any>, EvalAltResult>> =
Box::new(move |arg: &mut Box<Any>| {
let inside = (*arg).downcast_mut() as Option<&mut T>;
match inside {
Some(b) => Ok(Box::new(fun(b.clone())) as Box<Any>),
None => Err(EvalAltResult::ErrorFunctionArgMismatch),
}
});
let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new);
(*ent).push(FnType::ExternalFn1(wrapped));
}
}
impl<A, T> FnRegister<A, T, ()> for Engine
where A: 'static + Fn() -> T,
T: Any
{
fn register_fn(&mut self, name: &str, fun: A) {
let wrapped: Box<Fn() -> Result<Box<Any>, EvalAltResult>> = Box::new(move || {
Ok(Box::new(fun()) as Box<Any>)
});
let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new);
(*ent).push(FnType::ExternalFn0(wrapped));
}
}

View File

@ -1,10 +1,11 @@
//! # Rhai - embedded scripting for Rust //! # Rhai - embedded scripting for Rust
//!
//! Rhai is a tiny, simple and very fast embedded scripting language for Rust //! Rhai is a tiny, simple and very fast embedded scripting language for Rust
//! that gives you a safe and easy way to add scripting to your applications. //! that gives you a safe and easy way to add scripting to your applications.
//! It provides a familiar syntax based on JS and Rust and a simple Rust interface. //! It provides a familiar syntax based on JS and Rust and a simple Rust interface.
//! Here is a quick example. First, the contents of `my_script.rhai`: //! Here is a quick example. First, the contents of `my_script.rhai`:
//! //!
//! ```rust_todo_disable_testing_enable_highlighting //! ```rust,ignore
//! fn factorial(x) { //! fn factorial(x) {
//! if x == 1 { return 1; } //! if x == 1 { return 1; }
//! x * factorial(x - 1) //! x * factorial(x - 1)
@ -24,24 +25,22 @@
//! //!
//! let mut engine = Engine::new(); //! let mut engine = Engine::new();
//! engine.register_fn("compute_something", compute_something); //! engine.register_fn("compute_something", compute_something);
//! # // Very ugly hack incoming, TODO //! # // Very ugly hack incoming, TODO (maybe mark as no_run?)
//! # use std::fs::{File, remove_file}; //! # use std::fs::{File, remove_file};
//! # use std::io::Write; //! # use std::io::Write;
//! # let mut f = File::create("my_script.rhai").unwrap(); //! # let mut f = File::create("my_script.rhai").unwrap();
//! # let _ = write!(f, "{}", "fn f(x) { if x == 1 { return 1; } x * f(x-1) } compute_something(f(10))"); //! # let _ = write!(f, "{}", "fn f(x) { if x == 1 { return 1; } x * f(x-1) } compute_something(f(10))");
//! assert!(engine.eval_file::<bool>("my_script.rhai").unwrap()); //! assert_eq!(engine.eval_file::<bool>("my_script.rhai"), Ok(true));
//! # let _ = remove_file("my_script.rhai"); //! # let _ = remove_file("my_script.rhai");
//! ``` //! ```
//! //!
//! [Check out the README on github for more information!](https://github.com/jonathandturner/rhai) //! [Check out the README on GitHub for more information!](https://github.com/jonathandturner/rhai)
// lints required by Rhai // lints required by Rhai
#![allow(unknown_lints, #![allow(warnings, unknown_lints, type_complexity, new_without_default_derive,
type_complexity, needless_pass_by_value, too_many_arguments)]
new_without_default_derive,
needless_pass_by_value,
too_many_arguments)]
mod any;
mod engine; mod engine;
mod fn_register; mod fn_register;
mod parser; mod parser;
@ -49,6 +48,6 @@ mod parser;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
pub use engine::{Engine, Scope, EvalAltResult}; pub use any::Any;
pub use fn_register::FnRegister; pub use engine::{Engine, EvalAltResult, Scope};
pub use fn_register::RegisterFn;