use crate::{unwrap, Key, Value};
use std::{
any::{type_name, Any, TypeId},
collections::btree_map,
fmt::{self, Debug, Formatter},
marker::PhantomData,
ops::{Deref, DerefMut},
};
pub enum Entry<'a, T> {
Vacant(VacantEntry<'a, T>),
Occupied(OccupiedEntry<'a, T>),
}
impl<'a, T: Debug + Any + Send + Sync + 'static> Debug for Entry<'a, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Vacant(vacant_entry) => f.debug_tuple("Vacant").field(vacant_entry).finish(),
Self::Occupied(occupied_entry) => {
f.debug_tuple("Occupied").field(occupied_entry).finish()
}
}
}
}
pub struct VacantEntry<'a, T>(
pub(super) btree_map::VacantEntry<'a, Key, Value>,
PhantomData<T>,
);
impl<'a, T: Debug + Any + Send + Sync + 'static> Debug for VacantEntry<'a, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "VacantEntry<{}>", type_name::<T>())
}
}
pub struct OccupiedEntry<'a, T>(
pub(super) btree_map::OccupiedEntry<'a, Key, Value>,
PhantomData<T>,
);
impl<'a, T: Debug + Any + Send + Sync + 'static> Debug for OccupiedEntry<'a, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple(&format!("OccupiedEntry<{}>", type_name::<T>()))
.field(unwrap!(self.0.get().downcast_ref::<T>()))
.finish()
}
}
impl<'a, T: Send + Sync + 'static> Entry<'a, T> {
pub fn or_insert(self, default: T) -> &'a mut T {
match self {
Entry::Vacant(vacant) => vacant.insert(default),
Entry::Occupied(occupied) => occupied.into_mut(),
}
}
pub fn or_insert_with(self, default: impl FnOnce() -> T) -> &'a mut T {
match self {
Entry::Vacant(vacant) => vacant.insert(default()),
Entry::Occupied(occupied) => occupied.into_mut(),
}
}
#[must_use]
pub fn and_modify(self, f: impl FnOnce(&mut T)) -> Self {
match self {
Entry::Vacant(vacant) => Entry::Vacant(vacant),
Entry::Occupied(mut occupied) => {
f(occupied.get_mut());
Entry::Occupied(occupied)
}
}
}
#[must_use]
pub fn take(self) -> Option<T> {
self.into_occupied().map(OccupiedEntry::remove)
}
#[must_use]
pub fn unwrap_occupied(self) -> OccupiedEntry<'a, T> {
self.into_occupied().unwrap_or_else(|| {
panic!(
"expected an occupied type-set entry for {}, but was vacant",
type_name::<T>()
)
})
}
#[must_use]
pub fn unwrap_vacant(self) -> VacantEntry<'a, T> {
self.into_vacant().unwrap_or_else(|| {
panic!(
"expected a vacant type-set entry for {}, but was occupied",
type_name::<T>()
)
})
}
#[must_use]
pub fn into_mut(self) -> Option<&'a mut T> {
self.into_occupied().map(OccupiedEntry::into_mut)
}
#[must_use]
pub fn into_occupied(self) -> Option<OccupiedEntry<'a, T>> {
match self {
Entry::Occupied(occupied_entry) => Some(occupied_entry),
Entry::Vacant(_) => None,
}
}
#[must_use]
pub fn into_vacant(self) -> Option<VacantEntry<'a, T>> {
match self {
Entry::Occupied(_) => None,
Entry::Vacant(vacant_entry) => Some(vacant_entry),
}
}
#[must_use]
pub fn is_empty(&self) -> bool {
matches!(self, Entry::Vacant(_))
}
pub fn insert(self, value: T) -> Option<T> {
match self {
Entry::Vacant(v) => {
#[cfg(feature = "log")]
log::trace!("inserting {}", type_name::<T>());
v.insert(value);
None
}
Entry::Occupied(mut o) => {
#[cfg(feature = "log")]
log::trace!("replacing {}", type_name::<T>());
Some(o.insert(value))
}
}
}
pub(super) fn new(entry: btree_map::Entry<'a, TypeId, Value>) -> Self {
match entry {
btree_map::Entry::Vacant(vacant) => Self::Vacant(VacantEntry(vacant, PhantomData)),
btree_map::Entry::Occupied(occupied) => {
Self::Occupied(OccupiedEntry(occupied, PhantomData))
}
}
}
}
impl<'a, T: Default + Send + Sync + 'static> Entry<'a, T> {
pub fn or_default(self) -> &'a mut T {
#[allow(clippy::unwrap_or_default)]
self.or_insert_with(T::default)
}
}
impl<'a, T: Send + Sync + 'static> VacantEntry<'a, T> {
pub fn insert(self, value: T) -> &'a mut T {
unwrap!(self.0.insert(Value::new(value)).downcast_mut())
}
}
impl<'a, T: Send + Sync + 'static> OccupiedEntry<'a, T> {
#[must_use]
pub fn get(&self) -> &T {
unwrap!(self.0.get().downcast_ref())
}
#[must_use]
pub fn get_mut(&mut self) -> &mut T {
unwrap!(self.0.get_mut().downcast_mut())
}
pub fn insert(&mut self, value: T) -> T {
unwrap!(self.0.insert(Value::new(value)).downcast())
}
#[allow(clippy::must_use_candidate)] pub fn remove(self) -> T {
unwrap!(self.0.remove().downcast())
}
#[must_use]
pub fn into_mut(self) -> &'a mut T {
unwrap!(self.0.into_mut().downcast_mut())
}
}
impl<'a, T: Send + Sync + 'static> Deref for OccupiedEntry<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.get()
}
}
impl<'a, T: Send + Sync + 'static> DerefMut for OccupiedEntry<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.get_mut()
}
}
impl<'a, T: Send + Sync + 'static> From<OccupiedEntry<'a, T>> for Entry<'a, T> {
fn from(occupied_entry: OccupiedEntry<'a, T>) -> Self {
Self::Occupied(occupied_entry)
}
}
impl<'a, T: Send + Sync + 'static> From<VacantEntry<'a, T>> for Entry<'a, T> {
fn from(vacant_entry: VacantEntry<'a, T>) -> Self {
Self::Vacant(vacant_entry)
}
}