Simplify API by introducing the Dynamic and Array type aliases.

This commit is contained in:
Stephen Chung 2020-02-25 15:02:27 +08:00
parent 2e296ff9d7
commit 51abc4a2c1
5 changed files with 75 additions and 71 deletions

View File

@ -1,12 +1,15 @@
use std::any::{type_name, Any as StdAny, TypeId}; use std::any::{type_name, Any as StdAny, TypeId};
use std::fmt; use std::fmt;
pub type Variant = dyn Any;
pub type Dynamic = Box<Variant>;
pub trait Any: StdAny { pub trait Any: StdAny {
fn type_id(&self) -> TypeId; fn type_id(&self) -> TypeId;
fn type_name(&self) -> String; fn type_name(&self) -> String;
fn box_clone(&self) -> Box<dyn Any>; fn into_dynamic(&self) -> Dynamic;
/// This type may only be implemented by `rhai`. /// This type may only be implemented by `rhai`.
#[doc(hidden)] #[doc(hidden)]
@ -27,7 +30,7 @@ where
} }
#[inline] #[inline]
fn box_clone(&self) -> Box<dyn Any> { fn into_dynamic(&self) -> Dynamic {
Box::new(self.clone()) Box::new(self.clone())
} }
@ -36,15 +39,15 @@ where
} }
} }
impl dyn Any { impl Variant {
//#[inline] //#[inline]
// fn box_clone(&self) -> Box<dyn Any> { // fn into_dynamic(&self) -> Box<Variant> {
// Any::box_clone(self) // Any::into_dynamic(self)
// } // }
#[inline] #[inline]
pub fn is<T: Any>(&self) -> bool { pub fn is<T: Any>(&self) -> bool {
let t = TypeId::of::<T>(); let t = TypeId::of::<T>();
let boxed = <dyn Any as Any>::type_id(self); let boxed = <Variant as Any>::type_id(self);
t == boxed t == boxed
} }
@ -52,7 +55,7 @@ impl dyn Any {
#[inline] #[inline]
pub fn downcast_ref<T: Any>(&self) -> Option<&T> { pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
if self.is::<T>() { if self.is::<T>() {
unsafe { Some(&*(self as *const dyn Any as *const T)) } unsafe { Some(&*(self as *const Variant as *const T)) }
} else { } else {
None None
} }
@ -61,20 +64,20 @@ impl dyn Any {
#[inline] #[inline]
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> { pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
if self.is::<T>() { if self.is::<T>() {
unsafe { Some(&mut *(self as *mut dyn Any as *mut T)) } unsafe { Some(&mut *(self as *mut Variant as *mut T)) }
} else { } else {
None None
} }
} }
} }
impl Clone for Box<dyn Any> { impl Clone for Dynamic {
fn clone(&self) -> Self { 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 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad("?") f.pad("?")
} }
@ -84,11 +87,11 @@ pub trait AnyExt: Sized {
fn downcast<T: Any + Clone>(self) -> Result<Box<T>, Self>; fn downcast<T: Any + Clone>(self) -> Result<Box<T>, Self>;
} }
impl AnyExt for Box<dyn Any> { impl AnyExt for Dynamic {
fn downcast<T: Any + Clone>(self) -> Result<Box<T>, Self> { fn downcast<T: Any + Clone>(self) -> Result<Box<T>, Self> {
if self.is::<T>() { if self.is::<T>() {
unsafe { 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)) Ok(Box::from_raw(raw as *mut T))
} }
} else { } else {

View File

@ -1,24 +1,22 @@
//! Helper module which defines `FnArgs` //! Helper module which defines `FnArgs`
//! to make function calling easier. //! to make function calling easier.
use crate::any::Any; use crate::any::{Any, Variant};
pub trait FunArgs<'a> { 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 { macro_rules! impl_args {
($($p:ident),*) => { ($($p:ident),*) => {
impl<'a, $($p),*> FunArgs<'a> for ($(&'a mut $p,)*) impl<'a, $($p: Any + Clone),*> FunArgs<'a> for ($(&'a mut $p,)*)
where
$($p: Any + Clone),*
{ {
fn into_vec(self) -> Vec<&'a mut dyn Any> { fn into_vec(self) -> Vec<&'a mut Variant> {
let ($($p,)*) = self; let ($($p,)*) = self;
#[allow(unused_variables, unused_mut)] #[allow(unused_variables, unused_mut)]
let mut v = Vec::new(); let mut v = Vec::new();
$(v.push($p as &mut dyn Any);)* $(v.push($p as &mut Variant);)*
v v
} }

View File

@ -6,13 +6,14 @@ use std::fmt;
use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Shl, Shr, Sub}; use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Shl, Shr, Sub};
use std::{convert::TryInto, sync::Arc}; use std::{convert::TryInto, sync::Arc};
use crate::any::{Any, AnyExt}; use crate::any::{Any, AnyExt, Dynamic, Variant};
use crate::call::FunArgs; use crate::call::FunArgs;
use crate::fn_register::{RegisterBoxFn, RegisterFn}; use crate::fn_register::{RegisterBoxFn, RegisterFn};
use crate::parser::{lex, parse, Expr, FnDef, ParseError, Stmt, AST}; use crate::parser::{lex, parse, Expr, FnDef, ParseError, Stmt, AST};
use fmt::{Debug, Display}; use fmt::{Debug, Display};
type Array = Vec<Box<dyn Any>>; pub type Array = Vec<Dynamic>;
pub type FnCallArgs<'a> = Vec<&'a mut Variant>;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum EvalAltResult { pub enum EvalAltResult {
@ -30,7 +31,7 @@ pub enum EvalAltResult {
ErrorCantOpenScriptFile(String), ErrorCantOpenScriptFile(String),
ErrorMalformedDotExpression, ErrorMalformedDotExpression,
LoopBreak, LoopBreak,
Return(Box<dyn Any>), Return(Dynamic),
} }
impl EvalAltResult { impl EvalAltResult {
@ -131,7 +132,7 @@ pub struct FnSpec {
args: Option<Vec<TypeId>>, args: Option<Vec<TypeId>>,
} }
type IteratorFn = dyn Fn(&Box<dyn Any>) -> Box<dyn Iterator<Item = Box<dyn Any>>>; type IteratorFn = dyn Fn(&Dynamic) -> Box<dyn Iterator<Item = Dynamic>>;
/// Rhai's engine type. This is what you use to run Rhai scripts /// Rhai's engine type. This is what you use to run Rhai scripts
/// ///
@ -160,7 +161,7 @@ pub enum FnIntExt {
Int(FnDef), Int(FnDef),
} }
pub type FnAny = dyn Fn(Vec<&mut dyn Any>) -> Result<Box<dyn Any>, EvalAltResult>; pub type FnAny = dyn Fn(FnCallArgs) -> Result<Dynamic, EvalAltResult>;
/// A type containing information about current scope. /// A type containing information about current scope.
/// Useful for keeping state between `Engine` runs /// Useful for keeping state between `Engine` runs
@ -176,7 +177,7 @@ pub type FnAny = dyn Fn(Vec<&mut dyn Any>) -> Result<Box<dyn Any>, EvalAltResult
/// ``` /// ```
/// ///
/// Between runs, `Engine` only remembers functions when not using own `Scope`. /// Between runs, `Engine` only remembers functions when not using own `Scope`.
pub type Scope = Vec<(String, Box<dyn Any>)>; pub type Scope = Vec<(String, Dynamic)>;
impl Engine { impl Engine {
pub fn call_fn<'a, I, A, T>(&self, ident: I, args: A) -> Result<T, EvalAltResult> pub fn call_fn<'a, I, A, T>(&self, ident: I, args: A) -> Result<T, EvalAltResult>
@ -195,11 +196,7 @@ impl Engine {
/// Universal method for calling functions, that are either /// Universal method for calling functions, that are either
/// registered with the `Engine` or written in Rhai /// registered with the `Engine` or written in Rhai
pub fn call_fn_raw( pub fn call_fn_raw(&self, ident: String, args: FnCallArgs) -> Result<Dynamic, EvalAltResult> {
&self,
ident: String,
args: Vec<&mut dyn Any>,
) -> Result<Box<dyn Any>, EvalAltResult> {
debug_println!( debug_println!(
"Trying to call function {:?} with args {:?}", "Trying to call function {:?} with args {:?}",
ident, ident,
@ -225,7 +222,7 @@ impl Engine {
.ok_or_else(|| { .ok_or_else(|| {
let typenames = args let typenames = args
.iter() .iter()
.map(|x| (*(&**x).box_clone()).type_name()) .map(|x| (*(&**x).into_dynamic()).type_name())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
EvalAltResult::ErrorFunctionNotFound(format!( EvalAltResult::ErrorFunctionNotFound(format!(
"{} ({})", "{} ({})",
@ -260,7 +257,7 @@ impl Engine {
f.params f.params
.iter() .iter()
.cloned() .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) { match self.eval_stmt(&mut scope, &*f.body) {
@ -288,13 +285,13 @@ impl Engine {
/// Register an iterator adapter for a type. /// Register an iterator adapter for a type.
pub fn register_iterator<T: Any, F>(&mut self, f: F) pub fn register_iterator<T: Any, F>(&mut self, f: F)
where where
F: 'static + Fn(&Box<dyn Any>) -> Box<dyn Iterator<Item = Box<dyn Any>>>, F: 'static + Fn(&Dynamic) -> Box<dyn Iterator<Item = Dynamic>>,
{ {
self.type_iterators.insert(TypeId::of::<T>(), Arc::new(f)); self.type_iterators.insert(TypeId::of::<T>(), Arc::new(f));
} }
/// Register a get function for a member of a registered type /// Register a get function for a member of a registered type
pub fn register_get<T: Clone + Any, U: Clone + Any, F>(&mut self, name: &str, get_fn: F) pub fn register_get<T: Any + Clone, U: Any + Clone, F>(&mut self, name: &str, get_fn: F)
where where
F: 'static + Fn(&mut T) -> U, F: 'static + Fn(&mut T) -> U,
{ {
@ -303,7 +300,7 @@ impl Engine {
} }
/// Register a set function for a member of a registered type /// Register a set function for a member of a registered type
pub fn register_set<T: Clone + Any, U: Clone + Any, F>(&mut self, name: &str, set_fn: F) pub fn register_set<T: Any + Clone, U: Any + Clone, F>(&mut self, name: &str, set_fn: F)
where where
F: 'static + Fn(&mut T, U) -> (), F: 'static + Fn(&mut T, U) -> (),
{ {
@ -312,7 +309,7 @@ impl Engine {
} }
/// Shorthand for registering both getters and setters /// Shorthand for registering both getters and setters
pub fn register_get_set<T: Clone + Any, U: Clone + Any, F, G>( pub fn register_get_set<T: Any + Clone, U: Any + Clone, F, G>(
&mut self, &mut self,
name: &str, name: &str,
get_fn: F, get_fn: F,
@ -328,9 +325,9 @@ impl Engine {
fn get_dot_val_helper( fn get_dot_val_helper(
&self, &self,
scope: &mut Scope, scope: &mut Scope,
this_ptr: &mut dyn Any, this_ptr: &mut Variant,
dot_rhs: &Expr, dot_rhs: &Expr,
) -> Result<Box<dyn Any>, EvalAltResult> { ) -> Result<Dynamic, EvalAltResult> {
use std::iter::once; use std::iter::once;
match *dot_rhs { match *dot_rhs {
@ -389,7 +386,7 @@ impl Engine {
map: F, map: F,
) -> Result<(usize, T), EvalAltResult> ) -> Result<(usize, T), EvalAltResult>
where where
F: FnOnce(&'a mut dyn Any) -> Result<T, EvalAltResult>, F: FnOnce(&'a mut Variant) -> Result<T, EvalAltResult>,
{ {
scope scope
.iter_mut() .iter_mut()
@ -405,7 +402,7 @@ impl Engine {
scope: &mut Scope, scope: &mut Scope,
id: &str, id: &str,
idx: &Expr, idx: &Expr,
) -> Result<(usize, usize, Box<dyn Any>), EvalAltResult> { ) -> Result<(usize, usize, Dynamic), EvalAltResult> {
let idx_boxed = self let idx_boxed = self
.eval_expr(scope, idx)? .eval_expr(scope, idx)?
.downcast::<i64>() .downcast::<i64>()
@ -433,10 +430,10 @@ impl Engine {
scope: &mut Scope, scope: &mut Scope,
dot_lhs: &Expr, dot_lhs: &Expr,
dot_rhs: &Expr, dot_rhs: &Expr,
) -> Result<Box<dyn Any>, EvalAltResult> { ) -> Result<Dynamic, EvalAltResult> {
match *dot_lhs { match *dot_lhs {
Expr::Identifier(ref id) => { 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); 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 // In case the expression mutated `target`, we need to reassign it because
@ -461,10 +458,10 @@ impl Engine {
fn set_dot_val_helper( fn set_dot_val_helper(
&self, &self,
this_ptr: &mut dyn Any, this_ptr: &mut Variant,
dot_rhs: &Expr, dot_rhs: &Expr,
mut source_val: Box<dyn Any>, mut source_val: Dynamic,
) -> Result<Box<dyn Any>, EvalAltResult> { ) -> Result<Dynamic, EvalAltResult> {
match *dot_rhs { match *dot_rhs {
Expr::Identifier(ref id) => { Expr::Identifier(ref id) => {
let set_fn_name = "set$".to_string() + id; let set_fn_name = "set$".to_string() + id;
@ -495,11 +492,11 @@ impl Engine {
scope: &mut Scope, scope: &mut Scope,
dot_lhs: &Expr, dot_lhs: &Expr,
dot_rhs: &Expr, dot_rhs: &Expr,
source_val: Box<dyn Any>, source_val: Dynamic,
) -> Result<Box<dyn Any>, EvalAltResult> { ) -> Result<Dynamic, EvalAltResult> {
match *dot_lhs { match *dot_lhs {
Expr::Identifier(ref id) => { 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); 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 // 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<Box<dyn Any>, EvalAltResult> { fn eval_expr(&self, scope: &mut Scope, expr: &Expr) -> Result<Dynamic, EvalAltResult> {
match *expr { match *expr {
Expr::IntegerConstant(i) => Ok(Box::new(i)), Expr::IntegerConstant(i) => Ok(Box::new(i)),
Expr::FloatConstant(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<Box<dyn Any>, EvalAltResult> { fn eval_stmt(&self, scope: &mut Scope, stmt: &Stmt) -> Result<Dynamic, EvalAltResult> {
match *stmt { match *stmt {
Stmt::Expr(ref e) => self.eval_expr(scope, e), Stmt::Expr(ref e) => self.eval_expr(scope, e),
Stmt::Block(ref b) => { Stmt::Block(ref b) => {
let prev_len = scope.len(); let prev_len = scope.len();
let mut last_result: Result<Box<dyn Any>, EvalAltResult> = Ok(Box::new(())); let mut last_result: Result<Dynamic, EvalAltResult> = Ok(Box::new(()));
for s in b.iter() { for s in b.iter() {
last_result = self.eval_stmt(scope, s); last_result = self.eval_stmt(scope, s);
@ -801,7 +798,7 @@ impl Engine {
ast: &AST, ast: &AST,
) -> Result<T, EvalAltResult> { ) -> Result<T, EvalAltResult> {
let AST(os, fns) = ast; let AST(os, fns) = ast;
let mut x: Result<Box<dyn Any>, EvalAltResult> = Ok(Box::new(())); let mut x: Result<Dynamic, EvalAltResult> = Ok(Box::new(()));
for f in fns { for f in fns {
let name = f.name.clone(); 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, (), f32, f64, bool);
reg_func2x!(engine, "push", push, &mut Array, (), String, Array, ()); reg_func2x!(engine, "push", push, &mut Array, (), String, Array, ());
engine.register_box_fn("pop", |list: &mut Array| list.pop().unwrap()); engine.register_dynamic_fn("pop", |list: &mut Array| list.pop().unwrap_or(Box::new(())));
engine.register_box_fn("shift", |list: &mut Array| list.remove(0)); 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 { engine.register_fn("len", |list: &mut Array| -> i64 {
list.len().try_into().unwrap() list.len().try_into().unwrap()
}); });
@ -1127,7 +1130,7 @@ impl Engine {
a.downcast_ref::<Range<i64>>() a.downcast_ref::<Range<i64>>()
.unwrap() .unwrap()
.clone() .clone()
.map(|n| Box::new(n) as Box<dyn Any>), .map(|n| Box::new(n) as Dynamic),
) )
}); });

View File

@ -1,13 +1,13 @@
use std::any::TypeId; use std::any::TypeId;
use crate::any::Any; use crate::any::{Any, Dynamic};
use crate::engine::{Engine, EvalAltResult}; use crate::engine::{Engine, EvalAltResult, FnCallArgs};
pub trait RegisterFn<FN, ARGS, RET> { pub trait RegisterFn<FN, ARGS, RET> {
fn register_fn(&mut self, name: &str, f: FN); fn register_fn(&mut self, name: &str, f: FN);
} }
pub trait RegisterBoxFn<FN, ARGS> { pub trait RegisterBoxFn<FN, ARGS> {
fn register_box_fn(&mut self, name: &str, f: FN); fn register_dynamic_fn(&mut self, name: &str, f: FN);
} }
pub struct Ref<A>(A); pub struct Ref<A>(A);
@ -23,14 +23,14 @@ macro_rules! def_register {
def_register!(imp); def_register!(imp);
}; };
(imp $($par:ident => $mark:ty => $param:ty => $clone:expr),*) => { (imp $($par:ident => $mark:ty => $param:ty => $clone:expr),*) => {
impl<$($par,)* FN, RET> RegisterFn<FN, ($($mark,)*), RET> for Engine impl<
where
$($par: Any + Clone,)* $($par: Any + Clone,)*
FN: Fn($($param),*) -> RET + 'static, FN: Fn($($param),*) -> RET + 'static,
RET: Any, RET: Any
> RegisterFn<FN, ($($mark,)*), RET> for Engine
{ {
fn register_fn(&mut self, name: &str, f: FN) { 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 // Check for length at the beginning to avoid
// per-element bound checks. // per-element bound checks.
if args.len() != count_args!($($par)*) { if args.len() != count_args!($($par)*) {
@ -48,19 +48,19 @@ macro_rules! def_register {
// Call the user-supplied function using ($clone) to // Call the user-supplied function using ($clone) to
// potentially clone the value, otherwise pass the reference. // potentially clone the value, otherwise pass the reference.
let r = f($(($clone)($par)),*); let r = f($(($clone)($par)),*);
Ok(Box::new(r) as Box<dyn Any>) Ok(Box::new(r) as Dynamic)
}; };
self.register_fn_raw(name.to_owned(), Some(vec![$(TypeId::of::<$par>()),*]), Box::new(fun)); self.register_fn_raw(name.to_owned(), Some(vec![$(TypeId::of::<$par>()),*]), Box::new(fun));
} }
} }
impl<$($par,)* FN> RegisterBoxFn<FN, ($($mark,)*)> for Engine impl<
where
$($par: Any + Clone,)* $($par: Any + Clone,)*
FN: Fn($($param),*) -> Box<dyn Any> + 'static FN: Fn($($param),*) -> Dynamic + 'static,
> RegisterBoxFn<FN, ($($mark,)*)> for Engine
{ {
fn register_box_fn(&mut self, name: &str, f: FN) { fn register_dynamic_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 // Check for length at the beginning to avoid
// per-element bound checks. // per-element bound checks.
if args.len() != count_args!($($par)*) { if args.len() != count_args!($($par)*) {

View File

@ -45,7 +45,7 @@ mod engine;
mod fn_register; mod fn_register;
mod parser; mod parser;
pub use any::Any; pub use any::Dynamic;
pub use engine::{Engine, EvalAltResult, Scope}; pub use engine::{Array, Engine, EvalAltResult, Scope};
pub use fn_register::{RegisterBoxFn, RegisterFn}; pub use fn_register::{RegisterBoxFn, RegisterFn};
pub use parser::{ParseError, ParseErrorType, AST}; pub use parser::{ParseError, ParseErrorType, AST};