diff --git a/src/dynamic.rs b/src/dynamic.rs index 8e9e9efb..de5a4bb8 100644 --- a/src/dynamic.rs +++ b/src/dynamic.rs @@ -475,7 +475,45 @@ impl fmt::Display for Dynamic { #[cfg(not(feature = "no_std"))] Union::TimeStamp(_, _) => f.write_str(""), - Union::Variant(value, _) => f.write_str((*value).type_name()), + Union::Variant(value, _) => { + let _type_id = (***value).type_id(); + + #[cfg(not(feature = "only_i32"))] + #[cfg(not(feature = "only_i64"))] + if _type_id == TypeId::of::() { + return write!(f, "{}", (**value).as_any().downcast_ref::().unwrap()); + } else if _type_id == TypeId::of::() { + return write!(f, "{}", (**value).as_any().downcast_ref::().unwrap()); + } else if _type_id == TypeId::of::() { + return write!(f, "{}", (**value).as_any().downcast_ref::().unwrap()); + } else if _type_id == TypeId::of::() { + return write!(f, "{}", (**value).as_any().downcast_ref::().unwrap()); + } else if _type_id == TypeId::of::() { + return write!(f, "{}", (**value).as_any().downcast_ref::().unwrap()); + } else if _type_id == TypeId::of::() { + return write!(f, "{}", (**value).as_any().downcast_ref::().unwrap()); + } else if _type_id == TypeId::of::() { + return write!(f, "{}", (**value).as_any().downcast_ref::().unwrap()); + } else if _type_id == TypeId::of::() { + return write!(f, "{}", (**value).as_any().downcast_ref::().unwrap()); + } + + #[cfg(not(feature = "no_float"))] + if _type_id == TypeId::of::() { + return write!(f, "{}", (**value).as_any().downcast_ref::().unwrap()); + } else if _type_id == TypeId::of::() { + return write!(f, "{}", (**value).as_any().downcast_ref::().unwrap()); + } + + #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] + if _type_id == TypeId::of::() { + return write!(f, "{}", (**value).as_any().downcast_ref::().unwrap()); + } else if _type_id == TypeId::of::() { + return write!(f, "{}", (**value).as_any().downcast_ref::().unwrap()); + } + + f.write_str((***value).type_name()) + } #[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "sync"))] @@ -516,7 +554,53 @@ impl fmt::Debug for Dynamic { #[cfg(not(feature = "no_std"))] Union::TimeStamp(_, _) => write!(f, ""), - Union::Variant(value, _) => write!(f, "{}", (*value).type_name()), + Union::Variant(value, _) => { + let _type_id = (***value).type_id(); + + #[cfg(not(feature = "only_i32"))] + #[cfg(not(feature = "only_i64"))] + if _type_id == TypeId::of::() { + return write!(f, "{:?}", (**value).as_any().downcast_ref::().unwrap()); + } else if _type_id == TypeId::of::() { + return write!(f, "{:?}", (**value).as_any().downcast_ref::().unwrap()); + } else if _type_id == TypeId::of::() { + return write!(f, "{:?}", (**value).as_any().downcast_ref::().unwrap()); + } else if _type_id == TypeId::of::() { + return write!(f, "{:?}", (**value).as_any().downcast_ref::().unwrap()); + } else if _type_id == TypeId::of::() { + return write!(f, "{:?}", (**value).as_any().downcast_ref::().unwrap()); + } else if _type_id == TypeId::of::() { + return write!(f, "{:?}", (**value).as_any().downcast_ref::().unwrap()); + } else if _type_id == TypeId::of::() { + return write!(f, "{:?}", (**value).as_any().downcast_ref::().unwrap()); + } else if _type_id == TypeId::of::() { + return write!(f, "{:?}", (**value).as_any().downcast_ref::().unwrap()); + } + + #[cfg(not(feature = "no_float"))] + if _type_id == TypeId::of::() { + return write!(f, "{}", (**value).as_any().downcast_ref::().unwrap()); + } else if _type_id == TypeId::of::() { + return write!(f, "{}", (**value).as_any().downcast_ref::().unwrap()); + } + + #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] + if _type_id == TypeId::of::() { + return write!( + f, + "{:?}", + (**value).as_any().downcast_ref::().unwrap() + ); + } else if _type_id == TypeId::of::() { + return write!( + f, + "{:?}", + (**value).as_any().downcast_ref::().unwrap() + ); + } + + write!(f, "{}", (*value).type_name()) + } #[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "sync"))] diff --git a/src/fn_call.rs b/src/fn_call.rs index a63ba83a..8e283a8d 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -186,9 +186,8 @@ impl Engine { .entry(hash_fn) .or_insert_with(|| { let num_args = args.len(); - let max_bitmask = 1usize << num_args; let mut hash = hash_fn; - let mut bitmask = 1usize; + let mut bitmask = 1usize; // Bitmask of which parameter to replace with `Dynamic` loop { //lib.get_fn(hash, pub_only).or_else(|| @@ -210,8 +209,8 @@ impl Engine { // Specific version found Some(f) => return Some(f), - // No more permutations with `Dynamic` wildcards - _ if bitmask >= max_bitmask => return None, + // No parameters + _ if num_args == 0 => return None, // Try all permutations with `Dynamic` wildcards _ => { @@ -219,12 +218,19 @@ impl Engine { let arg_types = args.iter().enumerate().map(|(i, a)| { let mask = 1usize << (num_args - i - 1); if bitmask & mask != 0 { + // Replace with `Dynamic` TypeId::of::() } else { a.type_id() } }); hash = calc_native_fn_hash(empty(), fn_name, arg_types).unwrap(); + + // Stop when all permutations are exhausted + if hash == hash_fn { + return None; + } + bitmask += 1; } } diff --git a/src/packages/string_basic.rs b/src/packages/string_basic.rs index 4024cf2f..faecf29e 100644 --- a/src/packages/string_basic.rs +++ b/src/packages/string_basic.rs @@ -1,13 +1,8 @@ #![allow(non_snake_case)] -use crate::engine::{KEYWORD_DEBUG, KEYWORD_PRINT}; use crate::plugin::*; -use crate::stdlib::{ - fmt::{Debug, Display}, - format, - string::ToString, -}; -use crate::{def_package, FnPtr, ImmutableString, INT}; +use crate::stdlib::{format, string::ToString}; +use crate::{def_package, FnPtr, ImmutableString}; #[cfg(not(feature = "no_index"))] use crate::Array; @@ -15,139 +10,12 @@ use crate::Array; #[cfg(not(feature = "no_object"))] use crate::Map; -#[cfg(feature = "decimal")] -use rust_decimal::Decimal; - -const FUNC_TO_STRING: &'static str = "to_string"; const FUNC_TO_DEBUG: &'static str = "to_debug"; -type Unit = (); - -macro_rules! gen_functions { - ($root:ident => $fn_name:ident ( $($arg_type:ident),+ )) => { - pub mod $root { $(pub mod $arg_type { - use super::super::*; - - #[export_fn(pure)] - pub fn to_string_func(x: &mut $arg_type) -> ImmutableString { - super::super::$fn_name(x) - } - })* } - } -} - -macro_rules! reg_print_functions { - ($mod_name:ident += $root:ident ; $($arg_type:ident),+) => { $( - set_exported_fn!($mod_name, FUNC_TO_STRING, $root::$arg_type::to_string_func); - set_exported_fn!($mod_name, KEYWORD_PRINT, $root::$arg_type::to_string_func); - )* } -} - -macro_rules! reg_debug_functions { - ($mod_name:ident += $root:ident ; $($arg_type:ident),+) => { $( - set_exported_fn!($mod_name, FUNC_TO_DEBUG, $root::$arg_type::to_string_func); - set_exported_fn!($mod_name, KEYWORD_DEBUG, $root::$arg_type::to_string_func); - )* } -} - def_package!(crate:BasicStringPackage:"Basic string utilities, including printing.", lib, { combine_with_exported_module!(lib, "print_debug", print_debug_functions); - - reg_print_functions!(lib += print_basic; INT, bool, char, FnPtr); - reg_debug_functions!(lib += debug_basic; INT, bool, Unit, char, ImmutableString); - - #[cfg(not(feature = "only_i32"))] - #[cfg(not(feature = "only_i64"))] - { - reg_print_functions!(lib += print_numbers; i8, u8, i16, u16, i32, u32, i64, u64); - reg_debug_functions!(lib += debug_numbers; i8, u8, i16, u16, i32, u32, i64, u64); - - #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] - { - reg_print_functions!(lib += print_num_128; i128, u128); - reg_debug_functions!(lib += debug_num_128; i128, u128); - } - } - - #[cfg(not(feature = "no_float"))] - { - reg_print_functions!(lib += print_float_64; f64); - reg_debug_functions!(lib += print_float_64; f64); - reg_print_functions!(lib += print_float_32; f32); - reg_debug_functions!(lib += print_float_32; f32); - } - - #[cfg(feature = "decimal")] - { - reg_print_functions!(lib += print_decimal; Decimal); - reg_debug_functions!(lib += debug_decimal; Decimal); - } }); -fn to_string(x: &mut T) -> ImmutableString { - x.to_string().into() -} -fn to_debug(x: &mut T) -> ImmutableString { - format!("{:?}", x).into() -} -#[cfg(not(feature = "no_float"))] -fn print_f64(x: &mut f64) -> ImmutableString { - #[cfg(feature = "no_std")] - use num_traits::Float; - - let abs = x.abs(); - if abs > 10000000000000.0 || abs < 0.0000000000001 { - format!("{:e}", x).into() - } else { - x.to_string().into() - } -} -#[cfg(not(feature = "no_float"))] -fn print_f32(x: &mut f32) -> ImmutableString { - #[cfg(feature = "no_std")] - use num_traits::Float; - - let abs = x.abs(); - if abs > 10000000000000.0 || abs < 0.0000000000001 { - format!("{:e}", x).into() - } else { - x.to_string().into() - } -} - -gen_functions!(print_basic => to_string(INT, bool, char, FnPtr)); -gen_functions!(debug_basic => to_debug(INT, bool, Unit, char, ImmutableString)); - -#[cfg(not(feature = "only_i32"))] -#[cfg(not(feature = "only_i64"))] -gen_functions!(print_numbers => to_string(i8, u8, i16, u16, i32, u32, i64, u64)); - -#[cfg(not(feature = "only_i32"))] -#[cfg(not(feature = "only_i64"))] -gen_functions!(debug_numbers => to_debug(i8, u8, i16, u16, i32, u32, i64, u64)); - -#[cfg(not(feature = "only_i32"))] -#[cfg(not(feature = "only_i64"))] -#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] -gen_functions!(print_num_128 => to_string(i128, u128)); - -#[cfg(not(feature = "only_i32"))] -#[cfg(not(feature = "only_i64"))] -#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] -gen_functions!(debug_num_128 => to_debug(i128, u128)); - -#[cfg(not(feature = "no_float"))] -gen_functions!(print_float_64 => print_f64(f64)); - -#[cfg(not(feature = "no_float"))] -gen_functions!(print_float_32 => print_f32(f32)); - -#[cfg(feature = "decimal")] -gen_functions!(print_decimal => to_string(Decimal)); - -#[cfg(feature = "decimal")] -gen_functions!(debug_decimal => to_debug(Decimal)); - // Register print and debug #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] @@ -162,6 +30,16 @@ fn print_with_func(fn_name: &str, ctx: &NativeCallContext, value: &mut Dynamic) #[export_module] mod print_debug_functions { + use crate::ImmutableString; + + #[rhai_fn(name = "print", name = "to_string", pure)] + pub fn print_generic(item: &mut Dynamic) -> ImmutableString { + item.to_string().into() + } + #[rhai_fn(name = "debug", name = "to_debug", pure)] + pub fn debug_generic(item: &mut Dynamic) -> ImmutableString { + format!("{:?}", item).into() + } #[rhai_fn(name = "print", name = "debug")] pub fn print_empty_string() -> ImmutableString { "".to_string().into() @@ -176,7 +54,43 @@ mod print_debug_functions { } #[rhai_fn(name = "debug", pure)] pub fn debug_fn_ptr(f: &mut FnPtr) -> ImmutableString { - to_string(f) + f.to_string().into() + } + + #[cfg(not(feature = "no_float"))] + pub mod float_functions { + #[rhai_fn(name = "print", name = "to_string")] + pub fn print_f64(number: f64) -> ImmutableString { + #[cfg(feature = "no_std")] + use num_traits::Float; + + let abs = number.abs(); + if abs > 10000000000000.0 || abs < 0.0000000000001 { + format!("{:e}", number).into() + } else { + number.to_string().into() + } + } + #[rhai_fn(name = "print", name = "to_string")] + pub fn print_f32(number: f32) -> ImmutableString { + #[cfg(feature = "no_std")] + use num_traits::Float; + + let abs = number.abs(); + if abs > 10000000000000.0 || abs < 0.0000000000001 { + format!("{:e}", number).into() + } else { + number.to_string().into() + } + } + #[rhai_fn(name = "debug", name = "to_debug")] + pub fn debug_f64(number: f64) -> ImmutableString { + number.to_string().into() + } + #[rhai_fn(name = "debug", name = "to_debug")] + pub fn debug_f32(number: f32) -> ImmutableString { + number.to_string().into() + } } #[cfg(not(feature = "no_index"))] diff --git a/tests/print.rs b/tests/print.rs index 4adda4e2..c9d7fd28 100644 --- a/tests/print.rs +++ b/tests/print.rs @@ -1,6 +1,33 @@ -use rhai::{Engine, EvalAltResult, RegisterFn, INT}; +use rhai::{Engine, EvalAltResult, RegisterFn, Scope, INT}; use std::sync::{Arc, RwLock}; +#[cfg(not(feature = "only_i32"))] +#[cfg(not(feature = "only_i64"))] +#[test] +fn test_to_string() -> Result<(), Box> { + let engine = Engine::new(); + + let mut scope = Scope::new(); + scope.push("x", 42_u8); + scope.push("y", 42_i32); + scope.push("z", 42_i16); + + assert_eq!( + engine.eval_with_scope::(&mut scope, "x.to_string()")?, + "42" + ); + assert_eq!( + engine.eval_with_scope::(&mut scope, "y.to_string()")?, + "42" + ); + assert_eq!( + engine.eval_with_scope::(&mut scope, "z.to_string()")?, + "42" + ); + + Ok(()) +} + #[test] fn test_print_debug() -> Result<(), Box> { let logbook = Arc::new(RwLock::new(Vec::::new()));