typemap-0.3.3/.gitignore000064400007650000024000000002071242166075000134040ustar0000000000000000.DS_Store *~ *# *.o *.so *.swp *.dylib *.dSYM *.dll *.rlib *.dummy *.exe *-test /doc/ /target/ /examples/* !/examples/*.rs Cargo.lock typemap-0.3.3/.travis.yml000064400007650000024000000001021252332561200135150ustar0000000000000000language: rust sudo: false script: - cargo build - cargo test typemap-0.3.3/Cargo.toml000064400007650000024000000013571253666656000133670ustar0000000000000000# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] name = "typemap" version = "0.3.3" authors = ["Jonathan Reem "] description = "A typesafe store for many value types." readme = "README.md" license = "MIT" repository = "https://github.com/reem/rust-typemap" [dependencies.unsafe-any] version = "*" typemap-0.3.3/Cargo.toml.orig000064400007650000024000000004011253666656000143130ustar0000000000000000[package] name = "typemap" version = "0.3.3" authors = ["Jonathan Reem "] license = "MIT" description = "A typesafe store for many value types." repository = "https://github.com/reem/rust-typemap" [dependencies] unsafe-any = "*" typemap-0.3.3/README.md000064400007650000024000000013601245424436700127040ustar0000000000000000# `TypeMap` > A typesafe store keyed by types and containing different types of values. It provides functionality similar to AnyMap, but is more flexible because it allows for key-value pairs, rather than enforcing that keys and values are the same type. Key-value associations are defined through the `Key` trait, which uses an associated type parameter and trait coherence rules to enforce the invariants of `TypeMap`. ## Example ```rust #[deriving(Show, PartialEq)] struct KeyType; #[deriving(Show, PartialEq)] struct Value(i32); impl Key for KeyType { type Value = Value; } #[test] fn test_pairing() { let mut map = TypeMap::new(); map.insert::(Value(12)); assert_eq!(*map.find::().unwrap(), Value(12); } ``` typemap-0.3.3/src/internals.rs000064400007650000024000000103531253666600100145550ustar0000000000000000use uany::{UnsafeAny, UnsafeAnyExt}; use std::any::Any; use std::fmt::Debug; /// A marker trait meant for use as the `A` parameter in `TypeMap`. /// /// This can be used to construct `TypeMap`s containing only types which /// implement `Debug` like so: `TypeMap::::custom()`, which produces /// a `TypeMap`. Combine `DebugAny` with `Send` or `Sync` to add /// additional bounds. /// /// There is also an exported alias for this type of `TypeMap`, `DebugMap`. pub trait DebugAny: Any + Debug { } impl DebugAny for T { } unsafe impl UnsafeAnyExt for DebugAny {} unsafe impl UnsafeAnyExt for DebugAny + Send {} unsafe impl UnsafeAnyExt for DebugAny + Sync {} unsafe impl UnsafeAnyExt for DebugAny + Send + Sync {} /// A marker trait meant for use as the `A` parameter in `TypeMap`. /// /// This can be used to construct `TypeMap`s containing only types which /// implement `Clone` like so: `TypeMap::::custom()`, which produces /// a `TypeMap`. Combine `CloneAny` with `Send` or `Sync` to add /// additional bounds. /// /// There is also an exported alias for this type of `TypeMap`, `CloneAny`. pub trait CloneAny: Any { #[doc(hidden)] fn clone_any(&self) -> Box; #[doc(hidden)] fn clone_any_send(&self) -> Box where Self: Send; #[doc(hidden)] fn clone_any_sync(&self) -> Box where Self: Sync; #[doc(hidden)] fn clone_any_send_sync(&self) -> Box where Self: Send + Sync; } impl CloneAny for T { fn clone_any(&self) -> Box { Box::new(self.clone()) } fn clone_any_send(&self) -> Box where Self: Send { Box::new(self.clone()) } fn clone_any_sync(&self) -> Box where Self: Sync { Box::new(self.clone()) } fn clone_any_send_sync(&self) -> Box where Self: Send + Sync { Box::new(self.clone()) } } impl Clone for Box { fn clone(&self) -> Box { (**self).clone_any() } } impl Clone for Box { fn clone(&self) -> Box { (**self).clone_any_send() } } impl Clone for Box { fn clone(&self) -> Box { (**self).clone_any_sync() } } impl Clone for Box { fn clone(&self) -> Box { (**self).clone_any_send_sync() } } unsafe impl UnsafeAnyExt for CloneAny {} unsafe impl UnsafeAnyExt for CloneAny + Send {} unsafe impl UnsafeAnyExt for CloneAny + Sync {} unsafe impl UnsafeAnyExt for CloneAny + Send + Sync {} #[doc(hidden)] // Not actually exported pub unsafe trait Implements { fn into_object(self) -> Box; } unsafe impl Implements for T { fn into_object(self) -> Box { Box::new(self) } } unsafe impl Implements<(UnsafeAny + Send)> for T { fn into_object(self) -> Box { Box::new(self) } } unsafe impl Implements<(UnsafeAny + Sync)> for T { fn into_object(self) -> Box { Box::new(self) } } unsafe impl Implements<(UnsafeAny + Send + Sync)> for T { fn into_object(self) -> Box { Box::new(self) } } unsafe impl Implements for T { fn into_object(self) -> Box { Box::new(self) } } unsafe impl Implements<(CloneAny + Send)> for T { fn into_object(self) -> Box { Box::new(self) } } unsafe impl Implements<(CloneAny + Send + Sync)> for T { fn into_object(self) -> Box { Box::new(self) } } unsafe impl Implements for T { fn into_object(self) -> Box { Box::new(self) } } unsafe impl Implements for T { fn into_object(self) -> Box { Box::new(self) } } unsafe impl Implements for T { fn into_object(self) -> Box { Box::new(self) } } unsafe impl Implements for T { fn into_object(self) -> Box { Box::new(self) } } typemap-0.3.3/src/lib.rs000064400007650000024000000260101253666614000133250ustar0000000000000000#![deny(missing_docs, warnings)] //! A type-based key value store where one value type is allowed for each key. extern crate unsafe_any as uany; use uany::{UnsafeAny, UnsafeAnyExt}; use std::any::{Any, TypeId}; use std::collections::{hash_map, HashMap}; use std::marker::PhantomData; use Entry::{Occupied, Vacant}; pub use internals::{CloneAny, DebugAny}; use internals::Implements; /// A map keyed by types. /// /// Can contain one value of any type for each key type, as defined /// by the Assoc trait. /// /// You usually do not need to worry about the A type parameter, but it /// can be used to add bounds to the possible value types that can /// be stored in this map. Usually, you are looking for `ShareMap`, which /// is `Send + Sync`. #[derive(Default, Debug)] pub struct TypeMap where A: UnsafeAnyExt { data: HashMap> } impl Clone for TypeMap where A: UnsafeAnyExt, Box: Clone { // We are a bit cleverer than derive. fn clone(&self) -> TypeMap { TypeMap { data: self.data.clone() } } } /// A version of `TypeMap` containing only `Send` types. pub type SendMap = TypeMap; /// A version of `TypeMap` containing only `Sync` types. pub type SyncMap = TypeMap; /// A version of `TypeMap` containing only `Send + Sync` types. pub type ShareMap = TypeMap; /// A version of `TypeMap` containing only `Clone` types. pub type CloneMap = TypeMap; /// A version of `TypeMap` containing only `Clone + Send + Sync` types. pub type ShareCloneMap = TypeMap; /// A version of `TypeMap` containing only `Debug` types. pub type DebugMap = TypeMap; /// A version of `TypeMap` containing only `Debug + Send + Sync` types. pub type ShareDebugMap = TypeMap; // Assert some properties on SyncMap, SendMap and ShareMap. fn _assert_types() { use std::fmt::Debug; fn _assert_send() { } fn _assert_sync() { } fn _assert_clone() { } fn _assert_debug() { } _assert_send::(); _assert_sync::(); _assert_send::(); _assert_sync::(); _assert_clone::(); _assert_debug::(); } /// This trait defines the relationship between keys and values in a TypeMap. /// /// It is implemented for Keys, with a phantom associated type for the values. pub trait Key: Any { /// The value type associated with this key type. type Value: Any; } impl TypeMap { /// Create a new, empty TypeMap. pub fn new() -> TypeMap { TypeMap::custom() } } impl TypeMap { /// Create a new, empty TypeMap. /// /// Can be used with any `A` parameter; `new` is specialized to get around /// the required type annotations when using this function. pub fn custom() -> TypeMap { TypeMap { data: HashMap::new() } } /// Insert a value into the map with a specified key type. pub fn insert(&mut self, val: K::Value) -> Option where K::Value: Any + Implements { self.data.insert(TypeId::of::(), val.into_object()).map(|v| unsafe { *v.downcast_unchecked::() }) } /// Find a value in the map and get a reference to it. pub fn get(&self) -> Option<&K::Value> where K::Value: Any + Implements { self.data.get(&TypeId::of::()).map(|v| unsafe { v.downcast_ref_unchecked::() }) } /// Find a value in the map and get a mutable reference to it. pub fn get_mut(&mut self) -> Option<&mut K::Value> where K::Value: Any + Implements { self.data.get_mut(&TypeId::of::()).map(|v| unsafe { v.downcast_mut_unchecked::() }) } /// Check if a key has an associated value stored in the map. pub fn contains(&self) -> bool { self.data.contains_key(&TypeId::of::()) } /// Remove a value from the map. /// /// Returns `true` if a value was removed. pub fn remove(&mut self) -> Option where K::Value: Any + Implements { self.data.remove(&TypeId::of::()).map(|v| unsafe { *v.downcast_unchecked::() }) } /// Get the given key's corresponding entry in the map for in-place manipulation. pub fn entry<'a, K: Key>(&'a mut self) -> Entry<'a, K, A> where K::Value: Any + Implements { match self.data.entry(TypeId::of::()) { hash_map::Entry::Occupied(e) => Occupied(OccupiedEntry { data: e, _marker: PhantomData }), hash_map::Entry::Vacant(e) => Vacant(VacantEntry { data: e, _marker: PhantomData }) } } /// Read the underlying HashMap pub unsafe fn data(&self) -> &HashMap> { &self.data } /// Get a mutable reference to the underlying HashMap pub unsafe fn data_mut(&mut self) -> &mut HashMap> { &mut self.data } /// Get the number of values stored in the map. pub fn len(&self) -> usize { self.data.len() } /// Return true if the map contains no values. pub fn is_empty(&self) -> bool { self.data.is_empty() } /// Remove all entries from the map. pub fn clear(&mut self) { self.data.clear() } } /// A view onto an entry in a TypeMap. pub enum Entry<'a, K, A: ?Sized + UnsafeAnyExt + 'a = UnsafeAny> { /// A view onto an occupied entry in a TypeMap. Occupied(OccupiedEntry<'a, K, A>), /// A view onto an unoccupied entry in a TypeMap. Vacant(VacantEntry<'a, K, A>) } impl<'a, K: Key, A: ?Sized + UnsafeAnyExt + 'a = UnsafeAny> Entry<'a, K, A> { /// Ensures a value is in the entry by inserting the default if empty, and returns /// a mutable reference to the value in the entry. pub fn or_insert(self, default: K::Value) -> &'a mut K::Value where K::Value: Any + Implements { match self { Entry::Occupied(inner) => inner.into_mut(), Entry::Vacant(inner) => inner.insert(default), } } /// Ensures a value is in the entry by inserting the result of the default function if empty, /// and returns a mutable reference to the value in the entry. pub fn or_insert_with K::Value>(self, default: F) -> &'a mut K::Value where K::Value: Any + Implements { match self { Entry::Occupied(inner) => inner.into_mut(), Entry::Vacant(inner) => inner.insert(default()), } } } /// A view onto an occupied entry in a TypeMap. pub struct OccupiedEntry<'a, K, A: ?Sized + UnsafeAnyExt + 'a = UnsafeAny> { data: hash_map::OccupiedEntry<'a, TypeId, Box>, _marker: PhantomData } /// A view onto an unoccupied entry in a TypeMap. pub struct VacantEntry<'a, K, A: ?Sized + UnsafeAnyExt + 'a = UnsafeAny> { data: hash_map::VacantEntry<'a, TypeId, Box>, _marker: PhantomData } impl<'a, K: Key, A: UnsafeAnyExt + ?Sized> OccupiedEntry<'a, K, A> { /// Get a reference to the entry's value. pub fn get(&self) -> &K::Value where K::Value: Any + Implements { unsafe { self.data.get().downcast_ref_unchecked() } } /// Get a mutable reference to the entry's value. pub fn get_mut(&mut self) -> &mut K::Value where K::Value: Any + Implements { unsafe { self.data.get_mut().downcast_mut_unchecked() } } /// Transform the entry into a mutable reference with the same lifetime as the map. pub fn into_mut(self) -> &'a mut K::Value where K::Value: Any + Implements { unsafe { self.data.into_mut().downcast_mut_unchecked() } } /// Set the entry's value and return the previous value. pub fn insert(&mut self, value: K::Value) -> K::Value where K::Value: Any + Implements { unsafe { *self.data.insert(value.into_object()).downcast_unchecked() } } /// Move the entry's value out of the map, consuming the entry. pub fn remove(self) -> K::Value where K::Value: Any + Implements { unsafe { *self.data.remove().downcast_unchecked() } } } impl<'a, K: Key, A: ?Sized + UnsafeAnyExt> VacantEntry<'a, K, A> { /// Set the entry's value and return a mutable reference to it. pub fn insert(self, value: K::Value) -> &'a mut K::Value where K::Value: Any + Implements { unsafe { self.data.insert(value.into_object()).downcast_mut_unchecked() } } } mod internals; #[cfg(test)] mod test { use super::{TypeMap, CloneMap, DebugMap, SendMap, Key}; use super::Entry::{Occupied, Vacant}; #[derive(Debug, PartialEq)] struct KeyType; #[derive(Clone, Debug, PartialEq)] struct Value(u8); impl Key for KeyType { type Value = Value; } #[test] fn test_pairing() { let mut map = TypeMap::new(); map.insert::(Value(100)); assert_eq!(*map.get::().unwrap(), Value(100)); assert!(map.contains::()); } #[test] fn test_remove() { let mut map = TypeMap::new(); map.insert::(Value(10)); assert!(map.contains::()); map.remove::(); assert!(!map.contains::()); } #[test] fn test_entry() { let mut map = TypeMap::new(); map.insert::(Value(20)); match map.entry::() { Occupied(e) => { assert_eq!(e.get(), &Value(20)); assert_eq!(e.remove(), Value(20)); }, _ => panic!("Unable to locate inserted item.") } assert!(!map.contains::()); match map.entry::() { Vacant(e) => { e.insert(Value(2)); }, _ => panic!("Found non-existant entry.") } assert!(map.contains::()); } #[test] fn test_entry_or_insert() { let mut map = TypeMap::new(); map.entry::().or_insert(Value(20)).0 += 1; assert_eq!(map.get::().unwrap(), &Value(21)); // on existing value map.entry::().or_insert(Value(100)).0 += 1; assert_eq!(map.get::().unwrap(), &Value(22)); } #[test] fn test_custom_bounds() { let mut map: SendMap = TypeMap::custom(); map.insert::(Value(10)); assert!(map.contains::()); map.remove::(); assert!(!map.contains::()); } #[test] fn test_clonemap() { let mut map: CloneMap = TypeMap::custom(); map.insert::(Value(10)); assert!(map.contains::()); let cloned = map.clone(); assert_eq!(map.get::(), cloned.get::()); } #[test] fn test_debugmap() { let mut map: DebugMap = TypeMap::custom(); map.insert::(Value(10)); assert!(map.contains::()); } }