use crate::actor::Addr;
use crate::actor::registry::{ActorSnapshot, Owner};
use crate::actor::traits::ManagedActor;
use crate::observability::changes::{self, Change};
use super::{Scope, Teardown};
pub(super) struct HeldActor {
id: usize,
type_name: &'static str,
shape: crate::actor::shape::Shape,
owner: Owner,
snapshot: Box<dyn Fn() -> String>,
}
impl HeldActor {
fn read(&self) -> ActorSnapshot {
ActorSnapshot {
id: self.id,
type_name: self.type_name,
shape: self.shape,
owner: self.owner,
state: (self.snapshot)(),
}
}
}
fn read_all(scopes: Vec<Scope>) -> Vec<ActorSnapshot> {
scopes
.into_iter()
.filter_map(|scope| scope.data())
.flat_map(|data| data.actors.borrow().iter().map(HeldActor::read).collect::<Vec<_>>())
.collect()
}
fn read_one(scopes: Vec<Scope>, id: usize) -> Option<ActorSnapshot> {
scopes.into_iter().filter_map(|scope| scope.data()).find_map(|data| {
data.actors
.borrow()
.iter()
.find(|actor| actor.id == id)
.map(HeldActor::read)
})
}
struct Unlisted {
root: Option<u64>,
id: usize,
}
impl Teardown for Unlisted {
fn teardown(self) {
changes::changed(|| Change::ActorRemoved {
root: self.root,
id: self.id,
});
}
}
impl Scope {
pub fn set_window(&self, id: u64) {
if let Some(data) = self.data() {
data.window.set(Some(id));
}
}
pub fn window(&self) -> Option<u64> {
std::iter::successors(Some(*self), Scope::parent)
.find_map(|scope| scope.data()?.window.get())
}
pub fn hold_actor<A: ManagedActor + std::fmt::Debug>(
&self,
addr: &Addr<A>,
feature: Option<&'static str>,
drives: Option<&'static str>,
) {
let Some(data) = self.data() else { return };
let id = addr.id();
let type_name = crate::actor::short_type_name::<A>();
let owner = Owner {
scope: Some(self.key()),
feature,
drives,
};
let held = addr.clone();
data.actors.borrow_mut().push(HeldActor {
id,
type_name,
shape: A::SHAPE,
owner,
snapshot: Box::new(move || held.debug_snapshot()),
});
drop(data);
let root = self.window();
changes::changed(|| Change::ActorAdded {
root,
id,
type_name,
owner,
});
self.own(Unlisted { root, id });
}
pub fn actors(&self) -> Vec<ActorSnapshot> {
read_all(self.subtree())
}
pub fn actor(&self, id: usize) -> Option<ActorSnapshot> {
read_one(self.subtree(), id)
}
pub fn actors_here(&self) -> Vec<ActorSnapshot> {
read_all(vec![*self])
}
pub fn actor_here(&self, id: usize) -> Option<ActorSnapshot> {
read_one(vec![*self], id)
}
}