1use std::time::Duration;
5
6use crate::Step;
7use crate::behavior::{
8 Actions, Address, Behavior, BirthMode, SendAlgebra, SendProduct, ServiceSends, UserEvent,
9};
10use crate::protocol::{
11 ChildEvent, ChildStopped, PeerEvent, PeerStopped, ScheduleAfter, ShutdownEvent,
12 ShutdownRequested, TimeEvent, TimerElapsed, TimerGeneration, TimerId, WorkerEvent,
13 WorkerStopped,
14};
15
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub enum ReceiveTimeoutEvent<E> {
18 Inner(E),
19 Elapsed(TimerElapsed),
20}
21
22impl<E> TimeEvent for ReceiveTimeoutEvent<E> {
23 fn time_reached(event: TimerElapsed) -> Option<Self> {
24 Some(Self::Elapsed(event))
25 }
26}
27
28impl<E: UserEvent> UserEvent for ReceiveTimeoutEvent<E> {
29 type Addr = E::Addr;
30 type Message = E::Message;
31
32 fn user(from: Self::Addr, message: Self::Message) -> Self {
33 Self::Inner(E::user(from, message))
34 }
35
36 fn into_user(self) -> Result<crate::User<Self::Addr, Self::Message>, Self> {
37 match self {
38 Self::Inner(event) => event.into_user().map_err(Self::Inner),
39 elapsed @ Self::Elapsed(_) => Err(elapsed),
40 }
41 }
42}
43
44impl<E: PeerEvent<A>, A: Address> PeerEvent<A> for ReceiveTimeoutEvent<E> {
45 fn peer_stopped(event: PeerStopped<A>) -> Option<Self> {
46 E::peer_stopped(event).map(Self::Inner)
47 }
48}
49
50impl<E: ChildEvent<A>, A: Address> ChildEvent<A> for ReceiveTimeoutEvent<E> {
51 fn child_stopped(event: ChildStopped<A>) -> Option<Self> {
52 E::child_stopped(event).map(Self::Inner)
53 }
54}
55
56impl<E: WorkerEvent<A>, A: Address> WorkerEvent<A> for ReceiveTimeoutEvent<E> {
57 fn worker_stopped(event: WorkerStopped<A>) -> Option<Self> {
58 E::worker_stopped(event).map(Self::Inner)
59 }
60}
61
62impl<E: ShutdownEvent> ShutdownEvent for ReceiveTimeoutEvent<E> {
63 fn shutdown_requested(event: ShutdownRequested) -> Option<Self> {
64 E::shutdown_requested(event).map(Self::Inner)
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq)]
70pub enum ReceiveTimeoutError<E> {
71 Inner(E),
73 GenerationExhausted,
80}
81
82pub type ReceiveTimeoutReaction<B> = fn(
83 &mut B,
84) -> Result<
85 Actions<
86 <B as Behavior>::Addr,
87 <B as Behavior>::Ph,
88 <B as Behavior>::Sends,
89 <B as Behavior>::Birth,
90 >,
91 <B as Behavior>::Error,
92>;
93
94pub type ReceiveTimeoutSends<B> = SendProduct<<B as Behavior>::Sends, ServiceSends<ScheduleAfter>>;
95
96pub type ReceiveTimeoutActions<B> = Actions<
97 <B as Behavior>::Addr,
98 <B as Behavior>::Ph,
99 ReceiveTimeoutSends<B>,
100 <B as Behavior>::Birth,
101>;
102
103pub struct ReceiveTimeout<B: Behavior> {
111 inner: B,
112 id: TimerId,
113 after: Duration,
114 live: Option<TimerGeneration>,
115 last_issued: Option<TimerGeneration>,
116 on_elapsed: ReceiveTimeoutReaction<B>,
117}
118
119impl<B: Behavior> ReceiveTimeout<B> {
120 #[must_use]
121 pub fn new(
122 inner: B,
123 id: TimerId,
124 after: Duration,
125 on_elapsed: ReceiveTimeoutReaction<B>,
126 ) -> Self {
127 Self {
128 inner,
129 id,
130 after,
131 live: None,
132 last_issued: None,
133 on_elapsed,
134 }
135 }
136
137 #[must_use]
138 pub fn inner(&self) -> &B {
139 &self.inner
140 }
141
142 fn schedule(&mut self) -> Result<ServiceSends<ScheduleAfter>, ReceiveTimeoutError<B::Error>> {
143 let generation = match self.last_issued {
144 None => TimerGeneration(0),
145 Some(TimerGeneration(generation)) => TimerGeneration(
146 generation
147 .checked_add(1)
148 .ok_or(ReceiveTimeoutError::GenerationExhausted)?,
149 ),
150 };
151 self.last_issued = Some(generation);
152 self.live = Some(generation);
153 Ok(ServiceSends::one(ScheduleAfter {
154 id: self.id,
155 generation,
156 after: self.after,
157 }))
158 }
159
160 fn wrap(
161 actions: Actions<B::Addr, B::Ph, B::Sends, B::Birth>,
162 own: ServiceSends<ScheduleAfter>,
163 ) -> ReceiveTimeoutActions<B> {
164 Actions {
165 sends: SendProduct {
166 inner: actions.sends,
167 own,
168 },
169 creates: actions.creates,
170 become_: actions.become_,
171 }
172 }
173
174 fn terminal(actions: &Actions<B::Addr, B::Ph, B::Sends, B::Birth>) -> bool {
175 matches!(actions.become_, Step::Stop(_))
176 }
177}
178
179impl<B, A, Ph, Sends, Br> Behavior for ReceiveTimeout<B>
180where
181 A: Address + Send,
182 Sends: SendAlgebra,
183 Br: BirthMode,
184 B: Behavior<Addr = A, Ph = Ph, Sends = Sends, Birth = Br> + Send,
185 B::Event: TimeEvent + Send,
186 B::Msg: Send,
187{
188 type Addr = A;
189 type Msg = B::Msg;
190 type Event = ReceiveTimeoutEvent<B::Event>;
191 type Sends = ReceiveTimeoutSends<B>;
192 type Ph = Ph;
193 type Error = ReceiveTimeoutError<B::Error>;
194 type Birth = Br;
195
196 async fn init(&mut self) -> Result<ReceiveTimeoutActions<B>, Self::Error> {
197 let actions = self
198 .inner
199 .init()
200 .await
201 .map_err(ReceiveTimeoutError::Inner)?;
202 let own = if Self::terminal(&actions) {
203 self.live = None;
204 ServiceSends::empty()
205 } else {
206 self.schedule()?
207 };
208 Ok(Self::wrap(actions, own))
209 }
210
211 async fn step(&mut self, event: Self::Event) -> Result<ReceiveTimeoutActions<B>, Self::Error> {
212 match event {
213 ReceiveTimeoutEvent::Elapsed(elapsed)
214 if elapsed.id == self.id && self.live == Some(elapsed.generation) =>
215 {
216 self.live = None;
217 let actions =
218 (self.on_elapsed)(&mut self.inner).map_err(ReceiveTimeoutError::Inner)?;
219 Ok(Self::wrap(actions, ServiceSends::empty()))
220 }
221 ReceiveTimeoutEvent::Elapsed(elapsed) if elapsed.id == self.id => Ok(Actions::cont()),
222 ReceiveTimeoutEvent::Elapsed(elapsed) => {
223 let Some(inner) = B::Event::time_reached(elapsed) else {
224 return Ok(Actions::cont());
225 };
226 let actions = self
227 .inner
228 .step(inner)
229 .await
230 .map_err(ReceiveTimeoutError::Inner)?;
231 if Self::terminal(&actions) {
232 self.live = None;
233 }
234 Ok(Self::wrap(actions, ServiceSends::empty()))
235 }
236 ReceiveTimeoutEvent::Inner(event) => match event.into_user() {
237 Ok(user) => {
238 let event = B::Event::user(user.from, user.message);
239 let actions = self
240 .inner
241 .step(event)
242 .await
243 .map_err(ReceiveTimeoutError::Inner)?;
244 let own = if Self::terminal(&actions) {
245 self.live = None;
246 ServiceSends::empty()
247 } else {
248 self.schedule()?
249 };
250 Ok(Self::wrap(actions, own))
251 }
252 Err(service) => {
253 let actions = self
254 .inner
255 .step(service)
256 .await
257 .map_err(ReceiveTimeoutError::Inner)?;
258 if Self::terminal(&actions) {
259 self.live = None;
260 }
261 Ok(Self::wrap(actions, ServiceSends::empty()))
262 }
263 },
264 }
265 }
266}
267
268#[cfg(test)]
269mod tests {
270 use super::*;
271 use crate::{Acted, Base, Delivery, MailAddr, Never, NoBirths, State, User};
272
273 struct Count(u8);
274
275 impl State for Count {
276 type Addr = MailAddr;
277 type Msg = ();
278
279 fn handle(
280 &mut self,
281 _from: MailAddr,
282 (): (),
283 ) -> Acted<MailAddr, Never, Vec<Delivery<MailAddr, Never>>, NoBirths, Never> {
284 self.0 += 1;
285 Ok(Actions::cont())
286 }
287 }
288
289 type Inner = Base<Count>;
290
291 fn elapsed(
292 _inner: &mut Inner,
293 ) -> Acted<MailAddr, Never, Vec<Delivery<MailAddr, Never>>, NoBirths, Never> {
294 Ok(Actions::cont())
295 }
296
297 #[tokio::test]
298 async fn exhaustion_follows_the_successful_inner_fold_without_emitting_its_actions() {
299 let mut timeout = ReceiveTimeout::new(
300 Base::new(Count(0)),
301 TimerId(0),
302 Duration::from_secs(1),
303 elapsed,
304 );
305 timeout.init().await.unwrap();
306 timeout.last_issued = Some(TimerGeneration(u64::MAX));
307
308 let result = timeout
309 .step(ReceiveTimeoutEvent::Inner(User::user(MailAddr(1), ())))
310 .await;
311
312 assert!(matches!(
313 result,
314 Err(ReceiveTimeoutError::GenerationExhausted)
315 ));
316 assert_eq!(timeout.inner().state().0, 1);
317 assert_eq!(timeout.live, Some(TimerGeneration(0)));
318 }
319}