use std::sync::Weak;
use beamr::atom::Atom;
use beamr::native::native_process::{NativeContext, NativeHandler, NativeOutcome};
use beamr::process::ExitReason;
use beamr::term::Term;
use beamr::term::boxed::Tuple;
use crate::channel::actor::beam::ActorRuntime;
pub struct ChannelExitWatcher {
runtime: Weak<ActorRuntime>,
}
impl ChannelExitWatcher {
pub const fn new(runtime: Weak<ActorRuntime>) -> Self {
Self { runtime }
}
}
impl std::fmt::Debug for ChannelExitWatcher {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("ChannelExitWatcher")
.finish_non_exhaustive()
}
}
impl NativeHandler for ChannelExitWatcher {
fn handle(&mut self, ctx: &mut NativeContext<'_>) -> NativeOutcome {
let Some(runtime) = self.runtime.upgrade() else {
return NativeOutcome::Stop(ExitReason::Normal);
};
#[cfg(test)]
runtime.count_watcher_wake();
while let Some(message) = ctx.recv() {
if let Some(pid) = down_source(message) {
if let Err(error) = runtime.retire_exited(pid) {
tracing::error!(pid, %error, "channel actor exit could not retire its queue");
}
}
}
NativeOutcome::Wait
}
}
fn down_source(message: Term) -> Option<u64> {
let tuple = Tuple::new(message)?;
if tuple.arity() == 5 && tuple.get(0) == Some(Term::atom(Atom::DOWN)) {
tuple.get(3)?.as_pid()
} else {
None
}
}