Rewrite Rhai function dispatching
This commit is contained in:
parent
ecf143b649
commit
f09545921f
@ -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]")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use rhai::{Engine, FnRegister};
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct TestStruct {
|
struct TestStruct {
|
||||||
x: i64
|
x: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestStruct {
|
impl TestStruct {
|
||||||
|
@ -3,13 +3,15 @@ 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();
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,8 +23,7 @@ fn main() {
|
|||||||
|
|
||||||
match engine.eval_file::<()>(&fname) {
|
match engine.eval_file::<()>(&fname) {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(e) => {println!("Error: {}", e)}
|
Err(e) => println!("Error: {}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
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;
|
1160
src/engine.rs
1160
src/engine.rs
File diff suppressed because it is too large
Load Diff
@ -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,
|
macro_rules! count_args {
|
||||||
V: Clone + Any,
|
() => {0usize};
|
||||||
W: Clone + Any,
|
($head:ident $($tail:ident)*) => {1usize + count_args!($($tail)*)};
|
||||||
X: Clone + Any,
|
}
|
||||||
Y: Clone + Any,
|
|
||||||
Z: 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, fun: A) {
|
fn register_fn(&mut self, name: &str, f: FN) {
|
||||||
let wrapped: Box<Fn(&mut Box<Any>,
|
let fun = move |mut args: Vec<&mut Box<Any>>| {
|
||||||
&mut Box<Any>,
|
// Check for length at the beginning to avoid
|
||||||
&mut Box<Any>,
|
// per-element bound checks.
|
||||||
&mut Box<Any>,
|
if args.len() != count_args!($($par)*) {
|
||||||
&mut Box<Any>,
|
return Err(EvalAltResult::ErrorFunctionArgMismatch);
|
||||||
&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,
|
|
||||||
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);
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, A, T, U, V, W, X, Y, Z> FnRegister<A, Z, (&'a T, U, V, W, X, Y)> for Engine
|
//def_register!(imp_pop $($par => $mark => $param),*);
|
||||||
where A: 'static + Fn(T, U, V, W, X, Y) -> Z,
|
};
|
||||||
T: Clone + Any,
|
($p0:ident $(, $p:ident)*) => {
|
||||||
U: Clone + Any,
|
def_register!(imp $p0 => $p0 => $p0 => Clone::clone $(, $p => $p => $p => Clone::clone)*);
|
||||||
V: Clone + Any,
|
def_register!(imp $p0 => Ref<$p0> => &$p0 => |x| { x } $(, $p => $p => $p => Clone::clone)*);
|
||||||
W: Clone + Any,
|
def_register!(imp $p0 => Mut<$p0> => &mut $p0 => |x| { x } $(, $p => $p => $p => Clone::clone)*);
|
||||||
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>;
|
def_register!($($p),*);
|
||||||
let inside2 = (*arg2).downcast_mut() as Option<&mut U>;
|
};
|
||||||
let inside3 = (*arg3).downcast_mut() as Option<&mut V>;
|
// (imp_pop) => {};
|
||||||
let inside4 = (*arg4).downcast_mut() as Option<&mut W>;
|
// (imp_pop $head:ident => $head_mark:ty => $head_param:ty $(,$tail:ident => $tail_mark:ty => $tp:ty)*) => {
|
||||||
let inside5 = (*arg5).downcast_mut() as Option<&mut X>;
|
// def_register!(imp $($tail => $tail_mark => $tp),*);
|
||||||
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
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
where A: 'static + Fn(&mut T, U, V, W, X) -> Y,
|
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: 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
23
src/lib.rs
23
src/lib.rs
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user