From 29f1328087604463843bf6966146672ac83e11c6 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sun, 2 Jan 2022 20:47:03 +0800 Subject: [PATCH] Simplify Dynamic::from for better inlining. --- src/api/custom_syntax.rs | 16 +++---- src/func/register.rs | 5 +-- src/types/dynamic.rs | 94 +++++++++++++++++----------------------- src/unsafe.rs | 45 ++++++++++++------- 4 files changed, 77 insertions(+), 83 deletions(-) diff --git a/src/api/custom_syntax.rs b/src/api/custom_syntax.rs index c22503d2..782b6034 100644 --- a/src/api/custom_syntax.rs +++ b/src/api/custom_syntax.rs @@ -95,41 +95,39 @@ impl Expression<'_> { if TypeId::of::() == TypeId::of::() { return match self.0 { - Expr::IntegerConstant(x, _) => unsafe_try_cast(*x).ok(), + Expr::IntegerConstant(x, _) => unsafe_try_cast(*x), _ => None, }; } #[cfg(not(feature = "no_float"))] if TypeId::of::() == TypeId::of::() { return match self.0 { - Expr::FloatConstant(x, _) => unsafe_try_cast(*x).ok(), + Expr::FloatConstant(x, _) => unsafe_try_cast(*x), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Expr::CharConstant(x, _) => unsafe_try_cast(*x).ok(), + Expr::CharConstant(x, _) => unsafe_try_cast(*x), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Expr::StringConstant(x, _) => unsafe_try_cast(x.clone()).ok(), - Expr::Variable(_, _, x) => { - unsafe_try_cast(Into::::into(&x.2)).ok() - } + Expr::StringConstant(x, _) => unsafe_try_cast(x.clone()), + Expr::Variable(_, _, x) => unsafe_try_cast(Into::::into(&x.2)), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Expr::BoolConstant(x, _) => unsafe_try_cast(*x).ok(), + Expr::BoolConstant(x, _) => unsafe_try_cast(*x), _ => None, }; } if TypeId::of::() == TypeId::of::<()>() { return match self.0 { - Expr::Unit(_) => unsafe_try_cast(()).ok(), + Expr::Unit(_) => unsafe_try_cast(()), _ => None, }; } diff --git a/src/func/register.rs b/src/func/register.rs index daa93d41..70085821 100644 --- a/src/func/register.rs +++ b/src/func/register.rs @@ -5,7 +5,7 @@ use super::call::FnCallArgs; use super::callable_function::CallableFunction; use super::native::{FnAny, SendSync}; -use crate::r#unsafe::unsafe_try_cast; +use crate::r#unsafe::unsafe_cast; use crate::tokenizer::Position; use crate::types::dynamic::{DynamicWriteLock, Variant}; use crate::{Dynamic, NativeCallContext, RhaiResultOf, ERR}; @@ -50,8 +50,7 @@ pub fn by_value(data: &mut Dynamic) -> T { ref_t.clone() } else if TypeId::of::() == TypeId::of::() { // If T is `String`, data must be `ImmutableString`, so map directly to it - let value = mem::take(data).into_string().expect("`ImmutableString`"); - unsafe_try_cast(value).expect("checked") + unsafe_cast(mem::take(data).into_string().expect("`ImmutableString`")) } else { // We consume the argument and then replace it with () - the argument is not supposed to be used again. // This way, we avoid having to clone the argument again, because it is already a clone when passed here. diff --git a/src/types/dynamic.rs b/src/types/dynamic.rs index eefcc2f4..d86422c8 100644 --- a/src/types/dynamic.rs +++ b/src/types/dynamic.rs @@ -1,7 +1,7 @@ //! Helper module which defines the [`Any`] trait to to allow dynamic value handling. use crate::func::native::SendSync; -use crate::r#unsafe::{unsafe_cast_box, unsafe_try_cast}; +use crate::r#unsafe::{unsafe_cast, unsafe_cast_box, unsafe_try_cast}; use crate::{ExclusiveRange, FnPtr, ImmutableString, InclusiveRange, INT}; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -1209,11 +1209,11 @@ impl Dynamic { /// ``` #[inline] #[must_use] - pub fn from(mut value: T) -> Self { + pub fn from(value: T) -> Self { // Coded this way in order to maximally leverage potentials for dead-code removal. if TypeId::of::() == TypeId::of::() { - return unsafe_try_cast::<_, Dynamic>(value).ok().expect(CHECKED); + return unsafe_cast::<_, Dynamic>(value); } let val = value.as_any(); @@ -1249,52 +1249,36 @@ impl Dynamic { return ().into(); } - value = match unsafe_try_cast::<_, String>(value) { - Ok(s) => return s.into(), - Err(value) => value, - }; - #[cfg(not(feature = "no_index"))] - { - value = match unsafe_try_cast::<_, crate::Array>(value) { - Ok(array) => return array.into(), - Err(value) => value, - }; + if TypeId::of::() == TypeId::of::() { + return unsafe_cast::<_, String>(value).into(); + } + #[cfg(not(feature = "no_float"))] + if TypeId::of::() == TypeId::of::() { + return unsafe_cast::<_, crate::FLOAT>(value).into(); } #[cfg(not(feature = "no_index"))] - { - value = match unsafe_try_cast::<_, crate::Blob>(value) { - Ok(blob) => return Dynamic::from_blob(blob), // don't use blob.into() because it'll be converted into an Array - Err(value) => value, - }; + if TypeId::of::() == TypeId::of::() { + return unsafe_cast::<_, crate::Array>(value).into(); + } + #[cfg(not(feature = "no_index"))] + if TypeId::of::() == TypeId::of::() { + return Dynamic::from_blob(unsafe_cast::<_, crate::Blob>(value)); // don't use blob.into() because it'll be converted into an Array } - #[cfg(not(feature = "no_object"))] - { - value = match unsafe_try_cast::<_, crate::Map>(value) { - Ok(map) => return map.into(), - Err(value) => value, - }; + if TypeId::of::() == TypeId::of::() { + return unsafe_cast::<_, crate::Map>(value).into(); + } + if TypeId::of::() == TypeId::of::() { + return unsafe_cast::<_, FnPtr>(value).into(); } - - value = match unsafe_try_cast::<_, FnPtr>(value) { - Ok(fn_ptr) => return fn_ptr.into(), - Err(value) => value, - }; #[cfg(not(feature = "no_std"))] - { - value = match unsafe_try_cast::<_, Instant>(value) { - Ok(timestamp) => return timestamp.into(), - Err(value) => value, - }; + if TypeId::of::() == TypeId::of::() { + return unsafe_cast::<_, Instant>(value).into(); } - #[cfg(not(feature = "no_closure"))] - { - value = match unsafe_try_cast::<_, crate::Shared>>(value) { - Ok(value) => return value.into(), - Err(value) => value, - }; + if TypeId::of::() == TypeId::of::>>() { + return unsafe_cast::<_, crate::Shared>>(value).into(); } Self(Union::Variant( @@ -1365,12 +1349,12 @@ impl Dynamic { } if TypeId::of::() == TypeId::of::() { - return unsafe_try_cast::<_, T>(self).ok(); + return unsafe_try_cast::<_, T>(self); } if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Int(value, _, _) => unsafe_try_cast(value).ok(), + Union::Int(value, _, _) => unsafe_try_cast(value), _ => None, }; } @@ -1378,7 +1362,7 @@ impl Dynamic { #[cfg(not(feature = "no_float"))] if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Float(value, _, _) => unsafe_try_cast(*value).ok(), + Union::Float(value, _, _) => unsafe_try_cast(*value), _ => None, }; } @@ -1386,35 +1370,35 @@ impl Dynamic { #[cfg(feature = "decimal")] if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Decimal(value, _, _) => unsafe_try_cast(*value).ok(), + Union::Decimal(value, _, _) => unsafe_try_cast(*value), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Bool(value, _, _) => unsafe_try_cast(value).ok(), + Union::Bool(value, _, _) => unsafe_try_cast(value), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Str(value, _, _) => unsafe_try_cast(value).ok(), + Union::Str(value, _, _) => unsafe_try_cast(value), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Str(value, _, _) => unsafe_try_cast(value.into_owned()).ok(), + Union::Str(value, _, _) => unsafe_try_cast(value.into_owned()), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Char(value, _, _) => unsafe_try_cast(value).ok(), + Union::Char(value, _, _) => unsafe_try_cast(value), _ => None, }; } @@ -1422,7 +1406,7 @@ impl Dynamic { #[cfg(not(feature = "no_index"))] if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Array(value, _, _) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v), + Union::Array(value, _, _) => unsafe_cast_box::<_, T>(value).map(|v| *v), _ => None, }; } @@ -1430,7 +1414,7 @@ impl Dynamic { #[cfg(not(feature = "no_index"))] if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Blob(value, _, _) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v), + Union::Blob(value, _, _) => unsafe_cast_box::<_, T>(value).map(|v| *v), _ => None, }; } @@ -1438,14 +1422,14 @@ impl Dynamic { #[cfg(not(feature = "no_object"))] if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Map(value, _, _) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v), + Union::Map(value, _, _) => unsafe_cast_box::<_, T>(value).map(|v| *v), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::FnPtr(value, _, _) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v), + Union::FnPtr(value, _, _) => unsafe_cast_box::<_, T>(value).map(|v| *v), _ => None, }; } @@ -1453,20 +1437,20 @@ impl Dynamic { #[cfg(not(feature = "no_std"))] if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::TimeStamp(value, _, _) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v), + Union::TimeStamp(value, _, _) => unsafe_cast_box::<_, T>(value).map(|v| *v), _ => None, }; } if TypeId::of::() == TypeId::of::<()>() { return match self.0 { - Union::Unit(value, _, _) => unsafe_try_cast(value).ok(), + Union::Unit(value, _, _) => unsafe_try_cast(value), _ => None, }; } match self.0 { - Union::Variant(value, _, _) => (*value).as_box_any().downcast().map(|x| *x).ok(), + Union::Variant(value, _, _) => (*value).as_box_any().downcast().ok().map(|x| *x), #[cfg(not(feature = "no_closure"))] Union::Shared(_, _, _) => unreachable!("Union::Shared case should be already handled"), _ => None, diff --git a/src/unsafe.rs b/src/unsafe.rs index 3ce5b4c9..e7c81cbe 100644 --- a/src/unsafe.rs +++ b/src/unsafe.rs @@ -8,35 +8,48 @@ use std::{ }; /// Cast a type into another type. -#[inline] -pub fn unsafe_try_cast(a: A) -> Result { +/// +/// # Undefined Behavior +/// +/// It is UB if the types are not compatible. +#[inline(always)] +#[must_use] +pub fn unsafe_cast(a: A) -> B { + unsafe { + let ret: B = ptr::read(&a as *const _ as *const B); + // We explicitly forget the value immediately after moving out, + // removing any chance of a destructor running or value otherwise + // being used again. + mem::forget(a); + ret + } +} + +/// Cast a type into another type. +#[inline(always)] +#[must_use] +pub fn unsafe_try_cast(a: A) -> Option { if TypeId::of::() == a.type_id() { - // SAFETY: Just checked we have the right type. We explicitly forget the - // value immediately after moving out, removing any chance of a destructor - // running or value otherwise being used again. - unsafe { - let ret: B = ptr::read(&a as *const _ as *const B); - mem::forget(a); - Ok(ret) - } + // SAFETY: Just checked we have the right type. + Some(unsafe_cast(a)) } else { - Err(a) + None } } /// Cast a Boxed type into another type. -#[inline] -pub fn unsafe_cast_box(item: Box) -> Result, Box> { +#[inline(always)] +#[must_use] +pub fn unsafe_cast_box(item: Box) -> Option> { // Only allow casting to the exact same type if TypeId::of::() == TypeId::of::() { // SAFETY: just checked whether we are pointing to the correct type unsafe { let raw: *mut dyn Any = Box::into_raw(item as Box); - Ok(Box::from_raw(raw as *mut T)) + Some(Box::from_raw(raw as *mut T)) } } else { - // Return the consumed item for chaining. - Err(item) + None } }