Use std::any::type_name

This commit is contained in:
timfish 2019-09-30 18:57:21 +01:00
parent 20d30d93c3
commit 53bb0a38f0
3 changed files with 38 additions and 37 deletions

View File

@ -1,9 +1,11 @@
use std::any::{Any as StdAny, TypeId}; use std::any::{type_name, Any as StdAny, TypeId};
use std::fmt; use std::fmt;
pub trait Any: StdAny { pub trait Any: StdAny {
fn type_id(&self) -> TypeId; fn type_id(&self) -> TypeId;
fn type_name(&self) -> String;
fn box_clone(&self) -> Box<dyn Any>; fn box_clone(&self) -> Box<dyn Any>;
/// This type may only be implemented by `rhai`. /// This type may only be implemented by `rhai`.
@ -20,6 +22,10 @@ where
TypeId::of::<T>() TypeId::of::<T>()
} }
fn type_name(&self) -> String {
type_name::<T>().to_string()
}
#[inline] #[inline]
fn box_clone(&self) -> Box<dyn Any> { fn box_clone(&self) -> Box<dyn Any> {
Box::new(self.clone()) Box::new(self.clone())

View File

@ -127,7 +127,6 @@ pub struct FnSpec {
pub struct Engine { pub struct Engine {
/// A hashmap containing all functions known to the engine /// A hashmap containing all functions known to the engine
pub fns: HashMap<FnSpec, Arc<FnIntExt>>, pub fns: HashMap<FnSpec, Arc<FnIntExt>>,
pub type_names: HashMap<TypeId, String>,
} }
pub enum FnIntExt { pub enum FnIntExt {
@ -164,7 +163,7 @@ impl Engine {
.and_then(|b| { .and_then(|b| {
b.downcast() b.downcast()
.map(|b| *b) .map(|b| *b)
.map_err(|a| EvalAltResult::ErrorMismatchOutputType(self.nice_type_name(a))) .map_err(|a| EvalAltResult::ErrorMismatchOutputType((*a).type_name()))
}) })
} }
@ -202,7 +201,7 @@ impl Engine {
.ok_or_else(|| { .ok_or_else(|| {
let typenames = args let typenames = args
.iter() .iter()
.map(|x| self.nice_type_name((&**x).box_clone())) .map(|x| (*(&**x).box_clone()).type_name())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
EvalAltResult::ErrorFunctionNotFound(format!("{} ({})", ident, typenames.join(","))) EvalAltResult::ErrorFunctionNotFound(format!("{} ({})", ident, typenames.join(",")))
}) })
@ -239,13 +238,6 @@ impl Engine {
// currently a no-op, exists for future extensibility // currently a no-op, exists for future extensibility
} }
/// Register a type, providing a name for nice error messages.
pub fn register_type_name<T: Any>(&mut self, name: &str) {
self.register_type::<T>();
debug_println!("register type {}: {:?}", name, TypeId::of::<T>());
self.type_names.insert(TypeId::of::<T>(), name.into());
}
/// 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: Clone + Any, U: Clone + Any, F>(&mut self, name: &str, get_fn: F)
where where
@ -632,15 +624,6 @@ impl Engine {
} }
} }
fn nice_type_name(&self, b: Box<dyn Any>) -> String {
let tid = <dyn Any as Any>::type_id(&*b);
if let Some(name) = self.type_names.get(&tid) {
name.to_string()
} else {
format!("<unknown> {:?}", b.type_id())
}
}
/// Evaluate a file /// Evaluate a file
pub fn eval_file<T: Any + Clone>(&mut self, fname: &str) -> Result<T, EvalAltResult> { pub fn eval_file<T: Any + Clone>(&mut self, fname: &str) -> Result<T, EvalAltResult> {
use std::fs::File; use std::fs::File;
@ -705,7 +688,7 @@ impl Engine {
match x.downcast::<T>() { match x.downcast::<T>() {
Ok(out) => Ok(*out), Ok(out) => Ok(*out),
Err(a) => Err(EvalAltResult::ErrorMismatchOutputType( Err(a) => Err(EvalAltResult::ErrorMismatchOutputType(
self.nice_type_name(a), (*a).type_name(),
)), )),
} }
} }
@ -789,18 +772,6 @@ impl Engine {
/// Register the default library. That means, numberic types, char, bool /// Register the default library. That means, numberic types, char, bool
/// String, arithmetics and string concatenations. /// String, arithmetics and string concatenations.
pub fn register_default_lib(engine: &mut Engine) { pub fn register_default_lib(engine: &mut Engine) {
engine.register_type_name::<i32>("i32");
engine.register_type_name::<u32>("u32");
engine.register_type_name::<i64>("integer");
engine.register_type_name::<u64>("u64");
engine.register_type_name::<usize>("usize");
engine.register_type_name::<f32>("f32");
engine.register_type_name::<f64>("float");
engine.register_type_name::<String>("string");
engine.register_type_name::<char>("char");
engine.register_type_name::<bool>("boolean");
engine.register_type_name::<Vec<Box<dyn Any>>>("array");
macro_rules! reg_op { macro_rules! reg_op {
($engine:expr, $x:expr, $op:expr, $( $y:ty ),*) => ( ($engine:expr, $x:expr, $op:expr, $( $y:ty ),*) => (
$( $(
@ -942,8 +913,7 @@ impl Engine {
/// Make a new engine /// Make a new engine
pub fn new() -> Engine { pub fn new() -> Engine {
let mut engine = Engine { let mut engine = Engine {
fns: HashMap::new(), fns: HashMap::new()
type_names: HashMap::new(),
}; };
Engine::register_default_lib(&mut engine); Engine::register_default_lib(&mut engine);

View File

@ -1,4 +1,4 @@
use rhai::{Engine, EvalAltResult}; use rhai::{Engine, EvalAltResult, RegisterFn};
#[test] #[test]
fn test_mismatched_op() { fn test_mismatched_op() {
@ -7,7 +7,32 @@ fn test_mismatched_op() {
assert_eq!( assert_eq!(
engine.eval::<i64>("60 + \"hello\""), engine.eval::<i64>("60 + \"hello\""),
Err(EvalAltResult::ErrorFunctionNotFound( Err(EvalAltResult::ErrorFunctionNotFound(
"+ (integer,string)".into() "+ (i64,alloc::string::String)".into()
))
);
}
#[test]
fn test_mismatched_op_custom_type() {
#[derive(Clone)]
struct TestStruct {
x: i64,
}
impl TestStruct {
fn new() -> TestStruct {
TestStruct { x: 1 }
}
}
let mut engine = Engine::new();
engine.register_type::<TestStruct>();
engine.register_fn("new_ts", TestStruct::new);
assert_eq!(
engine.eval::<i64>("60 + new_ts()"),
Err(EvalAltResult::ErrorFunctionNotFound(
"+ (i64,mismatched_op::test_mismatched_op_custom_type::TestStruct)".into()
)) ))
); );
} }