use std::fmt::{self, Debug, Display};
use std::future::{self, Future};
use crate::actor::{Actor, ActorContext, ActorState};
use crate::address::{Address, Recipient, SenderInfo};
use crate::message::{Handler, Message};
use crate::utils::{ShortName, debug_trace};
pub enum SupervisionEvent<A>
where
A: Actor,
{
Warn(Address<A>, A::Error),
Terminated(Address<A>, Option<A::Error>),
Panicked(Address<A>, String),
State(Address<A>, ActorState),
}
impl<A> Debug for SupervisionEvent<A>
where
A: Actor,
A::Error: Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SupervisionEvent::Warn(address, error) => f
.debug_tuple("Warn")
.field(&address.index())
.field(&error.to_string())
.finish(),
SupervisionEvent::Terminated(address, error) => f
.debug_tuple("Terminated")
.field(&address.index())
.field(&error.as_ref().map(|e| e.to_string()))
.finish(),
SupervisionEvent::Panicked(address, info) => f
.debug_tuple("Panicked")
.field(&address.index())
.field(info)
.finish(),
SupervisionEvent::State(address, state) => f
.debug_tuple("State")
.field(&address.index())
.field(state)
.finish(),
}
}
}
impl<A> Message for SupervisionEvent<A>
where
A: Actor,
{
type Result = ();
}
pub enum Supervisor<A>
where
A: Actor,
{
Set(Recipient<SupervisionEvent<A>>),
Unset,
}
impl<A> Debug for Supervisor<A>
where
A: Actor,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Supervisor::Set(recipient) => f
.debug_tuple(&format!("{}::Set", ShortName::of::<Self>()))
.field(&recipient.index())
.finish(),
Supervisor::Unset => f
.debug_tuple(&format!("{}::Unset", ShortName::of::<Self>()))
.finish(),
}
}
}
impl<A> Message for Supervisor<A>
where
A: Actor,
{
type Result = ();
}
impl<A> Handler<Supervisor<A>> for A
where
A: Actor,
A::Context: ActorContext<A>,
{
type Result = ();
fn handle(
&mut self,
msg: Supervisor<A>,
ctx: &mut Self::Context,
) -> impl Future<Output = Self::Result> + Send {
debug_trace!("Handle command {:?}", msg);
match msg {
Supervisor::Set(recipient) => {
ctx.set_supervisor(Some(recipient));
}
Supervisor::Unset => {
ctx.set_supervisor(None);
}
}
future::ready(())
}
}
#[cfg(feature = "identifier")]
impl<A> crate::stable_type_id::StableId for Supervisor<A>
where
A: Actor + crate::stable_type_id::StableId,
{
const TYPE_ID: crate::stable_type_id::StableTypeId =
crate::stable_type_id::StableTypeId::from_stable_type_name(concat!(
module_path!(),
"::",
"Supervisor"
))
.combine(A::TYPE_ID.as_bytes());
}
#[cfg(feature = "identifier")]
impl<A> crate::stable_type_id::StableId for SupervisionEvent<A>
where
A: Actor + crate::stable_type_id::StableId,
{
const TYPE_ID: crate::stable_type_id::StableTypeId =
crate::stable_type_id::StableTypeId::from_stable_type_name(concat!(
module_path!(),
"::",
"SupervisionEvent"
))
.combine(A::TYPE_ID.as_bytes());
}
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use super::*;
use crate::channel::mpsc;
use crate::envelope::Envelope;
use crate::test_utils::{Dummy, TestError};
#[test]
fn test_debug_fmt() {
let (tx, _rx) = mpsc::channel::<Envelope<Dummy>>(1);
let address = Address::new(tx);
let index = address.index();
let event: SupervisionEvent<Dummy> =
SupervisionEvent::Warn(address.clone(), TestError::from("oops"));
assert_eq!(format!("{:?}", event), format!("Warn({}, \"oops\")", index));
let event: SupervisionEvent<Dummy> = SupervisionEvent::Terminated(address.clone(), None);
assert_eq!(
format!("{:?}", event),
format!("Terminated({}, None)", index)
);
let event: SupervisionEvent<Dummy> =
SupervisionEvent::Terminated(address.clone(), Some(TestError::from("boom")));
assert_eq!(
format!("{:?}", event),
format!("Terminated({}, Some(\"boom\"))", index)
);
let event: SupervisionEvent<Dummy> =
SupervisionEvent::Panicked(address.clone(), "panicked!".to_string());
assert_eq!(
format!("{:?}", event),
format!("Panicked({}, \"panicked!\")", index)
);
let event: SupervisionEvent<Dummy> =
SupervisionEvent::State(address.clone(), ActorState::Running);
assert_eq!(format!("{:?}", event), format!("State({}, Running)", index));
let (recipient, _rx) = Recipient::<SupervisionEvent<Dummy>>::create(1);
let recipient_index = recipient.index();
let cmd: Supervisor<Dummy> = Supervisor::Set(recipient);
assert_eq!(
format!("{:?}", cmd),
format!("Supervisor<Dummy>::Set({})", recipient_index)
);
let cmd: Supervisor<Dummy> = Supervisor::Unset;
assert_eq!(format!("{:?}", cmd), "Supervisor<Dummy>::Unset");
}
}