use std::any::Any;
use std::collections::BTreeMap;
use std::fmt;
use std::panic::RefUnwindSafe;
use std::sync::Arc;
trait ExtensionValue: Send + Sync + RefUnwindSafe {
fn as_any(&self) -> &dyn Any;
fn into_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
}
impl<T> ExtensionValue for T
where
T: Any + Send + Sync + RefUnwindSafe,
{
fn as_any(&self) -> &dyn Any {
self
}
fn into_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
self
}
}
type SharedExtension = Arc<dyn ExtensionValue>;
#[derive(Clone, Default)]
pub struct ExtensionStore {
values: BTreeMap<&'static str, SharedExtension>,
}
impl ExtensionStore {
#[must_use]
pub const fn new() -> Self {
Self {
values: BTreeMap::new(),
}
}
pub fn insert<T>(&mut self, key: &'static str, value: T)
where
T: Any + Send + Sync + RefUnwindSafe,
{
let _ = self.values.insert(key, Arc::new(value));
}
#[must_use]
pub fn get<T>(&self, key: &str) -> Option<&T>
where
T: Any + Send + Sync + RefUnwindSafe,
{
self.values.get(key)?.as_ref().as_any().downcast_ref()
}
#[must_use]
pub fn get_shared<T>(&self, key: &str) -> Option<Arc<T>>
where
T: Any + Send + Sync + RefUnwindSafe,
{
Arc::clone(self.values.get(key)?).into_any().downcast().ok()
}
pub fn clear(&mut self) {
self.values.clear();
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.values.is_empty()
}
#[must_use]
pub fn len(&self) -> usize {
self.values.len()
}
pub fn keys(&self) -> impl Iterator<Item = &'static str> + '_ {
self.values.keys().copied()
}
}
impl fmt::Debug for ExtensionStore {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("ExtensionStore")
.field("keys", &self.values.keys().collect::<Vec<_>>())
.finish()
}
}