Merge pull request #57 from torkleyy/rewrite

Rewrite Rhai function dispatching
This commit is contained in:
Lukáš Hozda [magnusi] 2017-12-21 11:17:54 +01:00 committed by GitHub
commit c1a0312432
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 663 additions and 1434 deletions

View File

@ -1,9 +1,9 @@
extern crate rhai;
use rhai::{Engine, FnRegister};
use rhai::{Engine, RegisterFn};
#[derive(Clone, Debug)]
struct TestStruct {
x: i64
x: i64,
}
impl TestStruct {
@ -24,5 +24,12 @@ fn main() {
engine.register_fn("update", TestStruct::update);
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.update(); x")
);
println!(
"{:?}",
engine.eval::<TestStruct>("let x = [new_ts()]; x[0].update(); x[0]")
);
}

View File

@ -1,9 +1,9 @@
extern crate rhai;
use rhai::{Engine, FnRegister};
use rhai::{Engine, RegisterFn};
#[derive(Clone)]
struct TestStruct {
x: i64
x: i64,
}
impl TestStruct {

View File

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

View File

@ -5,10 +5,14 @@ fn main() {
let mut engine = Engine::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") {
println!("result: {}", result);
println!("result: {}", result);
}
}

View File

@ -2,7 +2,7 @@ use std::env;
use std::fmt::Display;
extern crate rhai;
use rhai::{Engine, FnRegister};
use rhai::{Engine, RegisterFn};
fn showit<T: Display>(x: &mut T) -> () {
println!("{}", x)
@ -12,19 +12,18 @@ fn main() {
for fname in env::args().skip(1) {
let mut engine = Engine::new();
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 u32)->());
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 f64)->());
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 i32) -> ());
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 u64) -> ());
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 bool) -> ());
engine.register_fn("print", showit as fn(x: &mut String) -> ());
match engine.eval_file::<()>(&fname) {
Ok(_) => (),
Err(e) => {println!("Error: {}", e)}
Err(e) => println!("Error: {}", e),
}
}
}

View File

