From: Chris Morgan Date: Thu, 12 Jun 2014 12:59:03 +0000 (+1000) Subject: Skip type checking in from-Any casting. X-Git-Tag: 0.9.1~24 X-Git-Url: https://git.chrismorgan.info/anymap/commitdiff_plain/8c1b4578cc1e307a7e7fff6152fc904c4e8d4371 Skip type checking in from-Any casting. We know the type with certainty already. This should make a microscopic improvement in perf. --- diff --git a/src/lib.rs b/src/lib.rs index 2d03c56..8340ae2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,10 +11,12 @@ #[cfg(test)] extern crate test; -use std::any::{Any, AnyRefExt, AnyMutRefExt}; +use std::any::Any; use std::intrinsics::TypeId; use std::collections::HashMap; use std::hash::{Hash, Hasher, Writer}; +use std::mem::{transmute, transmute_copy}; +use std::raw::TraitObject; struct TypeIdHasher; @@ -29,7 +31,7 @@ impl Writer for TypeIdState { debug_assert!(bytes.len() == 8); unsafe { std::ptr::copy_nonoverlapping_memory(&mut self.value, - std::mem::transmute(&bytes[0]), + transmute(&bytes[0]), 1) } } @@ -45,6 +47,42 @@ impl Hasher for TypeIdHasher { } } +/// An extension of `AnyRefExt` allowing unchecked downcasting of trait objects to `&T`. +trait UncheckedAnyRefExt<'a> { + /// Returns a reference to the boxed value, assuming that it is of type `T`. This should only be + /// called if you are ABSOLUTELY CERTAIN of `T` as you will get really wacky output if it’s not. + unsafe fn as_ref_unchecked(self) -> &'a T; +} + +impl<'a> UncheckedAnyRefExt<'a> for &'a Any { + #[inline] + unsafe fn as_ref_unchecked(self) -> &'a T { + // Get the raw representation of the trait object + let to: TraitObject = transmute_copy(&self); + + // Extract the data pointer + transmute(to.data) + } +} + +/// An extension of `AnyMutRefExt` allowing unchecked downcasting of trait objects to `&mut T`. +trait UncheckedAnyMutRefExt<'a> { + /// Returns a reference to the boxed value, assuming that it is of type `T`. This should only be + /// called if you are ABSOLUTELY CERTAIN of `T` as you will get really wacky output if it’s not. + unsafe fn as_mut_unchecked(self) -> &'a mut T; +} + +impl<'a> UncheckedAnyMutRefExt<'a> for &'a mut Any { + #[inline] + unsafe fn as_mut_unchecked(self) -> &'a mut T { + // Get the raw representation of the trait object + let to: TraitObject = transmute_copy(&self); + + // Extract the data pointer + transmute(to.data) + } +} + /// A map containing zero or one values for any given type and allowing convenient, /// type-safe access to those values. /// @@ -86,12 +124,12 @@ impl AnyMap { impl AnyMap { /// Retrieve the value stored in the map for the type `T`, if it exists. pub fn find<'a, T: 'static>(&'a self) -> Option<&'a T> { - self.data.find(&TypeId::of::()).and_then(|any| any.as_ref::()) + self.data.find(&TypeId::of::()).map(|any| unsafe { any.as_ref_unchecked::() }) } /// Retrieve a mutable reference to the value stored in the map for the type `T`, if it exists. pub fn find_mut<'a, T: 'static>(&'a mut self) -> Option<&'a mut T> { - self.data.find_mut(&TypeId::of::()).and_then(|any| any.as_mut::()) + self.data.find_mut(&TypeId::of::()).map(|any| unsafe { any.as_mut_unchecked::() }) } /// Set the value contained in the map for the type `T`.