Skip to content

Commit

Permalink
A AnyMap that satisfies Clone.
Browse files Browse the repository at this point in the history
  • Loading branch information
chris-morgan committed Dec 17, 2014
1 parent 83434cc commit 96436bf
Showing 1 changed file with 52 additions and 11 deletions.
63 changes: 52 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
#[cfg(test)]
extern crate test;

use std::any::Any;
//use std::any::Any;
pub use with_clone::Any;
use std::intrinsics::{forget, TypeId};
use std::collections::HashMap;
use std::collections::hash_map;
Expand All @@ -18,8 +19,10 @@ use std::raw::TraitObject;

pub use Entry::{Vacant, Occupied};

#[deriving(Clone)]
struct TypeIdHasher;

#[deriving(Clone)]
struct TypeIdState {
value: u64,
}
Expand Down Expand Up @@ -104,6 +107,32 @@ impl UncheckedBoxAny for Box<Any + 'static> {
}
}

mod with_clone {
#[doc(hidden)]
pub trait CloneToAny {
/// Clone `self` into a new `Box<Any>` object.
fn clone_to_any(&self) -> Box<Any>;
}

impl<T: 'static + Clone> CloneToAny for T {
fn clone_to_any(&self) -> Box<Any> {
box self.clone()
}
}

#[doc(hidden)]
/// Pretty much just `std::any::Any + Clone`.
pub trait Any: ::std::any::Any + CloneToAny { }

impl<T: 'static + Clone> Any for T { }

impl Clone for Box<Any> {
fn clone(&self) -> Box<Any> {
(**self).clone_to_any()
}
}
}

/// A map containing zero or one values for any given type and allowing convenient,
/// type-safe access to those values.
///
Expand All @@ -116,7 +145,7 @@ impl UncheckedBoxAny for Box<Any + 'static> {
/// data.remove::<int>();
/// assert_eq!(data.get::<int>(), None);
///
/// #[deriving(PartialEq, Show)]
/// #[deriving(Clone, PartialEq, Show)]
/// struct Foo {
/// str: String,
/// }
Expand All @@ -129,6 +158,7 @@ impl UncheckedBoxAny for Box<Any + 'static> {
/// ```
///
/// Values containing non-static references are not permitted.
#[deriving(Clone)]
pub struct AnyMap {
data: HashMap<TypeId, Box<Any + 'static>, TypeIdHasher>,
}
Expand Down Expand Up @@ -227,7 +257,7 @@ pub enum Entry<'a, V: 'a> {
Vacant(VacantEntry<'a, V>),
}

impl<'a, V: 'static> OccupiedEntry<'a, V> {
impl<'a, V: 'static + Clone> OccupiedEntry<'a, V> {
/// Gets a reference to the value in the entry
pub fn get(&self) -> &V {
unsafe { self.entry.get().downcast_ref_unchecked() }
Expand Down Expand Up @@ -255,7 +285,7 @@ impl<'a, V: 'static> OccupiedEntry<'a, V> {
}
}

impl<'a, V: 'static> VacantEntry<'a, V> {
impl<'a, V: 'static + Clone> VacantEntry<'a, V> {
/// Sets the value of the entry with the VacantEntry's key,
/// and returns a mutable reference to it
pub fn set(self, value: V) -> &'a mut V {
Expand Down Expand Up @@ -297,13 +327,13 @@ fn bench_get_present(b: &mut ::test::Bencher) {

#[test]
fn test_entry() {
#[deriving(Show, PartialEq)] struct A(int);
#[deriving(Show, PartialEq)] struct B(int);
#[deriving(Show, PartialEq)] struct C(int);
#[deriving(Show, PartialEq)] struct D(int);
#[deriving(Show, PartialEq)] struct E(int);
#[deriving(Show, PartialEq)] struct F(int);
#[deriving(Show, PartialEq)] struct J(int);
#[deriving(Show, PartialEq, Clone)] struct A(int);
#[deriving(Show, PartialEq, Clone)] struct B(int);
#[deriving(Show, PartialEq, Clone)] struct C(int);
#[deriving(Show, PartialEq, Clone)] struct D(int);
#[deriving(Show, PartialEq, Clone)] struct E(int);
#[deriving(Show, PartialEq, Clone)] struct F(int);
#[deriving(Show, PartialEq, Clone)] struct J(int);

let mut map: AnyMap = AnyMap::new();
assert_eq!(map.insert(A(10)), None);
Expand Down Expand Up @@ -358,4 +388,15 @@ fn test_entry() {
}
assert_eq!(map.get::<J>().unwrap(), &J(1000));
assert_eq!(map.len(), 6);

// Cloning works as intended
let map2 = map.clone();
assert_eq!(map2.len(), 6)
assert_eq!(map2.get::<A>(), Some(&A(100)));
assert_eq!(map2.get::<B>(), Some(&B(200)));
assert_eq!(map2.get::<C>(), None);
assert_eq!(map2.get::<D>(), Some(&D(40)));
assert_eq!(map2.get::<E>(), Some(&E(50)));
assert_eq!(map2.get::<F>(), Some(&F(60)));
assert_eq!(map2.get::<J>(), Some(&J(1000)));
}

0 comments on commit 96436bf

Please sign in to comment.