use core::any::{Any, TypeId};
use std::collections::HashMap;
use std::sync::Arc;
use crate::compati::Mutex;
use foundation_compact::rng::{ChaCha8Rng, SeedableRng};
use foundation_compact::{Duration, Instant};
pub trait Clock: Send + Sync + 'static {
#[must_use]
fn now(&self) -> Instant;
#[must_use]
fn elapsed(&self) -> Duration;
}
#[derive(Debug, Clone, Copy)]
pub struct MonotonicClock {
origin: Instant,
}
impl MonotonicClock {
#[must_use]
pub fn new() -> Self {
Self {
origin: Instant::now(),
}
}
}
impl Clock for MonotonicClock {
fn now(&self) -> Instant {
Instant::now()
}
fn elapsed(&self) -> Duration {
self.origin.elapsed()
}
}
impl Default for MonotonicClock {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct Config;
impl Config {
#[must_use]
pub fn new() -> Self {
Config
}
}
pub struct Ctx(Arc<CtxInner>);
pub(crate) struct CtxInner {
map: Mutex<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>,
clock: Arc<dyn Clock>,
config: Arc<Config>,
rng: Arc<Mutex<ChaCha8Rng>>,
}
impl Ctx {
#[must_use]
pub fn new() -> Self {
Ctx(Arc::new(CtxInner {
map: Mutex::new(HashMap::new()),
clock: Arc::new(MonotonicClock::new()),
config: Arc::new(Config::new()),
rng: Arc::new(Mutex::new(ChaCha8Rng::seed_from_u64(0))),
}))
}
pub fn insert<T: Any + Send + Sync>(&self, value: Arc<T>) -> Option<Arc<T>> {
self.0
.map
.lock()
.expect("Ctx map poisoned")
.insert(TypeId::of::<T>(), value)
.and_then(|prior| prior.downcast::<T>().ok())
}
#[must_use]
pub fn get<T: Any + Send + Sync>(&self) -> Option<Arc<T>> {
self.0
.map
.lock()
.expect("Ctx map poisoned")
.get(&TypeId::of::<T>())
.cloned()
.and_then(|value| value.downcast::<T>().ok())
}
#[must_use]
pub fn get_or_insert<T: Any + Send + Sync>(&self, value: T) -> Arc<T> {
let mut map = self.0.map.lock().expect("Ctx map poisoned");
if let Some(existing) = map.get(&TypeId::of::<T>()) {
if let Ok(existing) = existing.clone().downcast::<T>() {
return existing;
}
}
let arc = Arc::new(value);
map.insert(TypeId::of::<T>(), arc.clone());
arc
}
#[must_use]
pub fn remove<T: Any + Send + Sync>(&self) -> Option<Arc<T>> {
self.0
.map
.lock()
.expect("Ctx map poisoned")
.remove(&TypeId::of::<T>())
.and_then(|value| value.downcast::<T>().ok())
}
#[must_use]
pub fn contains<T: Any + Send + Sync>(&self) -> bool {
self.0
.map
.lock()
.expect("Ctx map poisoned")
.contains_key(&TypeId::of::<T>())
}
#[must_use]
pub fn clock(&self) -> Arc<dyn Clock> {
self.0.clock.clone()
}
#[must_use]
pub fn config(&self) -> Arc<Config> {
self.0.config.clone()
}
#[must_use]
pub fn rng(&self) -> Arc<Mutex<ChaCha8Rng>> {
self.0.rng.clone()
}
#[must_use]
pub fn fork(&self) -> Ctx {
let map = self.0.map.lock().expect("Ctx map poisoned").clone();
Ctx(Arc::new(CtxInner {
map: Mutex::new(map),
clock: self.0.clock.clone(),
config: self.0.config.clone(),
rng: self.0.rng.clone(),
}))
}
}
impl Clone for Ctx {
fn clone(&self) -> Self {
Ctx(self.0.clone())
}
}
impl Default for Ctx {
fn default() -> Self {
Self::new()
}
}