1use core::convert::Infallible;
4use core::num::NonZeroU64;
5
6use behavior::{
7 Behavior, BehaviorAddr, Delivery, EndpointAddress, EstablishedActor, EstablishedDelivery,
8 EstablishedRecipient, NoSends, Protocol, Recipient, SendEffects,
9};
10
11use crate::atomic::RoleName;
12use crate::{ChildStopped, DeliveryRoute, ProxyPhase, ReplyDeliveries, ReplyRoute, StableProxy};
13
14use super::ActivationPlan;
15use super::WorkerUnavailable;
16
17mod sealed {
18 pub trait FixedLifecycleRoute<Role, Worker, Plan> {}
19}
20
21enum FixedLifecycleChange<Worker, Plan>
22where
23 Worker: Behavior,
24 Plan: ActivationPlan,
25 BehaviorAddr<Worker>: EndpointAddress,
26 StableProxy<Worker, Plan>: Behavior<Protocol = Worker::Protocol>,
27{
28 Started {
29 proxy: EstablishedActor<StableProxy<Worker, Plan>>,
30 },
31 Restarted {
32 proxy: EstablishedActor<StableProxy<Worker, Plan>>,
33 recovery: NonZeroU64,
34 },
35 WorkerStoppedIneligible {
36 stopped: ChildStopped<BehaviorAddr<Worker>>,
37 },
38 WorkerStoppedAfterAdmission {
39 stopped: ChildStopped<BehaviorAddr<Worker>>,
40 recovery: NonZeroU64,
41 },
42 Unavailable {
43 sender: BehaviorAddr<Worker>,
44 phase: ProxyPhase,
45 command: <Worker::Protocol as Protocol>::Msg,
46 },
47 MemberRetired,
48}
49
50pub struct FixedLifecycle<Role, Worker, Plan>
56where
57 Worker: Behavior,
58 Plan: ActivationPlan,
59 BehaviorAddr<Worker>: EndpointAddress,
60 StableProxy<Worker, Plan>: Behavior<Protocol = Worker::Protocol>,
61{
62 role: RoleName<Role>,
63 change: FixedLifecycleChange<Worker, Plan>,
64}
65
66pub enum FixedLifecycleEvent<'a, Role, Worker, Plan>
68where
69 Worker: Behavior,
70 Plan: ActivationPlan,
71 BehaviorAddr<Worker>: EndpointAddress,
72 StableProxy<Worker, Plan>: Behavior<Protocol = Worker::Protocol>,
73{
74 Started {
76 role: &'a Role,
77 proxy: &'a EstablishedActor<StableProxy<Worker, Plan>>,
78 },
79 Restarted {
81 role: &'a Role,
82 proxy: &'a EstablishedActor<StableProxy<Worker, Plan>>,
83 recovery: NonZeroU64,
84 },
85 WorkerStoppedIneligible {
87 role: &'a Role,
88 stopped: &'a ChildStopped<BehaviorAddr<Worker>>,
89 },
90 WorkerStoppedAfterAdmission {
92 role: &'a Role,
93 stopped: &'a ChildStopped<BehaviorAddr<Worker>>,
94 recovery: NonZeroU64,
95 },
96 Unavailable {
98 role: &'a Role,
99 sender: &'a BehaviorAddr<Worker>,
100 phase: ProxyPhase,
101 command: &'a <Worker::Protocol as Protocol>::Msg,
102 },
103 MemberRetired { role: &'a Role },
105}
106
107impl<Role, Worker, Plan> FixedLifecycle<Role, Worker, Plan>
108where
109 Worker: Behavior,
110 Plan: ActivationPlan,
111 BehaviorAddr<Worker>: EndpointAddress,
112 StableProxy<Worker, Plan>: Behavior<Protocol = Worker::Protocol>,
113{
114 pub(super) const fn started(
115 role: RoleName<Role>,
116 proxy: EstablishedActor<StableProxy<Worker, Plan>>,
117 ) -> Self {
118 Self {
119 role,
120 change: FixedLifecycleChange::Started { proxy },
121 }
122 }
123
124 pub(super) const fn restarted(
125 role: RoleName<Role>,
126 proxy: EstablishedActor<StableProxy<Worker, Plan>>,
127 recovery: NonZeroU64,
128 ) -> Self {
129 Self {
130 role,
131 change: FixedLifecycleChange::Restarted { proxy, recovery },
132 }
133 }
134
135 pub(super) const fn worker_stopped_ineligible(
136 role: RoleName<Role>,
137 stopped: ChildStopped<BehaviorAddr<Worker>>,
138 ) -> Self {
139 Self {
140 role,
141 change: FixedLifecycleChange::WorkerStoppedIneligible { stopped },
142 }
143 }
144
145 pub(super) const fn worker_stopped_after_admission(
146 role: RoleName<Role>,
147 stopped: ChildStopped<BehaviorAddr<Worker>>,
148 recovery: NonZeroU64,
149 ) -> Self {
150 Self {
151 role,
152 change: FixedLifecycleChange::WorkerStoppedAfterAdmission { stopped, recovery },
153 }
154 }
155
156 pub(super) fn unavailable(unavailable: WorkerUnavailable<Role, Worker>) -> Self {
157 let (role, sender, phase, command) = unavailable.into_parts();
158 Self {
159 role,
160 change: FixedLifecycleChange::Unavailable {
161 sender,
162 phase,
163 command,
164 },
165 }
166 }
167
168 pub(super) const fn member_retired(role: RoleName<Role>) -> Self {
169 Self {
170 role,
171 change: FixedLifecycleChange::MemberRetired,
172 }
173 }
174
175 #[must_use]
178 pub fn event(&self) -> FixedLifecycleEvent<'_, Role, Worker, Plan> {
179 let role = self.role.role();
180 match &self.change {
181 FixedLifecycleChange::Started { proxy } => FixedLifecycleEvent::Started { role, proxy },
182 FixedLifecycleChange::Restarted { proxy, recovery } => FixedLifecycleEvent::Restarted {
183 role,
184 proxy,
185 recovery: *recovery,
186 },
187 FixedLifecycleChange::WorkerStoppedIneligible { stopped } => {
188 FixedLifecycleEvent::WorkerStoppedIneligible { role, stopped }
189 }
190 FixedLifecycleChange::WorkerStoppedAfterAdmission { stopped, recovery } => {
191 FixedLifecycleEvent::WorkerStoppedAfterAdmission {
192 role,
193 stopped,
194 recovery: *recovery,
195 }
196 }
197 FixedLifecycleChange::Unavailable {
198 sender,
199 phase,
200 command,
201 } => FixedLifecycleEvent::Unavailable {
202 role,
203 sender,
204 phase: *phase,
205 command,
206 },
207 FixedLifecycleChange::MemberRetired => FixedLifecycleEvent::MemberRetired { role },
208 }
209 }
210}
211
212#[doc(hidden)]
214pub trait FixedLifecycleRoute<Role, Worker, Plan>:
215 sealed::FixedLifecycleRoute<Role, Worker, Plan> + Sized
216where
217 Worker: Behavior,
218 Plan: ActivationPlan,
219 BehaviorAddr<Worker>: EndpointAddress,
220 StableProxy<Worker, Plan>: Behavior<Protocol = Worker::Protocol>,
221{
222 type Sends: SendEffects;
223
224 fn deliver(self, lifecycle: FixedLifecycle<Role, Worker, Plan>) -> Self::Sends;
225}
226
227impl<Role, Worker, Plan> sealed::FixedLifecycleRoute<Role, Worker, Plan> for Infallible
228where
229 Worker: Behavior,
230 Plan: ActivationPlan,
231 BehaviorAddr<Worker>: EndpointAddress,
232 StableProxy<Worker, Plan>: Behavior<Protocol = Worker::Protocol>,
233{
234}
235
236impl<Role, Worker, Plan> FixedLifecycleRoute<Role, Worker, Plan> for Infallible
237where
238 Worker: Behavior,
239 Plan: ActivationPlan,
240 BehaviorAddr<Worker>: EndpointAddress,
241 StableProxy<Worker, Plan>: Behavior<Protocol = Worker::Protocol>,
242{
243 type Sends = NoSends;
244
245 fn deliver(self, _: FixedLifecycle<Role, Worker, Plan>) -> Self::Sends {
246 match self {}
247 }
248}
249
250impl<Role, Worker, Plan, P> sealed::FixedLifecycleRoute<Role, Worker, Plan> for Recipient<P>
251where
252 Worker: Behavior,
253 Plan: ActivationPlan,
254 BehaviorAddr<Worker>: EndpointAddress,
255 StableProxy<Worker, Plan>: Behavior<Protocol = Worker::Protocol>,
256 P: Protocol<Addr = BehaviorAddr<Worker>, Msg = FixedLifecycle<Role, Worker, Plan>>,
257{
258}
259
260impl<Role, Worker, Plan, P> FixedLifecycleRoute<Role, Worker, Plan> for Recipient<P>
261where
262 Worker: Behavior,
263 Plan: ActivationPlan,
264 BehaviorAddr<Worker>: EndpointAddress,
265 StableProxy<Worker, Plan>: Behavior<Protocol = Worker::Protocol>,
266 P: Protocol<Addr = BehaviorAddr<Worker>, Msg = FixedLifecycle<Role, Worker, Plan>>,
267{
268 type Sends = Vec<Delivery<P>>;
269
270 fn deliver(self, lifecycle: FixedLifecycle<Role, Worker, Plan>) -> Self::Sends {
271 DeliveryRoute::deliver(self, lifecycle)
272 }
273}
274
275impl<Role, Worker, Plan, P> sealed::FixedLifecycleRoute<Role, Worker, Plan>
276 for EstablishedRecipient<P>
277where
278 Worker: Behavior,
279 Plan: ActivationPlan,
280 BehaviorAddr<Worker>: EndpointAddress,
281 StableProxy<Worker, Plan>: Behavior<Protocol = Worker::Protocol>,
282 P: Protocol<Addr = BehaviorAddr<Worker>, Msg = FixedLifecycle<Role, Worker, Plan>>,
283{
284}
285
286impl<Role, Worker, Plan, P> FixedLifecycleRoute<Role, Worker, Plan> for EstablishedRecipient<P>
287where
288 Worker: Behavior,
289 Plan: ActivationPlan,
290 BehaviorAddr<Worker>: EndpointAddress,
291 StableProxy<Worker, Plan>: Behavior<Protocol = Worker::Protocol>,
292 P: Protocol<Addr = BehaviorAddr<Worker>, Msg = FixedLifecycle<Role, Worker, Plan>>,
293{
294 type Sends = Vec<EstablishedDelivery<P>>;
295
296 fn deliver(self, lifecycle: FixedLifecycle<Role, Worker, Plan>) -> Self::Sends {
297 DeliveryRoute::deliver(self, lifecycle)
298 }
299}
300
301impl<Role, Worker, Plan, P> sealed::FixedLifecycleRoute<Role, Worker, Plan> for ReplyRoute<P>
302where
303 Worker: Behavior,
304 Plan: ActivationPlan,
305 BehaviorAddr<Worker>: EndpointAddress,
306 StableProxy<Worker, Plan>: Behavior<Protocol = Worker::Protocol>,
307 P: Protocol<Addr = BehaviorAddr<Worker>, Msg = FixedLifecycle<Role, Worker, Plan>>,
308{
309}
310
311impl<Role, Worker, Plan, P> FixedLifecycleRoute<Role, Worker, Plan> for ReplyRoute<P>
312where
313 Worker: Behavior,
314 Plan: ActivationPlan,
315 BehaviorAddr<Worker>: EndpointAddress,
316 StableProxy<Worker, Plan>: Behavior<Protocol = Worker::Protocol>,
317 P: Protocol<Addr = BehaviorAddr<Worker>, Msg = FixedLifecycle<Role, Worker, Plan>>,
318{
319 type Sends = ReplyDeliveries<Delivery<P>, EstablishedDelivery<P>>;
320
321 fn deliver(self, lifecycle: FixedLifecycle<Role, Worker, Plan>) -> Self::Sends {
322 DeliveryRoute::deliver(self, lifecycle)
323 }
324}