1pub(crate) mod forward;
8
9use std::time::Duration;
10
11use std::time::Instant;
12
13use crate::behavior::Address;
14use crate::{Crash, CreationKind, Exit};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17pub struct TimerId(pub u64);
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
20pub struct TimerGeneration(pub u64);
21
22impl From<u64> for TimerId {
23 fn from(value: u64) -> Self {
24 Self(value)
25 }
26}
27
28impl From<TimerId> for u64 {
29 fn from(value: TimerId) -> Self {
30 value.0
31 }
32}
33
34impl From<u64> for TimerGeneration {
35 fn from(value: u64) -> Self {
36 Self(value)
37 }
38}
39
40impl From<TimerGeneration> for u64 {
41 fn from(value: TimerGeneration) -> Self {
42 value.0
43 }
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47pub struct ScheduleAt {
48 pub id: TimerId,
49 pub generation: TimerGeneration,
50 pub at: Instant,
51}
52
53impl ScheduleAt {
54 #[must_use]
55 pub const fn new(id: TimerId, generation: TimerGeneration, at: Instant) -> Self {
56 Self { id, generation, at }
57 }
58}
59
60impl From<(TimerId, TimerGeneration, Instant)> for ScheduleAt {
61 fn from((id, generation, at): (TimerId, TimerGeneration, Instant)) -> Self {
62 Self::new(id, generation, at)
63 }
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq)]
72pub struct ScheduleAfter {
73 pub id: TimerId,
74 pub generation: TimerGeneration,
75 pub after: Duration,
76}
77
78impl ScheduleAfter {
79 #[must_use]
80 pub const fn new(id: TimerId, generation: TimerGeneration, after: Duration) -> Self {
81 Self {
82 id,
83 generation,
84 after,
85 }
86 }
87}
88
89impl From<(TimerId, TimerGeneration, Duration)> for ScheduleAfter {
90 fn from((id, generation, after): (TimerId, TimerGeneration, Duration)) -> Self {
91 Self::new(id, generation, after)
92 }
93}
94
95#[derive(Debug, Clone, Copy, PartialEq, Eq)]
96pub struct TimerElapsed {
97 pub id: TimerId,
98 pub generation: TimerGeneration,
99}
100
101impl TimerElapsed {
102 #[must_use]
103 pub const fn new(id: TimerId, generation: TimerGeneration) -> Self {
104 Self { id, generation }
105 }
106}
107
108impl From<(TimerId, TimerGeneration)> for TimerElapsed {
109 fn from((id, generation): (TimerId, TimerGeneration)) -> Self {
110 Self::new(id, generation)
111 }
112}
113
114#[derive(Debug, Clone, Copy, PartialEq, Eq)]
125pub struct ObservePeer<A> {
126 pub peer: A,
127}
128
129impl<A> From<A> for ObservePeer<A> {
130 fn from(peer: A) -> Self {
131 Self { peer }
132 }
133}
134
135impl<A> ObservePeer<A> {
136 #[must_use]
137 pub const fn new(peer: A) -> Self {
138 Self { peer }
139 }
140}
141
142#[derive(Debug, Clone, Copy, PartialEq, Eq)]
151pub struct UnwatchPeer<A> {
152 pub peer: A,
153}
154
155impl<A> UnwatchPeer<A> {
156 #[must_use]
157 pub const fn new(peer: A) -> Self {
158 Self { peer }
159 }
160}
161
162impl<A> From<A> for UnwatchPeer<A> {
163 fn from(peer: A) -> Self {
164 Self::new(peer)
165 }
166}
167
168#[derive(Debug, Clone, PartialEq, Eq)]
169pub struct PeerStopped<A: Address> {
170 pub peer: A,
171 pub outcome: Result<Exit<A>, Crash>,
172}
173
174impl<A: Address> PeerStopped<A> {
175 #[must_use]
176 pub fn new(peer: A, outcome: Result<Exit<A>, Crash>) -> Self {
177 Self { peer, outcome }
178 }
179}
180
181#[derive(Debug, Clone, PartialEq, Eq)]
182pub struct ChildStopped<A: Address> {
183 pub nonce: A::Nonce,
184 pub outcome: Result<Exit<A>, Crash>,
185 pub at: Instant,
186}
187
188impl<A: Address> ChildStopped<A> {
189 #[must_use]
190 pub fn new(nonce: A::Nonce, outcome: Result<Exit<A>, Crash>, at: Instant) -> Self {
191 Self { nonce, outcome, at }
192 }
193}
194
195#[derive(Debug, Clone, Copy, PartialEq, Eq)]
204pub struct ObserveChild<N> {
205 pub nonce: N,
206}
207
208impl<N> ObserveChild<N> {
209 #[must_use]
210 pub const fn new(nonce: N) -> Self {
211 Self { nonce }
212 }
213}
214
215#[derive(Debug, Clone, PartialEq, Eq)]
219pub struct ReportWorkerStopped<A: Address> {
220 pub worker: A::Nonce,
221 pub outcome: Result<Exit<A>, Crash>,
222 pub at: Instant,
223}
224
225impl<A: Address> ReportWorkerStopped<A> {
226 #[must_use]
227 pub fn new(worker: A::Nonce, outcome: Result<Exit<A>, Crash>, at: Instant) -> Self {
228 Self {
229 worker,
230 outcome,
231 at,
232 }
233 }
234}
235
236impl<A: Address> From<ChildStopped<A>> for ReportWorkerStopped<A> {
237 fn from(stopped: ChildStopped<A>) -> Self {
238 Self::new(stopped.nonce, stopped.outcome, stopped.at)
239 }
240}
241
242#[derive(Debug, Clone, PartialEq, Eq)]
244pub struct WorkerStopped<A: Address> {
245 pub proxy: A::Nonce,
246 pub worker: A::Nonce,
247 pub outcome: Result<Exit<A>, Crash>,
248 pub at: Instant,
249}
250
251impl<A: Address> WorkerStopped<A> {
252 #[must_use]
253 pub fn new(
254 proxy: A::Nonce,
255 worker: A::Nonce,
256 outcome: Result<Exit<A>, Crash>,
257 at: Instant,
258 ) -> Self {
259 Self {
260 proxy,
261 worker,
262 outcome,
263 at,
264 }
265 }
266}
267
268impl<A: Address> From<(A::Nonce, ReportWorkerStopped<A>)> for WorkerStopped<A> {
269 fn from((proxy, stopped): (A::Nonce, ReportWorkerStopped<A>)) -> Self {
270 Self::new(proxy, stopped.worker, stopped.outcome, stopped.at)
271 }
272}
273
274#[derive(Debug, Clone, Copy, PartialEq, Eq)]
279pub enum CreationRejection {
280 NonceAlreadyBound,
283 InitializationFailed,
285 EnvironmentFailed,
287}
288
289#[derive(Debug, Clone, Copy, PartialEq, Eq)]
296pub struct CreationResolved<N> {
297 pub nonce: N,
298 pub kind: CreationKind<N>,
299 pub result: Result<(), CreationRejection>,
300}
301
302impl<N> CreationResolved<N> {
303 #[must_use]
304 pub const fn new(
305 nonce: N,
306 kind: CreationKind<N>,
307 result: Result<(), CreationRejection>,
308 ) -> Self {
309 Self {
310 nonce,
311 kind,
312 result,
313 }
314 }
315
316 #[must_use]
317 pub const fn installed(nonce: N, kind: CreationKind<N>) -> Self {
318 Self::new(nonce, kind, Ok(()))
319 }
320
321 #[must_use]
323 pub const fn birth(nonce: N) -> Self {
324 Self::installed(nonce, CreationKind::Birth)
325 }
326
327 #[must_use]
329 pub const fn replacement_incarnation(nonce: N, replaces: N) -> Self {
330 Self::installed(nonce, CreationKind::ReplacementIncarnation { replaces })
331 }
332
333 #[must_use]
334 pub const fn rejected(nonce: N, kind: CreationKind<N>, rejection: CreationRejection) -> Self {
335 Self::new(nonce, kind, Err(rejection))
336 }
337}
338
339#[derive(Debug, Clone, Copy, PartialEq, Eq)]
342pub struct ObserveCreation<N> {
343 pub nonce: N,
344}
345
346impl<N> ObserveCreation<N> {
347 #[must_use]
348 pub const fn new(nonce: N) -> Self {
349 Self { nonce }
350 }
351}
352
353#[derive(Debug, Clone, Copy, PartialEq, Eq)]
356pub struct ReportWorkerCreationResolved<N> {
357 pub worker: N,
358 pub kind: CreationKind<N>,
359 pub result: Result<(), CreationRejection>,
360}
361
362impl<N> ReportWorkerCreationResolved<N> {
363 #[must_use]
364 pub const fn new(
365 worker: N,
366 kind: CreationKind<N>,
367 result: Result<(), CreationRejection>,
368 ) -> Self {
369 Self {
370 worker,
371 kind,
372 result,
373 }
374 }
375}
376
377impl<N> From<CreationResolved<N>> for ReportWorkerCreationResolved<N> {
378 fn from(resolved: CreationResolved<N>) -> Self {
379 Self::new(resolved.nonce, resolved.kind, resolved.result)
380 }
381}
382
383#[derive(Debug, Clone, Copy, PartialEq, Eq)]
385pub struct WorkerCreationResolved<N> {
386 pub proxy: N,
387 pub worker: N,
388 pub kind: CreationKind<N>,
389 pub result: Result<(), CreationRejection>,
390}
391
392#[derive(Debug, Clone, Copy, PartialEq, Eq)]
401pub enum ReplacementResolution<N> {
402 Installed {
403 proxy: N,
404 replaced: N,
405 replacement: N,
406 },
407 Rejected {
408 proxy: N,
409 replaced: N,
410 attempt: N,
411 rejection: CreationRejection,
412 },
413}
414
415impl<N> WorkerCreationResolved<N> {
416 #[must_use]
417 pub const fn new(
418 proxy: N,
419 worker: N,
420 kind: CreationKind<N>,
421 result: Result<(), CreationRejection>,
422 ) -> Self {
423 Self {
424 proxy,
425 worker,
426 kind,
427 result,
428 }
429 }
430
431 #[must_use]
434 pub fn into_replacement(self) -> Option<ReplacementResolution<N>> {
435 let CreationKind::ReplacementIncarnation { replaces } = self.kind else {
436 return None;
437 };
438 Some(match self.result {
439 Ok(()) => ReplacementResolution::Installed {
440 proxy: self.proxy,
441 replaced: replaces,
442 replacement: self.worker,
443 },
444 Err(rejection) => ReplacementResolution::Rejected {
445 proxy: self.proxy,
446 replaced: replaces,
447 attempt: self.worker,
448 rejection,
449 },
450 })
451 }
452}
453
454impl<N> From<(N, ReportWorkerCreationResolved<N>)> for WorkerCreationResolved<N> {
455 fn from((proxy, resolved): (N, ReportWorkerCreationResolved<N>)) -> Self {
456 Self::new(proxy, resolved.worker, resolved.kind, resolved.result)
457 }
458}
459
460#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
462pub struct ShutdownRequested;
463
464#[cfg(test)]
465mod tests {
466 use super::*;
467 use crate::MailAddr;
468
469 #[test]
470 fn lifecycle_conversions_preserve_every_semantic_field() {
471 let at = Instant::now();
472 let child = ChildStopped::<MailAddr>::new(3, Err(Crash::Failed), at);
473 let report = ReportWorkerStopped::from(child);
474 let worker = WorkerStopped::from((7, report));
475 assert_eq!(worker.proxy, 7);
476 assert_eq!(worker.worker, 3);
477 assert_eq!(worker.outcome, Err(Crash::Failed));
478 assert_eq!(worker.at, at);
479
480 let creation = CreationResolved::<u64>::rejected(
481 4,
482 CreationKind::replacement_of(3),
483 CreationRejection::EnvironmentFailed,
484 );
485 let report = ReportWorkerCreationResolved::from(creation);
486 let worker = WorkerCreationResolved::from((7, report));
487 assert_eq!(worker.proxy, 7);
488 assert_eq!(worker.worker, 4);
489 assert_eq!(worker.kind, CreationKind::replacement_of(3));
490 assert_eq!(worker.result, Err(CreationRejection::EnvironmentFailed));
491 assert_eq!(
492 worker.into_replacement(),
493 Some(ReplacementResolution::Rejected {
494 proxy: 7,
495 replaced: 3,
496 attempt: 4,
497 rejection: CreationRejection::EnvironmentFailed,
498 })
499 );
500
501 let installed = WorkerCreationResolved::new(7, 5, CreationKind::replacement_of(4), Ok(()));
502 assert_eq!(
503 installed.into_replacement(),
504 Some(ReplacementResolution::Installed {
505 proxy: 7,
506 replaced: 4,
507 replacement: 5,
508 })
509 );
510 assert_eq!(
511 WorkerCreationResolved::new(7, 0, CreationKind::Birth, Ok(())).into_replacement(),
512 None
513 );
514 assert_eq!(
515 WorkerCreationResolved::new(
516 7,
517 0,
518 CreationKind::Birth,
519 Err(CreationRejection::NonceAlreadyBound),
520 )
521 .into_replacement(),
522 None
523 );
524 }
525
526 #[test]
527 fn timer_newtypes_and_requests_have_lossless_construction() {
528 let id = TimerId::from(2);
529 let generation = TimerGeneration::from(5);
530 assert_eq!(u64::from(id), 2);
531 assert_eq!(u64::from(generation), 5);
532 assert_eq!(
533 TimerElapsed::from((id, generation)),
534 TimerElapsed::new(id, generation)
535 );
536 }
537}