diff --git a/src/any.rs b/src/any.rs index b6913517..3584a5e7 100644 --- a/src/any.rs +++ b/src/any.rs @@ -1,12 +1,15 @@ use std::any::{type_name, Any as StdAny, TypeId}; use std::fmt; +pub type Variant = dyn Any; +pub type Dynamic = Box; + pub trait Any: StdAny { fn type_id(&self) -> TypeId; fn type_name(&self) -> String; - fn box_clone(&self) -> Box; + fn into_dynamic(&self) -> Dynamic; /// This type may only be implemented by `rhai`. #[doc(hidden)] @@ -27,7 +30,7 @@ where } #[inline] - fn box_clone(&self) -> Box { + fn into_dynamic(&self) -> Dynamic { Box::new(self.clone()) } @@ -36,15 +39,15 @@ where } } -impl dyn Any { +impl Variant { //#[inline] - // fn box_clone(&self) -> Box { - // Any::box_clone(self) + // fn into_dynamic(&self) -> Box { + // Any::into_dynamic(self) // } #[inline] pub fn is(&self) -> bool { let t = TypeId::of::(); - let boxed = ::type_id(self); + let boxed = ::type_id(self); t == boxed } @@ -52,7 +55,7 @@ impl dyn Any { #[inline] pub fn downcast_ref(&self) -> Option<&T> { if self.is::() { - unsafe { Some(&*(self as *const dyn Any as *const T)) } + unsafe { Some(&*(self as *const Variant as *const T)) } } else { None } @@ -61,20 +64,20 @@ impl dyn Any { #[inline] pub fn downcast_mut(&mut self) -> Option<&mut T> { if self.is::() { - unsafe { Some(&mut *(self as *mut dyn Any as *mut T)) } + unsafe { Some(&mut *(self as *mut Variant as *mut T)) } } else { None } } } -impl Clone for Box { +impl Clone for Dynamic { fn clone(&self) -> Self { - Any::box_clone(self.as_ref() as &dyn Any) + Any::into_dynamic(self.as_ref() as &Variant) } } -impl fmt::Debug for dyn Any { +impl fmt::Debug for Variant { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("?") } @@ -84,11 +87,11 @@ pub trait AnyExt: Sized { fn downcast(self) -> Result, Self>; } -impl AnyExt for Box { +impl AnyExt for Dynamic { fn downcast(self) -> Result, Self> { if self.is::() { unsafe { - let raw: *mut dyn Any = Box::into_raw(self); + let raw: *mut Variant = Box::into_raw(self); Ok(Box::from_raw(raw as *mut T)) } } else { diff --git a/src/call.rs b/src/call.rs index fa2439e9..d7565cd9 100644 --- a/src/call.rs +++ b/src/call.rs @@ -1,24 +1,22 @@ //! Helper module which defines `FnArgs` //! to make function calling easier. -use crate::any::Any; +use crate::any::{Any, Variant}; pub trait FunArgs<'a> { - fn into_vec(self) -> Vec<&'a mut dyn Any>; + fn into_vec(self) -> Vec<&'a mut Variant>; } macro_rules! impl_args { ($($p:ident),*) => { - impl<'a, $($p),*> FunArgs<'a> for ($(&'a mut $p,)*) - where - $($p: Any + Clone),* + impl<'a, $($p: Any + Clone),*> FunArgs<'a> for ($(&'a mut $p,)*) { - fn into_vec(self) -> Vec<&'a mut dyn Any> { + fn into_vec(self) -> Vec<&'a mut Variant> { let ($($p,)*) = self; #[allow(unused_variables, unused_mut)] let mut v = Vec::new(); - $(v.push($p as &mut dyn Any);)* + $(v.push($p as &mut Variant);)* v } diff --git a/src/engine.rs b/src/engine.rs index fbdd9d6f..ae6220a7 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -6,13 +6,14 @@ use std::fmt; use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Shl, Shr, Sub}; use std::{convert::TryInto, sync::Arc}; -use crate::any::{Any, AnyExt}; +use crate::any::{Any, AnyExt, Dynamic, Variant}; use crate::call::FunArgs; use crate::fn_register::{RegisterBoxFn, RegisterFn}; use crate::parser::{lex, parse, Expr, FnDef, ParseError, Stmt, AST}; use fmt::{Debug, Display}; -type Array = Vec>; +pub type Array = Vec; +pub type FnCallArgs<'a> = Vec<&'a mut Variant>; #[derive(Debug, Clone)] pub enum EvalAltResult { @@ -30,7 +31,7 @@ pub enum EvalAltResult { ErrorCantOpenScriptFile(String), ErrorMalformedDotExpression, LoopBreak, - Return(Box), + Return(Dynamic), } impl EvalAltResult { @@ -131,7 +132,7 @@ pub struct FnSpec { args: Option>, } -type IteratorFn = dyn Fn(&Box) -> Box>>; +type IteratorFn = dyn Fn(&Dynamic) -> Box>; /// Rhai's engine type. This is what you use to run Rhai scripts /// @@ -160,7 +161,7 @@ pub enum FnIntExt { Int(FnDef), } -pub type FnAny = dyn Fn(Vec<&mut dyn Any>) -> Result, EvalAltResult>; +pub type FnAny = dyn Fn(FnCallArgs) -> Result; /// A type containing information about current scope. /// Useful for keeping state between `Engine` runs @@ -176,7 +177,7 @@ pub type FnAny = dyn Fn(Vec<&mut dyn Any>) -> Result, EvalAltResult /// ``` /// /// Between runs, `Engine` only remembers functions when not using own `Scope`. -pub type Scope = Vec<(String, Box)>; +pub type Scope = Vec<(String, Dynamic)>; impl Engine { pub fn call_fn<'a, I, A, T>(&self, ident: I, args: A) -> Result @@ -195,11 +196,7 @@ impl Engine { /// Universal method for calling functions, that are either /// registered with the `Engine` or written in Rhai - pub fn call_fn_raw( - &self, - ident: String, - args: Vec<&mut dyn Any>, - ) -> Result, EvalAltResult> { + pub fn call_fn_raw(&self, ident: String, args: FnCallArgs) -> Result { debug_println!( "Trying to call function {:?} with args {:?}", ident, @@ -225,7 +222,7 @@ impl Engine { .ok_or_else(|| { let typenames = args .iter() - .map(|x| (*(&**x).box_clone()).type_name()) + .map(|x| (*(&**x).into_dynamic()).type_name()) .collect::>(); EvalAltResult::ErrorFunctionNotFound(format!( "{} ({})", @@ -260,7 +257,7 @@ impl Engine { f.params .iter() .cloned() - .zip(args.iter().map(|x| (&**x).box_clone())), + .zip(args.iter().map(|x| (&**x).into_dynamic())), ); match self.eval_stmt(&mut scope, &*f.body) { @@ -288,13 +285,13 @@ impl Engine { /// Register an iterator adapter for a type. pub fn register_iterator(&mut self, f: F) where - F: 'static + Fn(&Box) -> Box>>, + F: 'static + Fn(&Dynamic) -> Box>, { self.type_iterators.insert(TypeId::of::(), Arc::new(f)); } /// Register a get function for a member of a registered type - pub fn register_get(&mut self, name: &str, get_fn: F) + pub fn register_get(&mut self, name: &str, get_fn: F) where F: 'static + Fn(&mut T) -> U, { @@ -303,7 +300,7 @@ impl Engine { } /// Register a set function for a member of a registered type - pub fn register_set(&mut self, name: &str, set_fn: F) + pub fn register_set(&mut self, name: &str, set_fn: F) where F: 'static + Fn(&mut T, U) -> (), { @@ -312,7 +309,7 @@ impl Engine { } /// Shorthand for registering both getters and setters - pub fn register_get_set( + pub fn register_get_set( &mut self, name: &str, get_fn: F, @@ -328,9 +325,9 @@ impl Engine { fn get_dot_val_helper( &self, scope: &mut Scope, - this_ptr: &mut dyn Any, + this_ptr: &mut Variant, dot_rhs: &Expr, - ) -> Result, EvalAltResult> { + ) -> Result { use std::iter::once; match *dot_rhs { @@ -389,7 +386,7 @@ impl Engine { map: F, ) -> Result<(usize, T), EvalAltResult> where - F: FnOnce(&'a mut dyn Any) -> Result, + F: FnOnce(&'a mut Variant) -> Result, { scope .iter_mut() @@ -405,7 +402,7 @@ impl Engine { scope: &mut Scope, id: &str, idx: &Expr, - ) -> Result<(usize, usize, Box), EvalAltResult> { + ) -> Result<(usize, usize, Dynamic), EvalAltResult> { let idx_boxed = self .eval_expr(scope, idx)? .downcast::() @@ -433,10 +430,10 @@ impl Engine { scope: &mut Scope, dot_lhs: &Expr, dot_rhs: &Expr, - ) -> Result, EvalAltResult> { + ) -> Result { match *dot_lhs { Expr::Identifier(ref id) => { - let (sc_idx, mut target) = Self::search_scope(scope, id, |x| Ok(x.box_clone()))?; + let (sc_idx, mut target) = Self::search_scope(scope, id, |x| Ok(x.into_dynamic()))?; let value = self.get_dot_val_helper(scope, target.as_mut(), dot_rhs); // In case the expression mutated `target`, we need to reassign it because @@ -461,10 +458,10 @@ impl Engine { fn set_dot_val_helper( &self, - this_ptr: &mut dyn Any, + this_ptr: &mut Variant, dot_rhs: &Expr, - mut source_val: Box, - ) -> Result, EvalAltResult> { + mut source_val: Dynamic, + ) -> Result { match *dot_rhs { Expr::Identifier(ref id) => { let set_fn_name = "set$".to_string() + id; @@ -495,11 +492,11 @@ impl Engine { scope: &mut Scope, dot_lhs: &Expr, dot_rhs: &Expr, - source_val: Box, - ) -> Result, EvalAltResult> { + source_val: Dynamic, + ) -> Result { match *dot_lhs { Expr::Identifier(ref id) => { - let (sc_idx, mut target) = Self::search_scope(scope, id, |x| Ok(x.box_clone()))?; + let (sc_idx, mut target) = Self::search_scope(scope, id, |x| Ok(x.into_dynamic()))?; let value = self.set_dot_val_helper(target.as_mut(), dot_rhs, source_val); // In case the expression mutated `target`, we need to reassign it because @@ -522,7 +519,7 @@ impl Engine { } } - fn eval_expr(&self, scope: &mut Scope, expr: &Expr) -> Result, EvalAltResult> { + fn eval_expr(&self, scope: &mut Scope, expr: &Expr) -> Result { match *expr { Expr::IntegerConstant(i) => Ok(Box::new(i)), Expr::FloatConstant(i) => Ok(Box::new(i)), @@ -616,12 +613,12 @@ impl Engine { } } - fn eval_stmt(&self, scope: &mut Scope, stmt: &Stmt) -> Result, EvalAltResult> { + fn eval_stmt(&self, scope: &mut Scope, stmt: &Stmt) -> Result { match *stmt { Stmt::Expr(ref e) => self.eval_expr(scope, e), Stmt::Block(ref b) => { let prev_len = scope.len(); - let mut last_result: Result, EvalAltResult> = Ok(Box::new(())); + let mut last_result: Result = Ok(Box::new(())); for s in b.iter() { last_result = self.eval_stmt(scope, s); @@ -801,7 +798,7 @@ impl Engine { ast: &AST, ) -> Result { let AST(os, fns) = ast; - let mut x: Result, EvalAltResult> = Ok(Box::new(())); + let mut x: Result = Ok(Box::new(())); for f in fns { let name = f.name.clone(); @@ -1093,8 +1090,14 @@ impl Engine { reg_func2x!(engine, "push", push, &mut Array, (), f32, f64, bool); reg_func2x!(engine, "push", push, &mut Array, (), String, Array, ()); - engine.register_box_fn("pop", |list: &mut Array| list.pop().unwrap()); - engine.register_box_fn("shift", |list: &mut Array| list.remove(0)); + engine.register_dynamic_fn("pop", |list: &mut Array| list.pop().unwrap_or(Box::new(()))); + engine.register_dynamic_fn("shift", |list: &mut Array| { + if list.len() > 0 { + list.remove(0) + } else { + Box::new(()) + } + }); engine.register_fn("len", |list: &mut Array| -> i64 { list.len().try_into().unwrap() }); @@ -1127,7 +1130,7 @@ impl Engine { a.downcast_ref::>() .unwrap() .clone() - .map(|n| Box::new(n) as Box), + .map(|n| Box::new(n) as Dynamic), ) }); diff --git a/src/fn_register.rs b/src/fn_register.rs index d1bb6b6e..72bf4a7e 100644 --- a/src/fn_register.rs +++ b/src/fn_register.rs @@ -1,13 +1,13 @@ use std::any::TypeId; -use crate::any::Any; -use crate::engine::{Engine, EvalAltResult}; +use crate::any::{Any, Dynamic}; +use crate::engine::{Engine, EvalAltResult, FnCallArgs}; pub trait RegisterFn { fn register_fn(&mut self, name: &str, f: FN); } pub trait RegisterBoxFn { - fn register_box_fn(&mut self, name: &str, f: FN); + fn register_dynamic_fn(&mut self, name: &str, f: FN); } pub struct Ref(A); @@ -23,14 +23,14 @@ macro_rules! def_register { def_register!(imp); }; (imp $($par:ident => $mark:ty => $param:ty => $clone:expr),*) => { - impl<$($par,)* FN, RET> RegisterFn for Engine - where + impl< $($par: Any + Clone,)* FN: Fn($($param),*) -> RET + 'static, - RET: Any, + RET: Any + > RegisterFn for Engine { fn register_fn(&mut self, name: &str, f: FN) { - let fun = move |mut args: Vec<&mut dyn Any>| { + let fun = move |mut args: FnCallArgs| { // Check for length at the beginning to avoid // per-element bound checks. if args.len() != count_args!($($par)*) { @@ -48,19 +48,19 @@ macro_rules! def_register { // Call the user-supplied function using ($clone) to // potentially clone the value, otherwise pass the reference. let r = f($(($clone)($par)),*); - Ok(Box::new(r) as Box) + Ok(Box::new(r) as Dynamic) }; self.register_fn_raw(name.to_owned(), Some(vec![$(TypeId::of::<$par>()),*]), Box::new(fun)); } } - impl<$($par,)* FN> RegisterBoxFn for Engine - where + impl< $($par: Any + Clone,)* - FN: Fn($($param),*) -> Box + 'static + FN: Fn($($param),*) -> Dynamic + 'static, + > RegisterBoxFn for Engine { - fn register_box_fn(&mut self, name: &str, f: FN) { - let fun = move |mut args: Vec<&mut dyn Any>| { + fn register_dynamic_fn(&mut self, name: &str, f: FN) { + let fun = move |mut args: FnCallArgs| { // Check for length at the beginning to avoid // per-element bound checks. if args.len() != count_args!($($par)*) { diff --git a/src/lib.rs b/src/lib.rs index c002e814..841c56b2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,7 +45,7 @@ mod engine; mod fn_register; mod parser; -pub use any::Any; -pub use engine::{Engine, EvalAltResult, Scope}; +pub use any::Dynamic; +pub use engine::{Array, Engine, EvalAltResult, Scope}; pub use fn_register::{RegisterBoxFn, RegisterFn}; pub use parser::{ParseError, ParseErrorType, AST};