use alloc::boxed::Box;
use core::{
any::{Any, TypeId},
fmt,
hash::{BuildHasherDefault, Hasher},
};
use hashbrown::HashMap;
type AnyMap = HashMap<TypeId, Box<dyn Any + Send + Sync>, BuildHasherDefault<IdHasher>>;
#[derive(Default)]
struct IdHasher(u64);
impl Hasher for IdHasher {
fn write(&mut self, _: &[u8]) {
unreachable!("TypeId calls write_u64");
}
#[inline]
fn write_u64(&mut self, id: u64) {
self.0 = id;
}
#[inline]
fn finish(&self) -> u64 {
self.0
}
}
#[derive(Default)]
pub struct Map(Option<Box<AnyMap>>);
impl Map {
#[inline]
pub fn new() -> Self {
Self(None)
}
pub fn insert<T: Send + Sync + 'static>(&mut self, value: T) -> Option<T> {
self.0
.get_or_insert_with(Default::default)
.insert(TypeId::of::<T>(), Box::new(value))
.and_then(|boxed| boxed.downcast().ok().map(|v| *v))
}
pub fn remove<T: Send + Sync + 'static>(&mut self) -> Option<T> {
self.0
.as_mut()
.and_then(|map| map.remove(&TypeId::of::<T>()))
.and_then(|boxed| boxed.downcast().ok().map(|v| *v))
}
pub fn get<T: Send + Sync + 'static>(&self) -> Option<&T> {
self.0
.as_ref()
.and_then(|map| map.get(&TypeId::of::<T>()))
.and_then(|boxed| boxed.downcast_ref())
}
pub fn get_mut<T: Send + Sync + 'static>(&mut self) -> Option<&mut T> {
self.0
.as_mut()
.and_then(|map| map.get_mut(&TypeId::of::<T>()))
.and_then(|boxed| boxed.downcast_mut())
}
#[inline]
pub fn clear(&mut self) {
if let Some(map) = self.0.as_mut() {
map.clear();
}
}
#[inline]
pub fn is_empty(&self) -> bool {
self.0.as_ref().map_or(true, |map| map.is_empty())
}
#[inline]
pub fn len(&self) -> usize {
self.0.as_ref().map_or(0, |map| map.len())
}
pub fn extend(&mut self, other: Self) {
if let Some(other) = other.0 {
if let Some(map) = self.0.as_mut() {
map.extend(*other);
} else {
self.0 = Some(other);
}
}
}
}
impl fmt::Debug for Map {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Context").field("len", &self.len()).finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn basic_operations() {
#[derive(Debug, PartialEq)]
struct Foo(i32);
let mut context = Map::new();
assert!(context.is_empty());
assert_eq!(context.len(), 0);
context.insert(1);
assert!(!context.is_empty());
assert_eq!(context.len(), 1);
context.insert(Foo(2));
assert!(!context.is_empty());
assert_eq!(context.len(), 2);
let previous = context.insert(Foo(3));
assert!(!context.is_empty());
assert_eq!(context.len(), 2);
assert_eq!(previous, Some(Foo(2)));
assert_eq!(context.get::<i32>(), Some(&1));
assert_eq!(context.get_mut::<Foo>(), Some(&mut Foo(3)));
assert_eq!(context.remove::<Foo>(), Some(Foo(3)));
assert_eq!(context.remove::<i32>(), Some(1));
assert_eq!(context.remove::<i32>(), None);
assert!(context.is_empty());
assert_eq!(context.len(), 0);
}
}
#[derive(Debug, Default)]
pub struct Context {
env: Map,
data: Map,
}
impl Context {
pub fn with_data(data: Map) -> Self {
Self {
env: Map::new(),
data,
}
}
pub fn env(&self) -> &Map {
&self.env
}
pub fn env_mut(&mut self) -> &mut Map {
&mut self.env
}
pub fn data(&self) -> &Map {
&self.data
}
pub fn data_mut(&mut self) -> &mut Map {
&mut self.data
}
}