use std::rc::Rc;
use super::runtime::{NodeId, Owner, Scope};
use super::with_runtime;
impl Owner {
pub fn new(parent: Option<Owner>) -> Owner {
with_runtime(|rt| {
let parent = parent.or_else(|| rt.current_owner());
let parent_paused = parent
.and_then(|p| rt.owners.get(p))
.map(|o| o.paused)
.unwrap_or(false);
let mut scope = Scope::new(parent);
scope.paused = parent_paused;
let id = rt.owners.insert(scope);
if let Some(p) = parent {
if let Some(parent_scope) = rt.owners.get_mut(p) {
parent_scope.children.push(id);
}
}
id
})
}
pub fn detached_root() -> Owner {
with_runtime(|rt| rt.owners.insert(Scope::new(None)))
}
pub fn with<R>(self, f: impl FnOnce() -> R) -> R {
with_runtime(|rt| rt.owner_stack.push(self));
let result = f();
with_runtime(|rt| {
let popped = rt.owner_stack.pop();
debug_assert_eq!(
popped,
Some(self),
"Owner::with: stack imbalance — owner pop didn't match push"
);
});
result
}
pub fn dispose(self) {
let children;
let nodes;
let cleanups;
let parent;
let mount_fn;
let elements;
{
let removed = with_runtime(|rt| rt.owners.remove(self));
let Some(o) = removed else { return };
children = o.children;
nodes = o.nodes;
cleanups = o.cleanups;
parent = o.parent;
mount_fn = o.mount_fn;
elements = o.elements;
}
if let Some(fp) = mount_fn {
with_runtime(|rt| {
if let Some(list) = rt.component_owners.get_mut(&fp) {
list.retain(|o| *o != self);
if list.is_empty() {
rt.component_owners.remove(&fp);
}
}
});
with_runtime(|rt| {
let stale: Vec<super::component::MountId> = rt
.mount_sites
.iter()
.filter_map(|(id, site)| {
if site.owner == Some(self) {
Some(*id)
} else {
None
}
})
.collect();
for id in stale {
rt.mount_sites.remove(&id);
if let Some(list) = rt.fn_ptr_mounts.get_mut(&fp) {
list.retain(|m| *m != id);
if list.is_empty() {
rt.fn_ptr_mounts.remove(&fp);
}
}
}
});
}
if let Some(p) = parent {
with_runtime(|rt| {
if let Some(parent_scope) = rt.owners.get_mut(p) {
parent_scope.children.retain(|&c| c != self);
}
});
}
for child in children {
child.dispose();
}
let arc_unsubscribes: Vec<(Rc<dyn super::runtime::ArcSubscription>, NodeId)> =
with_runtime(|rt| {
let mut out: Vec<(Rc<dyn super::runtime::ArcSubscription>, NodeId)> = Vec::new();
for node_id in &nodes {
let Some(node) = rt.nodes.remove(*node_id) else {
continue;
};
for source in node.sources {
if let Some(src_node) = rt.nodes.get_mut(source) {
src_node.subscribers.remove(node_id);
}
}
for sub in node.subscribers {
if let Some(sub_node) = rt.nodes.get_mut(sub) {
sub_node.sources.remove(node_id);
}
}
for arc_src in node.arc_sources {
out.push((arc_src, *node_id));
}
}
rt.pending.retain(|n| !nodes.contains(n));
rt.deferred.retain(|n| !nodes.contains(n));
out
});
for (arc_src, subscriber) in arc_unsubscribes {
arc_src.unsubscribe(subscriber);
}
for handle in elements {
crate::view::release_element(handle);
}
for cleanup in cleanups.into_iter().rev() {
cleanup();
}
}
pub fn pause(self) {
with_runtime(|rt| {
let mut stack = vec![self];
while let Some(id) = stack.pop() {
let Some(o) = rt.owners.get_mut(id) else {
continue;
};
if o.paused {
continue;
}
o.paused = true;
stack.extend(o.children.iter().copied());
}
});
}
pub fn resume(self) {
let any_resumed = with_runtime(|rt| {
let mut stack = vec![self];
let mut any = false;
while let Some(id) = stack.pop() {
let Some(o) = rt.owners.get_mut(id) else {
continue;
};
if !o.paused {
continue;
}
o.paused = false;
any = true;
stack.extend(o.children.iter().copied());
}
if !any {
return false;
}
let deferred = std::mem::take(&mut rt.deferred);
for node in deferred {
let still_paused = rt
.nodes
.get(node)
.and_then(|n| rt.owners.get(n.owner))
.map(|o| o.paused);
match still_paused {
Some(false) => {
if !rt.pending.contains(&node) {
rt.pending.push(node);
}
}
Some(true) => rt.deferred.push(node),
None => {} }
}
true
});
if any_resumed {
crate::host_wake::wake_runtime();
}
}
pub fn is_paused(self) -> bool {
with_runtime(|rt| rt.owners.get(self).map(|o| o.paused).unwrap_or(false))
}
}
pub fn on_cleanup(f: impl FnOnce() + 'static) {
let registered = with_runtime(|rt| {
let Some(owner_id) = rt.current_owner() else {
return false;
};
if let Some(scope) = rt.owners.get_mut(owner_id) {
scope.cleanups.push(Box::new(f));
return true;
}
false
});
if !registered {
debug_assert!(
false,
"on_cleanup called outside any owner — registration ignored"
);
}
}