Merge pull request #57 from torkleyy/rewrite
Rewrite Rhai function dispatching
This commit is contained in:
commit
c1a0312432
@ -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]")
|
||||
);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
102
src/any.rs
Normal 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
36
src/call.rs
Normal 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);
|
1327
src/engine.rs
1327
src/engine.rs
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
|
36
src/lib.rs
36
src/lib.rs
@ -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;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use engine::Engine;
|
||||
use fn_register::FnRegister;
|
||||
use fn_register::RegisterFn;
|
||||
|
||||
#[test]
|
||||
fn test_arrays() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use engine::Engine;
|
||||
use fn_register::FnRegister;
|
||||
use fn_register::RegisterFn;
|
||||
|
||||
#[test]
|
||||
fn test_float() {
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use engine::Engine;
|
||||
use fn_register::FnRegister;
|
||||
use fn_register::RegisterFn;
|
||||
|
||||
#[test]
|
||||
fn test_method_call() {
|
||||
|
@ -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)
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user