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