use std::cell::RefCell; use std::num::{NonZero, NonZeroU16}; use std::rc::{Rc, Weak}; use std::{fmt, ops}; use futures_locks::RwLock; use hashbrown::HashMap; use orchid_base::builtin::Spawner; use orchid_base::interner::Interner; use crate::api; use crate::expr_store::ExprStore; use crate::system::{System, WeakSystem}; use crate::tree::WeakRoot; pub struct CtxData { pub i: Interner, pub spawn: Spawner, pub systems: RwLock>, pub system_id: RefCell, pub common_exprs: ExprStore, pub root: RwLock, } #[derive(Clone)] pub struct Ctx(Rc); impl ops::Deref for Ctx { type Target = CtxData; fn deref(&self) -> &Self::Target { &self.0 } } #[derive(Clone)] pub struct WeakCtx(Weak); impl WeakCtx { #[must_use] pub fn try_upgrade(&self) -> Option { Some(Ctx(self.0.upgrade()?)) } #[must_use] pub fn upgrade(&self) -> Ctx { self.try_upgrade().expect("Ctx manually kept alive until exit") } } impl Ctx { #[must_use] pub fn new(spawn: Spawner) -> Self { Self(Rc::new(CtxData { spawn, i: Interner::default(), systems: RwLock::default(), system_id: RefCell::new(NonZero::new(1).unwrap()), common_exprs: ExprStore::default(), root: RwLock::default(), })) } #[must_use] pub(crate) async fn system_inst(&self, id: api::SysId) -> Option { self.systems.read().await.get(&id).and_then(WeakSystem::upgrade) } #[must_use] pub(crate) fn next_sys_id(&self) -> api::SysId { let mut g = self.system_id.borrow_mut(); *g = g.checked_add(1).unwrap_or(NonZeroU16::new(1).unwrap()); api::SysId(*g) } #[must_use] pub fn downgrade(&self) -> WeakCtx { WeakCtx(Rc::downgrade(&self.0)) } } impl fmt::Debug for Ctx { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Ctx") .field("i", &self.i) .field("system_id", &self.system_id) .finish_non_exhaustive() } }