#![warn(missing_docs, unused_results)]
use core::hash::Hasher;
#[derive(Default)]
pub struct TypeIdHasher {
value: u64,
}
impl Hasher for TypeIdHasher {
#[inline]
fn write(&mut self, bytes: &[u8]) {
debug_assert_eq!(bytes.len(), 8);
let _ = bytes.try_into().map(|array| self.value = u64::from_ne_bytes(array));
}
#[inline]
fn finish(&self) -> u64 {
self.value
}
}
use core::any::{Any, TypeId};
use core::hash::BuildHasherDefault;
use core::marker::PhantomData;
use ::std::collections::hash_map;
#[allow(clippy::disallowed_types)] pub type RawMap<A> = hash_map::HashMap<TypeId, Box<A>, BuildHasherDefault<TypeIdHasher>>;
#[doc = "let mut data = anymap::AnyMap::new();"]
#[derive(Debug)]
pub struct Map<A: ?Sized + Downcast = dyn Any> {
raw: RawMap<A>,
}
pub type AnyMap = Map<dyn Any>;
impl<A: ?Sized + Downcast> Default for Map<A> {
#[inline]
fn default() -> Map<A> {
Map::new()
}
}
impl<A: ?Sized + Downcast> Map<A> {
#[inline]
pub fn new() -> Map<A> {
Map { raw: RawMap::with_hasher(Default::default()) }
}
#[inline]
pub fn get<T: IntoBox<A>>(&self) -> Option<&T> {
self.raw.get(&TypeId::of::<T>()).map(|any| unsafe { any.downcast_ref_unchecked::<T>() })
}
#[inline]
pub fn entry<T: IntoBox<A>>(&mut self) -> Entry<'_, A, T> {
match self.raw.entry(TypeId::of::<T>()) {
hash_map::Entry::Occupied(e) => {
Entry::Occupied(OccupiedEntry { inner: e, type_: PhantomData })
}
hash_map::Entry::Vacant(e) => {
Entry::Vacant(VacantEntry { inner: e, type_: PhantomData })
}
}
}
}
pub struct OccupiedEntry<'a, A: ?Sized + Downcast, V: 'a> {
inner: hash_map::OccupiedEntry<'a, TypeId, Box<A>>,
type_: PhantomData<V>,
}
pub struct VacantEntry<'a, A: ?Sized + Downcast, V: 'a> {
inner: hash_map::VacantEntry<'a, TypeId, Box<A>>,
type_: PhantomData<V>,
}
pub enum Entry<'a, A: ?Sized + Downcast, V> {
Occupied(OccupiedEntry<'a, A, V>),
Vacant(VacantEntry<'a, A, V>),
}
impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> Entry<'a, A, V> {
#[inline]
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
match self {
Entry::Occupied(inner) => inner.into_mut(),
Entry::Vacant(inner) => inner.insert(default()),
}
}
}
impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> OccupiedEntry<'a, A, V> {
#[inline]
pub fn into_mut(self) -> &'a mut V {
unsafe { self.inner.into_mut().downcast_mut_unchecked() }
}
}
impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> VacantEntry<'a, A, V> {
#[inline]
pub fn insert(self, value: V) -> &'a mut V {
unsafe { self.inner.insert(value.into_box()).downcast_mut_unchecked() }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_varieties() {
fn assert_send<T: Send>() {}
fn assert_sync<T: Sync>() {}
fn assert_debug<T: ::core::fmt::Debug>() {}
assert_send::<Map<dyn Any + Send>>();
assert_send::<Map<dyn Any + Send + Sync>>();
assert_sync::<Map<dyn Any + Send + Sync>>();
assert_debug::<Map<dyn Any>>();
assert_debug::<Map<dyn Any + Send>>();
assert_debug::<Map<dyn Any + Send + Sync>>();
assert_send::<Map<dyn CloneAny + Send>>();
assert_send::<Map<dyn CloneAny + Send + Sync>>();
assert_sync::<Map<dyn CloneAny + Send + Sync>>();
assert_debug::<Map<dyn CloneAny>>();
assert_debug::<Map<dyn CloneAny + Send>>();
assert_debug::<Map<dyn CloneAny + Send + Sync>>();
}
#[test]
fn type_id_hasher() {
use core::any::TypeId;
use core::hash::Hash;
fn verify_hashing_with(type_id: TypeId) {
let mut hasher = TypeIdHasher::default();
type_id.hash(&mut hasher);
let _ = hasher.finish();
}
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>>());
}
}
use core::fmt;
#[doc(hidden)]
pub trait CloneToAny {
fn clone_to_any(&self) -> Box<dyn CloneAny>;
}
impl<T: Any + Clone> CloneToAny for T {
#[inline]
fn clone_to_any(&self) -> Box<dyn CloneAny> {
Box::new(self.clone())
}
}
macro_rules! impl_clone {
($t:ty) => {
impl Clone for Box<$t> {
#[inline]
fn clone(&self) -> Box<$t> {
let clone: Box<dyn CloneAny> = (**self).clone_to_any();
let raw: *mut dyn CloneAny = Box::into_raw(clone);
unsafe { Box::from_raw(raw as *mut $t) }
}
}
impl fmt::Debug for $t {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad(stringify!($t))
}
}
};
}
pub trait Downcast {
fn type_id(&self) -> TypeId;
unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T;
unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T;
}
pub trait IntoBox<A: ?Sized + Downcast>: Any {
fn into_box(self) -> Box<A>;
}
macro_rules! implement {
($any_trait:ident $(+ $auto_traits:ident)*) => {
impl Downcast for dyn $any_trait $(+ $auto_traits)* {
#[inline]
fn type_id(&self) -> TypeId {
self.type_id()
}
#[inline]
unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
&*(self as *const Self as *const T)
}
#[inline]
unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
&mut *(self as *mut Self as *mut T)
}
}
impl<T: $any_trait $(+ $auto_traits)*> IntoBox<dyn $any_trait $(+ $auto_traits)*> for T {
#[inline]
fn into_box(self) -> Box<dyn $any_trait $(+ $auto_traits)*> {
Box::new(self)
}
}
}
}
implement!(Any);
implement!(Any + Send);
implement!(Any + Send + Sync);
pub trait CloneAny: Any + CloneToAny {}
impl<T: Any + Clone> CloneAny for T {}
implement!(CloneAny);
implement!(CloneAny + Send);
implement!(CloneAny + Send + Sync);
impl_clone!(dyn CloneAny);
impl_clone!(dyn CloneAny + Send);
impl_clone!(dyn CloneAny + Send + Sync);