use std::any::{Any, TypeId};
use std::collections::HashMap;
#[derive(Default)]
pub struct Extensions {
map: HashMap<TypeId, Box<dyn Any + Send + Sync>>,
}
impl Extensions {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn insert<T: Any + Send + Sync>(&mut self, value: T) {
self.map.insert(TypeId::of::<T>(), Box::new(value));
}
#[must_use]
pub fn get<T: Any + Send + Sync>(&self) -> Option<&T> {
self.map.get(&TypeId::of::<T>())?.downcast_ref::<T>()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
}
impl std::fmt::Debug for Extensions {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Extensions")
.field("entries", &self.map.len())
.finish_non_exhaustive()
}
}
#[cfg(test)]
mod tests {
use super::Extensions;
#[test]
fn one_value_per_type_and_distinct_types_coexist() {
let mut ext = Extensions::new();
assert!(ext.is_empty());
ext.insert(1u32);
ext.insert(2u32);
assert_eq!(ext.get::<u32>(), Some(&2));
ext.insert("tag");
assert_eq!(ext.get::<&str>(), Some(&"tag"));
assert_eq!(ext.get::<i64>(), None);
assert!(!ext.is_empty());
}
#[test]
fn debug_reports_entry_count() {
let mut ext = Extensions::new();
ext.insert(1u8);
assert!(format!("{ext:?}").contains("entries: 1"));
}
}