use std::collections::HashMap;
use std::any::{Any, TypeId};
use std::hash::{BuildHasherDefault, Hasher};
use std::ptr;
use unsafe_any::{UnsafeAny, UnsafeAnyExt};
#[derive(Default)]
pub struct TypeIdHasher {
value: u64,
}
impl Hasher for TypeIdHasher {
fn finish(&self) -> u64 {
self.value
}
fn write(&mut self, bytes: &[u8]) {
debug_assert!(bytes.len() == 8);
unsafe {
ptr::copy_nonoverlapping(&bytes[0] as *const u8 as *const u64, &mut self.value, 1)
}
}
}
#[doc(hidden)]
pub unsafe trait Implements<A: ?Sized + UnsafeAnyExt> {
fn into_object(self) -> Box<A>;
}
unsafe impl<T: UnsafeAny> Implements<UnsafeAny> for T {
fn into_object(self) -> Box<UnsafeAny> {
Box::new(self)
}
}
unsafe impl<T: UnsafeAny + Send + Sync> Implements<(UnsafeAny + Send + Sync)> for T {
fn into_object(self) -> Box<UnsafeAny + Send + Sync> {
Box::new(self)
}
}
#[derive(Default, Debug)]
pub struct TypeMap<A: ?Sized = UnsafeAny>
where
A: UnsafeAnyExt,
{
data: HashMap<TypeId, Box<A>, BuildHasherDefault<TypeIdHasher>>,
}
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::default(),
}
}
pub fn put<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) -> &K::Value
where
K::Value: Any + Implements<A>,
{
self.try_get::<K>().unwrap()
}
pub fn try_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 has<K: Key>(&self) -> bool {
self.data.contains_key(&TypeId::of::<K>())
}
}
pub type ShareMap = TypeMap<UnsafeAny + Sync + Send>;
#[cfg(test)]
mod tests {
use std::mem;
use std::hash::{Hash, Hasher};
use super::{Key, TypeId, TypeIdHasher, TypeMap};
#[derive(Debug, PartialEq)]
struct KeyType;
#[derive(Clone, Debug, PartialEq)]
struct ValueType(u8);
impl Key for KeyType {
type Value = ValueType;
}
#[test]
fn test_pair_key_to_value() {
let mut map = TypeMap::new();
map.put::<KeyType>(ValueType(32));
assert_eq!(map.get::<KeyType>(), &ValueType(32));
assert!(map.has::<KeyType>());
}
#[test]
fn test_type_id_hasher() {
fn verify_hashing_with(type_id: TypeId) {
let mut hasher = TypeIdHasher::default();
type_id.hash(&mut hasher);
assert_eq!(hasher.finish(), unsafe {
mem::transmute::<TypeId, u64>(type_id)
});
}
verify_hashing_with(TypeId::of::<usize>());
verify_hashing_with(TypeId::of::<()>());
verify_hashing_with(TypeId::of::<str>());
verify_hashing_with(TypeId::of::<&str>());
verify_hashing_with(TypeId::of::<Vec<u8>>());
}
}