From: Chris Morgan Date: Fri, 7 Nov 2014 23:24:37 +0000 (+1100) Subject: Rust update. X-Git-Tag: 0.9.1~2 X-Git-Url: https://git.chrismorgan.info/anymap/commitdiff_plain/c29e78c5634f9e6741287e9cfb281a73d4eddcc6 Rust update. This includes following the standard new semantics for `insert` and `remove`, where they return any value that was previously present, and renaming `find` and `find_mut` to `get` and `get_mut`. For the moment, I’ve even provided a deprecation path! Will wonders ever cease? --- diff --git a/src/lib.rs b/src/lib.rs index 152a397..80e5104 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,7 +11,7 @@ extern crate test; use std::any::Any; -use std::intrinsics::TypeId; +use std::intrinsics::{forget, TypeId}; use std::collections::HashMap; use std::hash::{Hash, Hasher, Writer}; use std::mem::{transmute, transmute_copy}; @@ -50,12 +50,12 @@ impl Hasher for TypeIdHasher { 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; + unsafe fn downcast_ref_unchecked(self) -> &'a T; } impl<'a> UncheckedAnyRefExt<'a> for &'a Any + 'a { #[inline] - unsafe fn as_ref_unchecked(self) -> &'a T { + unsafe fn downcast_ref_unchecked(self) -> &'a T { // Get the raw representation of the trait object let to: TraitObject = transmute_copy(&self); @@ -68,12 +68,12 @@ impl<'a> UncheckedAnyRefExt<'a> for &'a Any + 'a { 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; + unsafe fn downcast_mut_unchecked(self) -> &'a mut T; } impl<'a> UncheckedAnyMutRefExt<'a> for &'a mut Any + 'a { #[inline] - unsafe fn as_mut_unchecked(self) -> &'a mut T { + unsafe fn downcast_mut_unchecked(self) -> &'a mut T { // Get the raw representation of the trait object let to: TraitObject = transmute_copy(&self); @@ -82,28 +82,49 @@ impl<'a> UncheckedAnyMutRefExt<'a> for &'a mut Any + 'a { } } +/// An extension of `BoxAny` allowing unchecked downcasting of trait objects to `Box`. +trait UncheckedBoxAny { + /// Returns 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 downcast_unchecked(self) -> Box; +} + +impl UncheckedBoxAny for Box { + #[inline] + unsafe fn downcast_unchecked(self) -> Box { + // Get the raw representation of the trait object + let to: TraitObject = *transmute::<&Box, &TraitObject>(&self); + + // Prevent destructor on self being run + forget(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. /// /// ```rust /// # use anymap::AnyMap; /// let mut data = AnyMap::new(); -/// assert_eq!(data.find(), None::<&int>); +/// assert_eq!(data.get(), None::<&int>); /// data.insert(42i); -/// assert_eq!(data.find(), Some(&42i)); +/// assert_eq!(data.get(), Some(&42i)); /// data.remove::(); -/// assert_eq!(data.find::(), None); +/// assert_eq!(data.get::(), None); /// /// #[deriving(PartialEq, Show)] /// struct Foo { /// str: String, /// } /// -/// assert_eq!(data.find::(), None); +/// assert_eq!(data.get::(), None); /// data.insert(Foo { str: "foo".to_string() }); -/// assert_eq!(data.find(), Some(&Foo { str: "foo".to_string() })); -/// data.find_mut::().map(|foo| foo.str.push('t')); -/// assert_eq!(data.find::().unwrap().str.as_slice(), "foot"); +/// assert_eq!(data.get(), Some(&Foo { str: "foo".to_string() })); +/// data.get_mut::().map(|foo| foo.str.push('t')); +/// assert_eq!(data.get::().unwrap().str.as_slice(), "foot"); /// ``` /// /// Values containing non-static references are not permitted. @@ -121,25 +142,41 @@ impl AnyMap { } impl AnyMap { - /// Retrieve the value stored in the map for the type `T`, if it exists. + /// Deprecated: Renamed to `get`. + #[deprecated = "Renamed to `get`"] pub fn find(&self) -> Option<&T> { - self.data.find(&TypeId::of::()).map(|any| unsafe { any.as_ref_unchecked::() }) + self.get::() } - /// Retrieve a mutable reference to the value stored in the map for the type `T`, if it exists. + /// Deprecated: Renamed to `get_mut`. + #[deprecated = "Renamed to `get_mut`"] pub fn find_mut(&mut self) -> Option<&mut T> { - self.data.find_mut(&TypeId::of::()).map(|any| unsafe { any.as_mut_unchecked::() }) + self.get_mut::() + } + + /// Retrieve the value stored in the map for the type `T`, if it exists. + pub fn get(&self) -> Option<&T> { + self.data.get(&TypeId::of::()) + .map(|any| unsafe { any.downcast_ref_unchecked::() }) + } + + /// Retrieve a mutable reference to the value stored in the map for the type `T`, if it exists. + pub fn get_mut(&mut self) -> Option<&mut T> { + self.data.get_mut(&TypeId::of::()) + .map(|any| unsafe { any.downcast_mut_unchecked::() }) } /// Set the value contained in the map for the type `T`. - /// This will override any previous value stored. - pub fn insert(&mut self, value: T) { - self.data.insert(TypeId::of::(), box value as Box); + /// If there is a previous value stored, it will be returned. + pub fn insert(&mut self, value: T) -> Option { + self.data.insert(TypeId::of::(), box value as Box) + .map(|any| *unsafe { any.downcast_unchecked::() }) } - /// Remove the value for the type `T` if it existed. - pub fn remove(&mut self) { - self.data.remove(&TypeId::of::()); + /// Remove and return the value for the type `T` if it existed. + pub fn remove(&mut self) -> Option { + self.data.remove(&TypeId::of::()) + .map(|any| *unsafe { any.downcast_unchecked::() }) } /// Does a value of type `T` exist? @@ -168,29 +205,29 @@ fn bench_insertion(b: &mut ::test::Bencher) { b.iter(|| { let mut data = AnyMap::new(); for _ in range(0u, 100) { - data.insert(42i); + let _ = data.insert(42i); } }) } #[bench] -fn bench_find_missing(b: &mut ::test::Bencher) { +fn bench_get_missing(b: &mut ::test::Bencher) { b.iter(|| { let data = AnyMap::new(); for _ in range(0u, 100) { - assert_eq!(data.find(), None::<&int>); + assert_eq!(data.get(), None::<&int>); } }) } #[bench] -fn bench_find_present(b: &mut ::test::Bencher) { +fn bench_get_present(b: &mut ::test::Bencher) { b.iter(|| { let mut data = AnyMap::new(); - data.insert(42i); + let _ = data.insert(42i); // These inner loops are a feeble attempt to drown the other factors. for _ in range(0u, 100) { - assert_eq!(data.find(), Some(&42i)); + assert_eq!(data.get(), Some(&42i)); } }) }