1use crate::behavior::{Actions, Address, Behavior, BirthMode, SendAlgebra, User, UserEvent};
9use crate::protocol::forward::forward_event_lane;
10use crate::protocol::{ShutdownEvent, ShutdownRequested};
11use crate::{Exit, Step};
12
13#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum ShutdownProtocol<E> {
16 Inner(E),
17 ShutdownRequested(ShutdownRequested),
18}
19
20impl<E: UserEvent> ShutdownEvent for ShutdownProtocol<E> {
21 fn shutdown_requested(event: ShutdownRequested) -> Option<Self> {
22 Some(Self::ShutdownRequested(event))
23 }
24}
25
26impl<E: UserEvent> crate::EventInput<ShutdownRequested> for ShutdownProtocol<E> {
27 fn inject(event: ShutdownRequested) -> Self {
28 Self::ShutdownRequested(event)
29 }
30}
31
32impl<E: UserEvent> UserEvent for ShutdownProtocol<E> {
33 type Addr = E::Addr;
34 type Message = E::Message;
35
36 fn user(from: Self::Addr, message: Self::Message) -> Self {
37 Self::Inner(E::user(from, message))
38 }
39
40 fn into_user(self) -> Result<User<Self::Addr, Self::Message>, Self> {
41 match self {
42 Self::Inner(event) => event.into_user().map_err(Self::Inner),
43 shutdown @ Self::ShutdownRequested(_) => Err(shutdown),
44 }
45 }
46}
47
48forward_event_lane!(
49 ShutdownProtocol,
50 TimeEvent,
51 time_reached,
52 crate::TimerElapsed
53);
54forward_event_lane!(
55 ShutdownProtocol,
56 PeerEvent,
57 peer_stopped,
58 crate::PeerStopped<E::Addr>
59);
60forward_event_lane!(
61 ShutdownProtocol,
62 ChildEvent,
63 child_stopped,
64 crate::ChildStopped<E::Addr>
65);
66forward_event_lane!(
67 ShutdownProtocol,
68 WorkerEvent,
69 worker_stopped,
70 crate::WorkerStopped<E::Addr>
71);
72forward_event_lane!(
73 ShutdownProtocol,
74 CreationEvent,
75 creation_resolved,
76 crate::CreationResolved<<E::Addr as crate::Address>::Nonce>
77);
78forward_event_lane!(
79 ShutdownProtocol,
80 WorkerCreationEvent,
81 worker_creation_resolved,
82 crate::WorkerCreationResolved<<E::Addr as crate::Address>::Nonce>
83);
84
85pub struct StopOnShutdown<B> {
87 inner: B,
88}
89
90impl<B> StopOnShutdown<B> {
91 #[must_use]
92 pub fn new(inner: B) -> Self {
93 Self { inner }
94 }
95
96 #[must_use]
97 pub fn inner(&self) -> &B {
98 &self.inner
99 }
100}
101
102pub type ShutdownReaction<B> = fn(
105 &mut B,
106 ShutdownRequested,
107) -> Result<
108 Actions<
109 <B as Behavior>::Addr,
110 <B as Behavior>::Ph,
111 <B as Behavior>::Sends,
112 <B as Behavior>::Birth,
113 >,
114 <B as Behavior>::Error,
115>;
116
117pub struct FinalizeOnShutdown<B: Behavior> {
119 inner: B,
120 finalize: ShutdownReaction<B>,
121}
122
123impl<B: Behavior> FinalizeOnShutdown<B> {
124 #[must_use]
125 pub fn new(inner: B, finalize: ShutdownReaction<B>) -> Self {
126 Self { inner, finalize }
127 }
128
129 #[must_use]
130 pub fn inner(&self) -> &B {
131 &self.inner
132 }
133}
134
135macro_rules! impl_shutdown_behavior {
136 ($wrapper:ident, $shutdown:expr) => {
137 impl<B, A, Ph, Sends, Br> Behavior for $wrapper<B>
138 where
139 A: Address,
140 Sends: SendAlgebra,
141 Br: BirthMode,
142 B: Behavior<Addr = A, Ph = Ph, Sends = Sends, Birth = Br>,
143 {
144 type Addr = A;
145 type Msg = B::Msg;
146 type Event = ShutdownProtocol<B::Event>;
147 type Sends = Sends;
148 type Ph = Ph;
149 type Error = B::Error;
150 type Birth = Br;
151
152 fn init(&mut self) -> Result<Actions<A, Ph, Sends, Br>, B::Error> {
153 self.inner.init()
154 }
155
156 fn transition(
157 &mut self,
158 event: Self::Event,
159 ) -> Result<Actions<A, Ph, Sends, Br>, B::Error> {
160 match event {
161 ShutdownProtocol::Inner(event) => self.inner.transition(event),
162 ShutdownProtocol::ShutdownRequested(request) => $shutdown(self, request),
163 }
164 }
165 }
166 };
167}
168
169impl_shutdown_behavior!(StopOnShutdown, |_this: &mut StopOnShutdown<B>, _request| {
170 Ok(Actions::stop(Exit::Normal))
171});
172
173impl_shutdown_behavior!(
174 FinalizeOnShutdown,
175 |this: &mut FinalizeOnShutdown<B>, request| {
176 let actions = (this.finalize)(&mut this.inner, request)?;
177 Ok(actions.map_become(|_| Step::Stop(Exit::Normal)))
178 }
179);