From 0a7cca9910d381bf3fe9dcd76afaa7638a2b25df Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sat, 6 May 2023 02:08:32 +0800 Subject: [PATCH] Add Dynamic::try_cast_raw --- src/api/eval.rs | 12 ++++---- src/eval/stmt.rs | 9 ++++-- src/func/call.rs | 24 +++++++++------ src/types/dynamic.rs | 71 +++++++++++++++++++++++++------------------- 4 files changed, 69 insertions(+), 47 deletions(-) diff --git a/src/api/eval.rs b/src/api/eval.rs index 60a9b816..741714f7 100644 --- a/src/api/eval.rs +++ b/src/api/eval.rs @@ -212,11 +212,13 @@ impl Engine { return Ok(reify! { result => T }); } - let typ = self.map_type_name(result.type_name()); - - result.try_cast::().ok_or_else(|| { - let t = self.map_type_name(type_name::()).into(); - ERR::ErrorMismatchOutputType(t, typ.into(), Position::NONE).into() + result.try_cast_raw::().map_err(|v| { + ERR::ErrorMismatchOutputType( + self.map_type_name(type_name::()).into(), + self.map_type_name(v.type_name()).into(), + Position::NONE, + ) + .into() }) } /// Evaluate an [`AST`] with own scope, returning the result value or an error. diff --git a/src/eval/stmt.rs b/src/eval/stmt.rs index a58cbbc3..f1ea9423 100644 --- a/src/eval/stmt.rs +++ b/src/eval/stmt.rs @@ -861,9 +861,12 @@ impl Engine { } let v = self.eval_expr(global, caches, scope, this_ptr, expr)?; - let typ = v.type_name(); - let path = v.try_cast::().ok_or_else(|| { - self.make_type_mismatch_err::(typ, expr.position()) + + let path = v.try_cast_raw::().map_err(|v| { + self.make_type_mismatch_err::( + v.type_name(), + expr.position(), + ) })?; let path_pos = expr.start_position(); diff --git a/src/func/call.rs b/src/func/call.rs index f52fb915..05e153b7 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -796,9 +796,11 @@ impl Engine { debug_assert!(!call_args.is_empty()); // FnPtr call on object - let typ = call_args[0].type_name(); - let fn_ptr = call_args[0].take().try_cast::().ok_or_else(|| { - self.make_type_mismatch_err::(self.map_type_name(typ), first_arg_pos) + let fn_ptr = call_args[0].take().try_cast_raw::().map_err(|v| { + self.make_type_mismatch_err::( + self.map_type_name(v.type_name()), + first_arg_pos, + ) })?; #[cfg(not(feature = "no_function"))] @@ -1025,9 +1027,11 @@ impl Engine { let (first_arg_value, first_arg_pos) = self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), arg)?; - let typ = first_arg_value.type_name(); - let fn_ptr = first_arg_value.try_cast::().ok_or_else(|| { - self.make_type_mismatch_err::(self.map_type_name(typ), first_arg_pos) + let fn_ptr = first_arg_value.try_cast_raw::().map_err(|v| { + self.make_type_mismatch_err::( + self.map_type_name(v.type_name()), + first_arg_pos, + ) })?; #[cfg(not(feature = "no_function"))] @@ -1104,9 +1108,11 @@ impl Engine { let (first_arg_value, first_arg_pos) = self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), first)?; - let typ = first_arg_value.type_name(); - let mut fn_ptr = first_arg_value.try_cast::().ok_or_else(|| { - self.make_type_mismatch_err::(self.map_type_name(typ), first_arg_pos) + let mut fn_ptr = first_arg_value.try_cast_raw::().map_err(|v| { + self.make_type_mismatch_err::( + self.map_type_name(v.type_name()), + first_arg_pos, + ) })?; // Append the new curried arguments to the existing list. diff --git a/src/types/dynamic.rs b/src/types/dynamic.rs index c3887d86..041e8884 100644 --- a/src/types/dynamic.rs +++ b/src/types/dynamic.rs @@ -1174,108 +1174,119 @@ impl Dynamic { /// /// assert_eq!(x.try_cast::().expect("x should be u32"), 42); /// ``` - #[inline] + #[inline(always)] #[must_use] #[allow(unused_mut)] pub fn try_cast(mut self) -> Option { + self.try_cast_raw().ok() + } + /// Convert the [`Dynamic`] value into specific type. + /// + /// Casting to a [`Dynamic`] just returns as is, but if it contains a shared value, + /// it is cloned into a [`Dynamic`] with a normal value. + /// + /// Returns itself if types mismatched. + pub(crate) fn try_cast_raw(mut self) -> Result { // Coded this way in order to maximally leverage potentials for dead-code removal. #[cfg(not(feature = "no_closure"))] self.flatten_in_place(); if TypeId::of::() == TypeId::of::() { - return Some(reify! { self => !!! T }); + return Ok(reify! { self => !!! T }); } if TypeId::of::() == TypeId::of::<()>() { return match self.0 { - Union::Unit(..) => Some(reify! { () => !!! T }), - _ => None, + Union::Unit(..) => Ok(reify! { () => !!! T }), + _ => Err(self), }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Int(n, ..) => Some(reify! { n => !!! T }), - _ => None, + Union::Int(n, ..) => Ok(reify! { n => !!! T }), + _ => Err(self), }; } #[cfg(not(feature = "no_float"))] if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Float(v, ..) => Some(reify! { *v => !!! T }), - _ => None, + Union::Float(v, ..) => Ok(reify! { *v => !!! T }), + _ => Err(self), }; } #[cfg(feature = "decimal")] if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Decimal(v, ..) => Some(reify! { *v => !!! T }), - _ => None, + Union::Decimal(v, ..) => Ok(reify! { *v => !!! T }), + _ => Err(self), }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Bool(b, ..) => Some(reify! { b => !!! T }), - _ => None, + Union::Bool(b, ..) => Ok(reify! { b => !!! T }), + _ => Err(self), }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Str(s, ..) => Some(reify! { s => !!! T }), - _ => None, + Union::Str(s, ..) => Ok(reify! { s => !!! T }), + _ => Err(self), }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Str(s, ..) => Some(reify! { s.to_string() => !!! T }), - _ => None, + Union::Str(s, ..) => Ok(reify! { s.to_string() => !!! T }), + _ => Err(self), }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Char(c, ..) => Some(reify! { c => !!! T }), - _ => None, + Union::Char(c, ..) => Ok(reify! { c => !!! T }), + _ => Err(self), }; } #[cfg(not(feature = "no_index"))] if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Array(a, ..) => Some(reify! { *a => !!! T }), - _ => None, + Union::Array(a, ..) => Ok(reify! { *a => !!! T }), + _ => Err(self), }; } #[cfg(not(feature = "no_index"))] if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Blob(b, ..) => Some(reify! { *b => !!! T }), - _ => None, + Union::Blob(b, ..) => Ok(reify! { *b => !!! T }), + _ => Err(self), }; } #[cfg(not(feature = "no_object"))] if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Map(m, ..) => Some(reify! { *m => !!! T }), - _ => None, + Union::Map(m, ..) => Ok(reify! { *m => !!! T }), + _ => Err(self), }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::FnPtr(f, ..) => Some(reify! { *f => !!! T }), - _ => None, + Union::FnPtr(f, ..) => Ok(reify! { *f => !!! T }), + _ => Err(self), }; } #[cfg(not(feature = "no_time"))] if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::TimeStamp(t, ..) => Some(reify! { *t => !!! T }), - _ => None, + Union::TimeStamp(t, ..) => Ok(reify! { *t => !!! T }), + _ => Err(self), }; } match self.0 { - Union::Variant(v, ..) => (*v).as_boxed_any().downcast().ok().map(|x| *x), + Union::Variant(v, ..) if TypeId::of::() == (**v).type_id() => { + Ok((*v).as_boxed_any().downcast().map(|x| *x).unwrap()) + } #[cfg(not(feature = "no_closure"))] Union::Shared(..) => unreachable!("Union::Shared case should be already handled"), - _ => None, + _ => Err(self), } } /// Convert the [`Dynamic`] value into a specific type.