behavior/timing/
deadline.rs1use std::time::Instant;
5
6use super::domain::OneShotSchedule;
7use super::event::TimedEvent;
8use crate::Step;
9use crate::behavior::{Actions, Address, Become, Behavior, BirthMode, SendAlgebra, ServiceSends};
10use crate::protocol::{ScheduleAt, TimerElapsed, TimerId};
11use crate::{Own, RouteInput, SendInput};
12
13pub type DeadlineEvent<E> = TimedEvent<E>;
14
15pub type DeadlineReaction<B> =
16 fn(&mut B) -> Result<Become<<B as Behavior>::Addr>, <B as Behavior>::Error>;
17
18#[derive(Debug, Clone, PartialEq, Eq)]
20pub struct DeadlineSends<Sends> {
21 pub behavior: Sends,
22 pub schedules: ServiceSends<ScheduleAt>,
23}
24
25impl<Sends: SendAlgebra> SendAlgebra for DeadlineSends<Sends> {
26 fn empty() -> Self {
27 Self {
28 behavior: Sends::empty(),
29 schedules: ServiceSends::empty(),
30 }
31 }
32
33 fn append(&mut self, other: Self) {
34 self.behavior.append(other.behavior);
35 self.schedules.append(other.schedules);
36 }
37}
38
39impl<Sends> SendInput<ScheduleAt, Own> for DeadlineSends<Sends> {
40 fn emit(&mut self, input: ScheduleAt) {
41 self.schedules.send(input);
42 }
43}
44
45pub(crate) type DeadlineActions<B> = Actions<
46 <B as Behavior>::Addr,
47 <B as Behavior>::Ph,
48 DeadlineSends<<B as Behavior>::Sends>,
49 <B as Behavior>::Birth,
50>;
51
52pub struct Deadline<B: Behavior> {
53 inner: B,
54 schedule: OneShotSchedule,
55 on_reached: DeadlineReaction<B>,
56}
57
58impl<B: Behavior> Deadline<B> {
59 #[must_use]
60 pub(crate) fn new(
61 inner: B,
62 id: TimerId,
63 at: Option<Instant>,
64 on_reached: DeadlineReaction<B>,
65 ) -> Self {
66 Self {
67 inner,
68 schedule: OneShotSchedule::new(id, at),
69 on_reached,
70 }
71 }
72}
73
74impl<B: Behavior + crate::BehaviorBase> crate::BehaviorBase for Deadline<B> {
75 type Base = B::Base;
76
77 fn base(&self) -> &Self::Base {
78 self.inner.base()
79 }
80}
81
82impl<B> crate::StashStatus for Deadline<B>
83where
84 B: Behavior + crate::StashStatus,
85{
86 fn stashed_messages(&self) -> usize {
87 self.inner.stashed_messages()
88 }
89}
90
91impl<B, A, Ph, Sends, Br> Behavior for Deadline<B>
92where
93 A: Address,
94 Sends: SendAlgebra,
95 Br: BirthMode,
96 B: Behavior<Addr = A, Ph = Ph, Sends = Sends, Birth = Br>,
97 B::Event: crate::RouteInput<TimerElapsed>,
98{
99 type Addr = A;
100 type Msg = B::Msg;
101 type Event = DeadlineEvent<B::Event>;
102 type Sends = DeadlineSends<Sends>;
103 type Ph = Ph;
104 type Error = B::Error;
105 type Birth = Br;
106
107 fn init(&mut self, _: crate::InitializationTurn) -> Result<DeadlineActions<B>, B::Error> {
108 let actions = crate::calculus::initialize(&mut self.inner)?;
109 let own = if matches!(actions.become_, Step::Stop(_)) {
110 self.schedule.cancel();
111 ServiceSends::empty()
112 } else {
113 self.schedule
114 .request()
115 .map_or_else(ServiceSends::empty, |(id, generation, at)| {
116 ServiceSends::one(ScheduleAt::new(id, generation, at))
117 })
118 };
119 Ok(Self::wrap(actions, own))
120 }
121
122 fn transition(
123 &mut self,
124 _: crate::ActiveTurn,
125 event: Self::Event,
126 ) -> Result<DeadlineActions<B>, B::Error> {
127 match event {
128 DeadlineEvent::Elapsed(event) if self.schedule.accept(event.id, event.generation) => {
129 let become_ = match (self.on_reached)(&mut self.inner)? {
130 Step::Continue => Step::Continue,
131 Step::Goto(never) => match never {},
132 Step::Stop(exit) => Step::Stop(exit),
133 };
134 Ok(Actions::just(become_))
135 }
136 DeadlineEvent::Elapsed(event) => match B::Event::route(event) {
137 Ok(inner) => {
138 let actions = crate::calculus::delegate_transition(&mut self.inner, inner)?;
139 if matches!(actions.become_, Step::Stop(_)) {
140 self.schedule.cancel();
141 }
142 Ok(Self::wrap(actions, ServiceSends::empty()))
143 }
144 Err(_) => Ok(Actions::cont()),
145 },
146 DeadlineEvent::Behavior(event) => {
147 let actions = crate::calculus::delegate_transition(&mut self.inner, event)?;
148 if matches!(actions.become_, Step::Stop(_)) {
149 self.schedule.cancel();
150 }
151 Ok(Self::wrap(actions, ServiceSends::empty()))
152 }
153 }
154 }
155}
156
157impl<B: Behavior> Deadline<B> {
158 fn wrap(
159 actions: Actions<B::Addr, B::Ph, B::Sends, B::Birth>,
160 own: ServiceSends<ScheduleAt>,
161 ) -> DeadlineActions<B> {
162 actions.map_sends(|behavior| DeadlineSends {
163 behavior,
164 schedules: own,
165 })
166 }
167}