#![warn(missing_docs, unused_results)]
#![allow(unused_doc_comments)]
use std::{any::TypeId, marker::PhantomData};
use crate::{
any::{Any, IntoBox, UncheckedAnyExt},
raw::RawMap,
};
macro_rules! impl_common_methods {
(
field: $t:ident.$field:ident;
new() => $new:expr;
with_capacity($with_capacity_arg:ident) => $with_capacity:expr;
) => {
impl<A: ?Sized + UncheckedAnyExt> $t<A> {
#[inline]
pub fn new() -> $t<A> {
$t { $field: $new }
}
#[inline]
pub fn with_capacity($with_capacity_arg: usize) -> $t<A> {
$t {
$field: $with_capacity,
}
}
#[inline]
pub fn capacity(&self) -> usize {
self.$field.capacity()
}
#[inline]
pub fn reserve(&mut self, additional: usize) {
self.$field.reserve(additional)
}
#[inline]
pub fn shrink_to_fit(&mut self) {
self.$field.shrink_to_fit()
}
#[inline]
pub fn len(&self) -> usize {
self.$field.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.$field.is_empty()
}
#[inline]
pub fn clear(&mut self) {
self.$field.clear()
}
}
impl<A: ?Sized + UncheckedAnyExt> Default for $t<A> {
#[inline]
fn default() -> $t<A> {
$t::new()
}
}
};
}
pub mod any;
pub mod raw;
#[derive(Debug)]
pub struct Map<A: ?Sized + UncheckedAnyExt = dyn Any> {
raw: RawMap<A>,
}
impl<A: ?Sized + UncheckedAnyExt> Clone for Map<A>
where
Box<A>: Clone,
{
#[inline]
fn clone(&self) -> Map<A> {
Map {
raw: self.raw.clone(),
}
}
}
pub type AnyMap = Map<dyn Any>;
pub type SendSyncAnyMap = Map<dyn Any + Send + Sync>;
impl_common_methods! {
field: Map.raw;
new() => RawMap::new();
with_capacity(capacity) => RawMap::with_capacity(capacity);
}
impl<A: ?Sized + UncheckedAnyExt> Map<A> {
#[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 get_mut<T: IntoBox<A>>(&mut self) -> Option<&mut T> {
self.raw
.get_mut(&TypeId::of::<T>())
.map(|any| unsafe { any.downcast_mut_unchecked::<T>() })
}
#[inline]
pub fn insert<T: IntoBox<A>>(&mut self, value: T) -> Option<T> {
unsafe {
self.raw
.insert(TypeId::of::<T>(), value.into_box())
.map(|any| *any.downcast_unchecked::<T>())
}
}
#[inline]
pub fn remove<T: IntoBox<A>>(&mut self) -> Option<T> {
self.raw
.remove(&TypeId::of::<T>())
.map(|any| *unsafe { any.downcast_unchecked::<T>() })
}
#[inline]
pub fn contains<T: IntoBox<A>>(&self) -> bool {
self.raw.contains_key(&TypeId::of::<T>())
}
#[inline]
pub fn entry<T: IntoBox<A>>(&mut self) -> Entry<A, T> {
match self.raw.entry(TypeId::of::<T>()) {
raw::Entry::Occupied(e) => Entry::Occupied(OccupiedEntry {
inner: e,
type_: PhantomData,
}),
raw::Entry::Vacant(e) => Entry::Vacant(VacantEntry {
inner: e,
type_: PhantomData,
}),
}
}
}
impl<A: ?Sized + UncheckedAnyExt> AsRef<RawMap<A>> for Map<A> {
#[inline]
fn as_ref(&self) -> &RawMap<A> {
&self.raw
}
}
impl<A: ?Sized + UncheckedAnyExt> AsMut<RawMap<A>> for Map<A> {
#[inline]
fn as_mut(&mut self) -> &mut RawMap<A> {
&mut self.raw
}
}
impl<A: ?Sized + UncheckedAnyExt> From<Map<A>> for RawMap<A> {
#[inline]
fn from(map: Map<A>) -> Self {
map.raw
}
}
pub struct OccupiedEntry<'a, A: ?Sized + UncheckedAnyExt, V: 'a> {
inner: raw::OccupiedEntry<'a, A>,
type_: PhantomData<V>,
}
pub struct VacantEntry<'a, A: ?Sized + UncheckedAnyExt, V: 'a> {
inner: raw::VacantEntry<'a, A>,
type_: PhantomData<V>,
}
pub enum Entry<'a, A: ?Sized + UncheckedAnyExt, V: 'a> {
Occupied(OccupiedEntry<'a, A, V>),
Vacant(VacantEntry<'a, A, V>),
}
impl<'a, A: ?Sized + UncheckedAnyExt, V: IntoBox<A>> Entry<'a, A, V> {
#[inline]
pub fn or_insert(self, default: V) -> &'a mut V {
match self {
Entry::Occupied(inner) => inner.into_mut(),
Entry::Vacant(inner) => inner.insert(default),
}
}
#[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 + UncheckedAnyExt, V: Default + IntoBox<A>> Entry<'a, A, V> {
pub fn or_default(self) -> &'a mut V {
match self {
Entry::Occupied(entry) => entry.into_mut(),
Entry::Vacant(entry) => entry.insert(Default::default()),
}
}
}
impl<'a, A: ?Sized + UncheckedAnyExt, V: IntoBox<A>> OccupiedEntry<'a, A, V> {
#[inline]
pub fn get(&self) -> &V {
unsafe { self.inner.get().downcast_ref_unchecked() }
}
#[inline]
pub fn get_mut(&mut self) -> &mut V {
unsafe { self.inner.get_mut().downcast_mut_unchecked() }
}
#[inline]
pub fn into_mut(self) -> &'a mut V {
unsafe { self.inner.into_mut().downcast_mut_unchecked() }
}
#[inline]
pub fn insert(&mut self, value: V) -> V {
unsafe { *self.inner.insert(value.into_box()).downcast_unchecked() }
}
#[inline]
pub fn remove(self) -> V {
unsafe { *self.inner.remove().downcast_unchecked() }
}
}
impl<'a, A: ?Sized + UncheckedAnyExt, 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 crate::{
any::{Any, CloneAny, CloneAnySend, CloneAnySendSync, CloneAnySync},
AnyMap, Entry, Map,
};
#[derive(Clone, Debug, PartialEq)]
struct A(i32);
#[derive(Clone, Debug, PartialEq)]
struct B(i32);
#[derive(Clone, Debug, PartialEq)]
struct C(i32);
#[derive(Clone, Debug, PartialEq)]
struct D(i32);
#[derive(Clone, Debug, PartialEq)]
struct E(i32);
#[derive(Clone, Debug, PartialEq)]
struct F(i32);
#[derive(Clone, Debug, PartialEq)]
struct J(i32);
macro_rules! test_entry {
($name:ident, $init:ty) => {
#[test]
fn $name() {
let mut map = <$init>::new();
assert_eq!(map.insert(A(10)), None);
assert_eq!(map.insert(B(20)), None);
assert_eq!(map.insert(C(30)), None);
assert_eq!(map.insert(D(40)), None);
assert_eq!(map.insert(E(50)), None);
assert_eq!(map.insert(F(60)), None);
match map.entry::<A>() {
Entry::Vacant(_) => unreachable!(),
Entry::Occupied(mut view) => {
assert_eq!(view.get(), &A(10));
assert_eq!(view.insert(A(100)), A(10));
}
}
assert_eq!(map.get::<A>().unwrap(), &A(100));
assert_eq!(map.len(), 6);
match map.entry::<B>() {
Entry::Vacant(_) => unreachable!(),
Entry::Occupied(mut view) => {
let v = view.get_mut();
let new_v = B(v.0 * 10);
*v = new_v;
}
}
assert_eq!(map.get::<B>().unwrap(), &B(200));
assert_eq!(map.len(), 6);
match map.entry::<C>() {
Entry::Vacant(_) => unreachable!(),
Entry::Occupied(view) => {
assert_eq!(view.remove(), C(30));
}
}
assert_eq!(map.get::<C>(), None);
assert_eq!(map.len(), 5);
match map.entry::<J>() {
Entry::Occupied(_) => unreachable!(),
Entry::Vacant(view) => {
assert_eq!(*view.insert(J(1000)), J(1000));
}
}
assert_eq!(map.get::<J>().unwrap(), &J(1000));
assert_eq!(map.len(), 6);
map.entry::<B>().or_insert(B(71)).0 += 1;
assert_eq!(map.get::<B>().unwrap(), &B(201));
assert_eq!(map.len(), 6);
map.entry::<C>().or_insert(C(300)).0 += 1;
assert_eq!(map.get::<C>().unwrap(), &C(301));
assert_eq!(map.len(), 7);
}
};
}
test_entry!(test_entry_any, AnyMap);
test_entry!(test_entry_cloneany, Map<dyn CloneAny>);
#[test]
fn test_default() {
let map: AnyMap = Default::default();
assert_eq!(map.len(), 0);
}
#[test]
fn test_clone() {
let mut map: Map<dyn CloneAny> = Map::new();
let _ = map.insert(A(1));
let _ = map.insert(B(2));
let _ = map.insert(D(3));
let _ = map.insert(E(4));
let _ = map.insert(F(5));
let _ = map.insert(J(6));
let map2 = map.clone();
assert_eq!(map2.len(), 6);
assert_eq!(map2.get::<A>(), Some(&A(1)));
assert_eq!(map2.get::<B>(), Some(&B(2)));
assert_eq!(map2.get::<C>(), None);
assert_eq!(map2.get::<D>(), Some(&D(3)));
assert_eq!(map2.get::<E>(), Some(&E(4)));
assert_eq!(map2.get::<F>(), Some(&F(5)));
assert_eq!(map2.get::<J>(), Some(&J(6)));
}
#[test]
fn test_varieties() {
fn assert_send<T: Send>() {}
fn assert_sync<T: Sync>() {}
fn assert_clone<T: Clone>() {}
fn assert_debug<T: ::std::fmt::Debug>() {}
assert_send::<Map<dyn Any + Send>>();
assert_send::<Map<dyn Any + Send + Sync>>();
assert_sync::<Map<dyn Any + Sync>>();
assert_sync::<Map<dyn Any + Send + Sync>>();
assert_debug::<Map<dyn Any>>();
assert_debug::<Map<dyn Any + Send>>();
assert_debug::<Map<dyn Any + Sync>>();
assert_debug::<Map<dyn Any + Send + Sync>>();
assert_send::<Map<dyn CloneAnySend + Send>>();
assert_send::<Map<dyn CloneAnySendSync + Send + Sync>>();
assert_sync::<Map<dyn CloneAnySync + Sync>>();
assert_sync::<Map<dyn CloneAnySendSync + Send + Sync>>();
assert_clone::<Map<dyn CloneAnySend + Send>>();
assert_clone::<Map<dyn CloneAnySendSync + Send + Sync>>();
assert_clone::<Map<dyn CloneAnySync + Sync>>();
assert_clone::<Map<dyn CloneAnySendSync + Send + Sync>>();
assert_debug::<Map<dyn CloneAny>>();
assert_debug::<Map<dyn CloneAnySend + Send>>();
assert_debug::<Map<dyn CloneAnySync + Sync>>();
assert_debug::<Map<dyn CloneAnySendSync + Send + Sync>>();
}
}