use crate::behavior::{Actions, Address, Behavior, BirthMode, SendAlgebra, User, UserEvent};
use crate::protocol::ShutdownRequested;
use crate::protocol::forward::forward_event_lane;
use crate::{Exit, Step};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ShutdownProtocol<E> {
Behavior(E),
ShutdownRequested(ShutdownRequested),
}
impl<E: UserEvent> crate::RouteInput<ShutdownRequested> for ShutdownProtocol<E> {
fn route(event: ShutdownRequested) -> Result<Self, ShutdownRequested> {
Ok(Self::ShutdownRequested(event))
}
}
impl<E: UserEvent> crate::EventInput<ShutdownRequested> for ShutdownProtocol<E> {
fn inject(event: ShutdownRequested) -> Self {
Self::ShutdownRequested(event)
}
}
impl<E: UserEvent> UserEvent for ShutdownProtocol<E> {
type Addr = E::Addr;
type Message = E::Message;
fn user(from: Self::Addr, message: Self::Message) -> Self {
Self::Behavior(E::user(from, message))
}
fn into_user(self) -> Result<User<Self::Addr, Self::Message>, Self> {
match self {
Self::Behavior(event) => event.into_user().map_err(Self::Behavior),
shutdown @ Self::ShutdownRequested(_) => Err(shutdown),
}
}
}
forward_event_lane!(ShutdownProtocol, crate::TimerElapsed);
forward_event_lane!(ShutdownProtocol, crate::PeerStopped<E::Addr>);
forward_event_lane!(ShutdownProtocol, crate::ChildStopped<E::Addr>);
forward_event_lane!(ShutdownProtocol, crate::WorkerStopped<E::Addr>);
forward_event_lane!(
ShutdownProtocol,
crate::CreationResolved<<E::Addr as crate::Address>::Nonce>
);
forward_event_lane!(
ShutdownProtocol,
crate::WorkerCreationResolved<<E::Addr as crate::Address>::Nonce>
);
pub struct StopOnShutdown<B> {
inner: B,
}
impl<B> StopOnShutdown<B> {
#[must_use]
pub(crate) fn new(inner: B) -> Self {
Self { inner }
}
}
impl<B: Behavior + crate::BehaviorBase> crate::BehaviorBase for StopOnShutdown<B> {
type Base = B::Base;
fn base(&self) -> &Self::Base {
self.inner.base()
}
}
impl<B: crate::StashStatus> crate::StashStatus for StopOnShutdown<B> {
fn stashed_messages(&self) -> usize {
self.inner.stashed_messages()
}
}
pub type ShutdownReaction<B> = fn(
&mut B,
ShutdownRequested,
) -> Result<
Actions<
<B as Behavior>::Addr,
<B as Behavior>::Ph,
<B as Behavior>::Sends,
<B as Behavior>::Birth,
>,
<B as Behavior>::Error,
>;
pub struct FinalizeOnShutdown<B: Behavior> {
inner: B,
finalize: ShutdownReaction<B>,
}
impl<B: Behavior> FinalizeOnShutdown<B> {
#[must_use]
pub(crate) fn new(inner: B, finalize: ShutdownReaction<B>) -> Self {
Self { inner, finalize }
}
}
impl<B: Behavior + crate::BehaviorBase> crate::BehaviorBase for FinalizeOnShutdown<B> {
type Base = B::Base;
fn base(&self) -> &Self::Base {
self.inner.base()
}
}
impl<B> crate::StashStatus for FinalizeOnShutdown<B>
where
B: Behavior + crate::StashStatus,
{
fn stashed_messages(&self) -> usize {
self.inner.stashed_messages()
}
}
macro_rules! impl_shutdown_behavior {
($wrapper:ident, $shutdown:expr) => {
impl<B, A, Ph, Sends, Br> Behavior for $wrapper<B>
where
A: Address,
Sends: SendAlgebra,
Br: BirthMode,
B: Behavior<Addr = A, Ph = Ph, Sends = Sends, Birth = Br>,
{
type Addr = A;
type Msg = B::Msg;
type Event = ShutdownProtocol<B::Event>;
type Sends = Sends;
type Ph = Ph;
type Error = B::Error;
type Birth = Br;
fn init(
&mut self,
_: crate::InitializationTurn,
) -> Result<Actions<A, Ph, Sends, Br>, B::Error> {
crate::calculus::initialize(&mut self.inner)
}
fn transition(
&mut self,
_: crate::ActiveTurn,
event: Self::Event,
) -> Result<Actions<A, Ph, Sends, Br>, B::Error> {
match event {
ShutdownProtocol::Behavior(event) => {
crate::calculus::delegate_transition(&mut self.inner, event)
}
ShutdownProtocol::ShutdownRequested(request) => $shutdown(self, request),
}
}
}
};
}
impl_shutdown_behavior!(StopOnShutdown, |_this: &mut StopOnShutdown<B>, _request| {
Ok(Actions::stop(Exit::Normal))
});
impl_shutdown_behavior!(
FinalizeOnShutdown,
|this: &mut FinalizeOnShutdown<B>, request| {
let actions = (this.finalize)(&mut this.inner, request)?;
Ok(actions.map_become(|_| Step::Stop(Exit::Normal)))
}
);