use std::any::{Any, TypeId};
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::rc::Rc;
use crate::actor::shape::Declared;
mod actors;
mod features;
mod lifetime;
mod state;
mod tree;
#[cfg(test)]
mod tests;
pub use features::{Installed, Listener};
pub use lifetime::{Awake, DropGuard, Teardown};
pub use state::{DescribedState, Reducer, Slot, StateHandle, Subscription};
pub use tree::{ScopeGuard, ScopeTree};
use actors::HeldActor;
use state::{Cell, Kind};
use tree::{Tree, tree};
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct Scope {
tree: u32,
index: u32,
serial: u64,
}
impl std::fmt::Debug for Scope {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Scope({})", self.serial)
}
}
pub type Outlet = &'static str;
pub const MAIN: Outlet = "main";
#[derive(Default)]
struct ScopeData {
cells: RefCell<HashMap<TypeId, Cell>>,
kinds: RefCell<HashMap<TypeId, Kind>>,
teardowns: RefCell<Vec<Box<dyn FnOnce()>>>,
installed_features: RefCell<HashSet<TypeId>>,
exports: RefCell<HashSet<TypeId>>,
sections: RefCell<Vec<HashMap<TypeId, Rc<dyn Any>>>>,
section_names: RefCell<Vec<Option<&'static str>>>,
section_declarations: RefCell<Vec<Option<Declared>>>,
declarations: RefCell<HashMap<TypeId, Declared>>,
listeners: RefCell<Vec<Listener>>,
owners: RefCell<HashMap<TypeId, usize>>,
installing: RefCell<Vec<usize>>,
leave_guards: RefCell<Vec<Rc<dyn Fn() -> crate::guard::Verdict>>>,
asleep: Rc<std::cell::Cell<bool>>,
wake_hooks: RefCell<Vec<Rc<dyn Fn()>>>,
window: std::cell::Cell<Option<u64>>,
actors: RefCell<Vec<HeldActor>>,
}
impl Scope {
pub fn child(&self) -> Scope {
self.child_in(MAIN)
}
pub fn child_in(&self, outlet: Outlet) -> Scope {
let tree =
tree(self.tree).unwrap_or_else(|| panic!("a child for {self:?}, whose tree is gone"));
let mut nodes = tree.borrow_mut();
assert!(
nodes.node(self.index, self.serial).is_some(),
"a child for {self:?}, which was removed"
);
let (index, serial) = nodes.insert(Some(self.index), outlet);
Scope {
tree: self.tree,
index,
serial,
}
}
pub fn remove(&self) {
let Some(tree) = tree(self.tree) else {
return;
};
let detached = tree.borrow_mut().detach(self.index, self.serial);
drop(tree);
for data in detached {
data.tear_down();
}
}
pub fn is_alive(&self) -> bool {
self.read(|tree| tree.node(self.index, self.serial).is_some())
.unwrap_or(false)
}
pub fn parent(&self) -> Option<Scope> {
self.read(|tree| {
let parent = tree.node(self.index, self.serial)?.parent?;
Some(self.named(tree, parent))
})
.flatten()
}
pub fn outlet(&self) -> Option<Outlet> {
self.read(|tree| tree.node(self.index, self.serial).map(|node| node.outlet))
.flatten()
}
pub fn ancestors(&self) -> Vec<Scope> {
std::iter::successors(self.parent(), Scope::parent).collect()
}
pub fn children_in(&self, outlet: Outlet) -> Vec<Scope> {
self.read(|tree| {
let Some(node) = tree.node(self.index, self.serial) else {
return Vec::new();
};
node.children
.iter()
.filter(|&&child| tree.nodes[child as usize].outlet == outlet)
.map(|&child| self.named(tree, child))
.collect()
})
.unwrap_or_default()
}
pub fn beside(&self) -> Vec<Scope> {
self.read(|tree| {
let Some(node) = tree.node(self.index, self.serial) else {
return Vec::new();
};
node.children
.iter()
.filter(|&&child| tree.nodes[child as usize].outlet != MAIN)
.map(|&child| self.named(tree, child))
.collect()
})
.unwrap_or_default()
}
fn read<T>(&self, read: impl FnOnce(&Tree) -> T) -> Option<T> {
let tree = tree(self.tree)?;
let nodes = tree.borrow();
Some(read(&nodes))
}
fn named(&self, tree: &Tree, index: u32) -> Scope {
Scope {
tree: self.tree,
index,
serial: tree.nodes[index as usize].serial,
}
}
pub fn owner_of<R: 'static>(&self) -> Option<Scope> {
if self.claims::<R>() {
return Some(*self);
}
std::iter::successors(self.parent(), Scope::parent).find(|scope| scope.exports::<R>())
}
pub fn subtree(&self) -> Vec<Scope> {
self.read(|tree| {
if tree.node(self.index, self.serial).is_none() {
return Vec::new();
}
let mut order = Vec::new();
tree.collect(self.index, &mut order);
order
.into_iter()
.map(|index| self.named(tree, index))
.collect()
})
.unwrap_or_default()
}
pub fn guard(&self) -> ScopeGuard {
ScopeGuard(*self)
}
pub fn key(&self) -> usize {
self.serial as usize
}
fn data(&self) -> Option<Rc<ScopeData>> {
self.read(|tree| {
tree.node(self.index, self.serial)
.and_then(|node| node.data.clone())
})
.flatten()
}
fn installing(&self, doing: &str) -> Rc<ScopeData> {
self.data()
.unwrap_or_else(|| panic!("{doing} in {self:?}, which was removed"))
}
}
impl ScopeData {
fn section_name(&self, section: usize) -> Option<&'static str> {
self.section_names.borrow().get(section).copied().flatten()
}
fn current_section(&self) -> usize {
self.installing.borrow().last().copied().unwrap_or(0)
}
}