@ -1,5 +1,5 @@
extern crate rhai;
use rhai::{Engine, FnRegister};
use rhai::{Engine, RegisterFn};
fn add(x: i64, y: i64) -> i64 {
x + y
@ -9,8 +9,7 @@ fn main() {
let mut engine = Engine::new();
engine.register_fn("add", add);
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;

36
src/call.rs Normal file
View File

@ -0,0 +1,36 @@
//! Helper module which defines `FnArgs`
//! to make function calling easier.
use any::Any;
pub trait FunArgs<'a> {
fn into_vec(self) -> Vec<&'a mut Any>;
}
macro_rules! impl_args {
($($p:ident),*) => {
impl<'a, $($p),*> FunArgs<'a> for ($(&'a mut $p,)*)
where
$($p: Any + Clone),*
{
fn into_vec(self) -> Vec<&'a mut Any> {
let ($($p,)*) = self;
let mut v = Vec::new();
$(v.push($p as &mut Any);)*
v
}
}
impl_args!(@pop $($p),*);
};
(@pop) => {
};
(@pop $head:ident $(, $tail:ident)*) => {
impl_args!($($tail),*);
};
}
#[cfg_attr(rustfmt, rustfmt_skip)]
impl_args!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);

File diff suppressed because it is too large Load Diff

View File

@ -1,421 +1,68 @@
use std::any::Any;
use std::boxed::Box;
use std::any::TypeId;
use engine::{EvalAltResult, Engine, FnType};
use any::Any;
use engine::{Engine, EvalAltResult};
/// A trait used for registering functions to an Engine
/// Currently, Rhai supports functions with up to 6 parameters
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);
pub trait RegisterFn<FN, ARGS, RET> {
fn register_fn(&mut self, name: &str, f: FN);
}
impl<'a, A, T, U, V, W, X, Y, Z> FnRegister<A, Z, (&'a mut T, U, V, W, X, Y)> for Engine
where A: 'static + Fn(&mut T, U, V, W, X, Y) -> Z,
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>| {
pub struct Ref<A>(A);
pub struct Mut<A>(A);
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>;
macro_rules! count_args {
() => {0usize};
($head:ident $($tail:ident)*) => {1usize + count_args!($($tail)*)};
}
match (inside1, inside2, inside3, inside4, inside5, inside6) {
(Some(b), Some(c), Some(d), Some(e), Some(f), Some(g)) => {
Ok(Box::new(fun(b,
c.clone(),
d.clone(),
e.clone(),
f.clone(),
g.clone())) as Box<Any>)
macro_rules! def_register {
() => {
def_register!(imp);
};
(imp $($par:ident => $mark:ty => $param:ty => $clone:expr),*) => {
impl<$($par,)* FN, RET> RegisterFn<FN, ($($mark,)*), RET> for Engine
where
$($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 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);
(*ent).push(FnType::ExternalFn6(wrapped));
}
let mut drain = args.drain(..);
$(
// 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(), Some(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
where A: 'static + Fn(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));
}
}
#[cfg_attr(rustfmt, rustfmt_skip)]
def_register!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);

View File

@ -1,10 +1,11 @@
//! # Rhai - embedded scripting 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.
//! 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`:
//!
//! ```rust_todo_disable_testing_enable_highlighting
//!
//! ```rust,ignore
//! fn factorial(x) {
//! if x == 1 { return 1; }
//! x * factorial(x - 1)
@ -12,36 +13,35 @@
//!
//! compute_something(factorial(10))
//! ```
//!
//!
//! And the Rust part:
//!
//!
//! ```rust
//! use rhai::{FnRegister, Engine};
//!
//! use rhai::{Engine, RegisterFn};
//!
//! fn compute_something(x: i64) -> bool {
//! (x % 40) == 0
//! }
//!
//!
//! let mut engine = Engine::new();
//! 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::io::Write;
//! # 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))");
//! 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");
//! ```
//!
//! [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
#![allow(unknown_lints,
type_complexity,
new_without_default_derive,
needless_pass_by_value,
too_many_arguments)]
#![allow(warnings, unknown_lints, type_complexity, new_without_default_derive,
needless_pass_by_value, too_many_arguments)]
mod any;
mod call;
mod engine;
mod fn_register;
mod parser;
@ -49,6 +49,6 @@ mod parser;
#[cfg(test)]
mod tests;
pub use engine::{Engine, Scope, EvalAltResult};
pub use fn_register::FnRegister;
pub use any::Any;
pub use engine::{Engine, EvalAltResult, Scope};
pub use fn_register::RegisterFn;

View File

@ -1,5 +1,5 @@
use engine::Engine;
use fn_register::FnRegister;
use fn_register::RegisterFn;
#[test]
fn test_arrays() {

View File

@ -1,5 +1,5 @@
use engine::Engine;
use fn_register::FnRegister;
use fn_register::RegisterFn;
#[test]
fn test_float() {

View File

@ -1,5 +1,5 @@
use engine::Engine;
use fn_register::FnRegister;
use fn_register::RegisterFn;
#[test]
fn test_get_set() {
@ -86,9 +86,5 @@ fn test_big_get_set() {
engine.register_fn("new_tp", TestParent::new);
if let Ok(result) = engine.eval::<i64>("let a = new_tp(); a.child.x = 500; a.child.x") {
assert_eq!(result, 500);
} else {
assert!(false);
}
assert_eq!(engine.eval::<i64>("let a = new_tp(); a.child.x = 500; a.child.x"), Ok(500));
}

View File

@ -1,5 +1,5 @@
use engine::Engine;
use fn_register::FnRegister;
use fn_register::RegisterFn;
#[test]
fn test_method_call() {

View File

@ -4,8 +4,8 @@ use engine::{Engine, EvalAltResult};
fn test_mismatched_op() {
let mut engine = Engine::new();
match engine.eval::<i64>("60 + \"hello\"") {
Err(EvalAltResult::ErrorFunctionArgMismatch) => (),
_ => assert!(false),
}
assert_eq!(
engine.eval::<i64>("60 + \"hello\""),
Err(EvalAltResult::ErrorFunctionNotFound)
);
}