use std::rc::Rc;
use tokio::task::JoinHandle;
use crate::actor::Addr;
use crate::actor::event_bus::subscribe::BusSubscription;
use super::{Scope, ScopeData};
#[derive(Clone)]
pub struct Awake(Rc<std::cell::Cell<bool>>);
impl Awake {
pub fn now(&self) -> bool {
!self.0.get()
}
}
impl Scope {
pub fn own_subscription(&self, subscription: BusSubscription) {
self.own(DropGuard(subscription));
}
pub fn own<R: Teardown>(&self, resource: R) {
match self.data() {
Some(data) => data
.teardowns
.borrow_mut()
.push(Box::new(move || resource.teardown())),
None => resource.teardown(),
}
}
pub fn on_leave(&self, guard: impl Fn() -> crate::guard::Verdict + 'static) {
let data = self.installing("guarding a leave");
data.leave_guards.borrow_mut().push(Rc::new(guard));
}
pub fn leave_guards(&self) -> Vec<Rc<dyn Fn() -> crate::guard::Verdict>> {
self.data()
.map(|data| data.leave_guards.borrow().clone())
.unwrap_or_default()
}
pub fn sleep(&self) {
if let Some(data) = self.data() {
data.asleep.set(true);
}
}
pub fn wake(&self) {
let Some(data) = self.data() else { return };
data.asleep.set(false);
let hooks = data.wake_hooks.borrow().clone();
drop(data);
for hook in hooks {
hook();
}
}
pub fn is_awake(&self) -> bool {
self.data().is_some_and(|data| !data.asleep.get())
}
pub fn awake(&self) -> Awake {
match self.data() {
Some(data) => Awake(data.asleep.clone()),
None => Awake(Rc::new(std::cell::Cell::new(true))),
}
}
pub fn on_wake(&self, hook: impl Fn() + 'static) {
let data = self.installing("waiting for a wake");
data.wake_hooks.borrow_mut().push(Rc::new(hook));
}
}
impl ScopeData {
pub(super) fn tear_down(&self) {
let teardowns = std::mem::take(&mut *self.teardowns.borrow_mut());
for teardown in teardowns.into_iter().rev() {
teardown();
}
}
}
pub trait Teardown: 'static {
fn teardown(self);
}
impl Teardown for JoinHandle<()> {
fn teardown(self) {
self.abort();
}
}
impl<A: 'static> Teardown for Addr<A> {
fn teardown(self) {
self.dispose();
drop(self);
}
}
pub struct DropGuard<T: 'static>(pub T);
impl<T: 'static> Teardown for DropGuard<T> {
fn teardown(self) {
drop(self.0);
}
}