#![deny(missing_docs)]
extern crate unsafe_any_ors as uany;
use std::any::{Any, TypeId};
use std::collections::{hash_map, HashMap};
use std::marker::PhantomData;
use uany::{UnsafeAny, UnsafeAnyExt};
use Entry::{Occupied, Vacant};
use internals::Implements;
pub use internals::{CloneAny, DebugAny};
#[derive(Default, Debug)]
pub struct TypeMap<A: ?Sized = dyn UnsafeAny>
where
A: UnsafeAnyExt,
{
data: HashMap<TypeId, Box<A>>,
}
impl<A: ?Sized> Clone for TypeMap<A>
where
A: UnsafeAnyExt,
Box<A>: Clone,
{
fn clone(&self) -> TypeMap<A> {
TypeMap {
data: self.data.clone(),
}
}
}
pub type SendMap = TypeMap<dyn UnsafeAny + Send>;
pub type SyncMap = TypeMap<dyn UnsafeAny + Sync>;
pub type ShareMap = TypeMap<dyn UnsafeAny + Send + Sync>;
pub type CloneMap = TypeMap<dyn CloneAny>;
pub type ShareCloneMap = TypeMap<dyn CloneAny + Send + Sync>;
pub type DebugMap = TypeMap<dyn DebugAny>;
pub type ShareDebugMap = TypeMap<dyn DebugAny + Send + Sync>;
fn _assert_types() {
use std::fmt::Debug;
fn _assert_send<T: Send>() {}
fn _assert_sync<T: Sync>() {}
fn _assert_clone<T: Clone>() {}
fn _assert_debug<T: Debug>() {}
_assert_send::<SendMap>();
_assert_sync::<SyncMap>();
_assert_send::<ShareMap>();
_assert_sync::<ShareMap>();
_assert_clone::<CloneMap>();
_assert_debug::<DebugMap>();
}
pub trait Key: Any {
type Value: Any;
}
impl TypeMap {
pub fn new() -> TypeMap {
TypeMap::custom()
}
}
impl<A: UnsafeAnyExt + ?Sized> TypeMap<A> {
pub fn custom() -> TypeMap<A> {
TypeMap {
data: HashMap::new(),
}
}
pub fn insert<K: Key>(&mut self, val: K::Value) -> Option<K::Value>
where
K::Value: Any + Implements<A>,
{
self.data
.insert(TypeId::of::<K>(), val.into_object())
.map(|v| unsafe { *v.downcast_unchecked::<K::Value>() })
}
pub fn get<K: Key>(&self) -> Option<&K::Value>
where
K::Value: Any + Implements<A>,
{
self.data
.get(&TypeId::of::<K>())
.map(|v| unsafe { v.downcast_ref_unchecked::<K::Value>() })
}
pub fn get_mut<K: Key>(&mut self) -> Option<&mut K::Value>
where
K::Value: Any + Implements<A>,
{
self.data
.get_mut(&TypeId::of::<K>())
.map(|v| unsafe { v.downcast_mut_unchecked::<K::Value>() })
}
pub fn contains<K: Key>(&self) -> bool {
self.data.contains_key(&TypeId::of::<K>())
}
pub fn remove<K: Key>(&mut self) -> Option<K::Value>
where
K::Value: Any + Implements<A>,
{
self.data
.remove(&TypeId::of::<K>())
.map(|v| unsafe { *v.downcast_unchecked::<K::Value>() })
}
pub fn entry<K: Key>(&mut self) -> Entry<K, A>
where
K::Value: Any + Implements<A>,
{
match self.data.entry(TypeId::of::<K>()) {
hash_map::Entry::Occupied(e) => Occupied(OccupiedEntry {
data: e,
_marker: PhantomData,
}),
hash_map::Entry::Vacant(e) => Vacant(VacantEntry {
data: e,
_marker: PhantomData,
}),
}
}
pub unsafe fn data(&self) -> &HashMap<TypeId, Box<A>> {
&self.data
}
pub unsafe fn data_mut(&mut self) -> &mut HashMap<TypeId, Box<A>> {
&mut self.data
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn clear(&mut self) {
self.data.clear()
}
}
pub enum Entry<'a, K, A: ?Sized + UnsafeAnyExt + 'a = dyn UnsafeAny> {
Occupied(OccupiedEntry<'a, K, A>),
Vacant(VacantEntry<'a, K, A>),
}
impl<'a, K: Key, A: ?Sized + UnsafeAnyExt + 'a> Entry<'a, K, A> {
pub fn or_insert(self, default: K::Value) -> &'a mut K::Value
where
K::Value: Any + Implements<A>,
{
match self {
Entry::Occupied(inner) => inner.into_mut(),
Entry::Vacant(inner) => inner.insert(default),
}
}
pub fn or_insert_with<F: FnOnce() -> K::Value>(self, default: F) -> &'a mut K::Value
where
K::Value: Any + Implements<A>,
{
match self {
Entry::Occupied(inner) => inner.into_mut(),
Entry::Vacant(inner) => inner.insert(default()),
}
}
}
pub struct OccupiedEntry<'a, K, A: ?Sized + UnsafeAnyExt + 'a = dyn UnsafeAny> {
data: hash_map::OccupiedEntry<'a, TypeId, Box<A>>,
_marker: PhantomData<K>,
}
pub struct VacantEntry<'a, K, A: ?Sized + UnsafeAnyExt + 'a = dyn UnsafeAny> {
data: hash_map::VacantEntry<'a, TypeId, Box<A>>,
_marker: PhantomData<K>,
}
impl<'a, K: Key, A: UnsafeAnyExt + ?Sized> OccupiedEntry<'a, K, A> {
pub fn get(&self) -> &K::Value
where
K::Value: Any + Implements<A>,
{
unsafe { self.data.get().downcast_ref_unchecked() }
}
pub fn get_mut(&mut self) -> &mut K::Value
where
K::Value: Any + Implements<A>,
{
unsafe { self.data.get_mut().downcast_mut_unchecked() }
}
pub fn into_mut(self) -> &'a mut K::Value
where
K::Value: Any + Implements<A>,
{
unsafe { self.data.into_mut().downcast_mut_unchecked() }
}
pub fn insert(&mut self, value: K::Value) -> K::Value
where
K::Value: Any + Implements<A>,
{
unsafe { *self.data.insert(value.into_object()).downcast_unchecked() }
}
pub fn remove(self) -> K::Value
where
K::Value: Any + Implements<A>,
{
unsafe { *self.data.remove().downcast_unchecked() }
}
}
impl<'a, K: Key, A: ?Sized + UnsafeAnyExt> VacantEntry<'a, K, A> {
pub fn insert(self, value: K::Value) -> &'a mut K::Value
where
K::Value: Any + Implements<A>,
{
unsafe {
self.data
.insert(value.into_object())
.downcast_mut_unchecked()
}
}
}
mod internals;
#[cfg(test)]
mod test {
use super::Entry::{Occupied, Vacant};
use super::{CloneMap, DebugMap, Key, SendMap, TypeMap};
#[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::<KeyType>(Value(100));
assert_eq!(*map.get::<KeyType>().unwrap(), Value(100));
assert!(map.contains::<KeyType>());
}
#[test]
fn test_remove() {
let mut map = TypeMap::new();
map.insert::<KeyType>(Value(10));
assert!(map.contains::<KeyType>());
map.remove::<KeyType>();
assert!(!map.contains::<KeyType>());
}
#[test]
fn test_entry() {
let mut map = TypeMap::new();
map.insert::<KeyType>(Value(20));
match map.entry::<KeyType>() {
Occupied(e) => {
assert_eq!(e.get(), &Value(20));
assert_eq!(e.remove(), Value(20));
}
_ => panic!("Unable to locate inserted item."),
}
assert!(!map.contains::<KeyType>());
match map.entry::<KeyType>() {
Vacant(e) => {
e.insert(Value(2));
}
_ => panic!("Found non-existant entry."),
}
assert!(map.contains::<KeyType>());
}
#[test]
fn test_entry_or_insert() {
let mut map = TypeMap::new();
map.entry::<KeyType>().or_insert(Value(20)).0 += 1;
assert_eq!(map.get::<KeyType>().unwrap(), &Value(21));
map.entry::<KeyType>().or_insert(Value(100)).0 += 1;
assert_eq!(map.get::<KeyType>().unwrap(), &Value(22));
}
#[test]
fn test_custom_bounds() {
let mut map: SendMap = TypeMap::custom();
map.insert::<KeyType>(Value(10));
assert!(map.contains::<KeyType>());
map.remove::<KeyType>();
assert!(!map.contains::<KeyType>());
}
#[test]
fn test_clonemap() {
let mut map: CloneMap = TypeMap::custom();
map.insert::<KeyType>(Value(10));
assert!(map.contains::<KeyType>());
let cloned = map.clone();
assert_eq!(map.get::<KeyType>(), cloned.get::<KeyType>());
}
#[test]
fn test_debugmap() {
let mut map: DebugMap = TypeMap::custom();
map.insert::<KeyType>(Value(10));
assert!(map.contains::<KeyType>());
}
}