Skip to main content

behavior/
deadlined.rs

1//! Pure one-shot time composition. Scheduling is a request to the emitting
2//! actor's local clock service.
3
4use tokio::time::Instant;
5
6use crate::behavior::{
7    Actions, Address, Become, Behavior, BirthMode, SendAlgebra, SendProduct, ServiceSends, User,
8    UserEvent,
9};
10use crate::shutdown::{ShutdownEvent, ShutdownRequested};
11use crate::supervising::{ChildEvent, ChildStopped, WorkerEvent, WorkerStopped};
12use crate::watching::{PeerEvent, PeerStopped};
13use crate::{Exit, Step};
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16pub struct AtId(pub u64);
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19pub struct AtGeneration(pub u64);
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub struct ScheduleAt {
23    pub id: AtId,
24    pub generation: AtGeneration,
25    pub at: Instant,
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub struct TimeReached {
30    pub id: AtId,
31    pub generation: AtGeneration,
32    pub at: Instant,
33}
34
35#[derive(Debug, Clone, PartialEq, Eq)]
36pub enum AtEvent<E> {
37    Inner(E),
38    Reached(TimeReached),
39}
40
41pub trait TimeEvent: Sized {
42    fn time_reached(event: TimeReached) -> Option<Self>;
43}
44
45impl<E> TimeEvent for AtEvent<E> {
46    fn time_reached(event: TimeReached) -> Option<Self> {
47        Some(Self::Reached(event))
48    }
49}
50
51impl<E: UserEvent> UserEvent for AtEvent<E> {
52    type Addr = E::Addr;
53    type Message = E::Message;
54
55    fn user(from: Self::Addr, message: Self::Message) -> Self {
56        Self::Inner(E::user(from, message))
57    }
58
59    fn into_user(self) -> Result<User<Self::Addr, Self::Message>, Self> {
60        match self {
61            Self::Inner(event) => event.into_user().map_err(Self::Inner),
62            reached @ Self::Reached(_) => Err(reached),
63        }
64    }
65}
66
67impl<E: PeerEvent<A>, A: Address> PeerEvent<A> for AtEvent<E> {
68    fn peer_stopped(event: PeerStopped<A>) -> Option<Self> {
69        E::peer_stopped(event).map(Self::Inner)
70    }
71}
72
73impl<E: ChildEvent<A>, A: Address> ChildEvent<A> for AtEvent<E> {
74    fn child_stopped(event: ChildStopped<A>) -> Option<Self> {
75        E::child_stopped(event).map(Self::Inner)
76    }
77}
78
79impl<E: WorkerEvent<A>, A: Address> WorkerEvent<A> for AtEvent<E> {
80    fn worker_stopped(event: WorkerStopped<A>) -> Option<Self> {
81        E::worker_stopped(event).map(Self::Inner)
82    }
83}
84
85impl<E: ShutdownEvent> ShutdownEvent for AtEvent<E> {
86    fn shutdown_requested(event: ShutdownRequested) -> Option<Self> {
87        E::shutdown_requested(event).map(Self::Inner)
88    }
89}
90
91pub type AtReaction<B> =
92    fn(&mut B) -> Result<Become<<B as Behavior>::Addr>, <B as Behavior>::Error>;
93
94pub type AtSends<B> = SendProduct<<B as Behavior>::Sends, ServiceSends<ScheduleAt>>;
95
96pub type AtActions<B> =
97    Actions<<B as Behavior>::Addr, <B as Behavior>::Ph, AtSends<B>, <B as Behavior>::Birth>;
98
99pub struct At<B: Behavior> {
100    inner: B,
101    id: AtId,
102    scheduled: Option<(AtGeneration, Instant)>,
103    on_reached: AtReaction<B>,
104}
105
106impl<B: Behavior> At<B> {
107    #[must_use]
108    pub fn new(inner: B, id: AtId, at: Option<Instant>, on_reached: AtReaction<B>) -> Self {
109        Self {
110            inner,
111            id,
112            scheduled: at.map(|at| (AtGeneration(0), at)),
113            on_reached,
114        }
115    }
116
117    #[must_use]
118    pub fn inner(&self) -> &B {
119        &self.inner
120    }
121}
122
123impl<B, A, Ph, Sends, Br> Behavior for At<B>
124where
125    A: Address + Send,
126    Sends: SendAlgebra,
127    Br: BirthMode,
128    B: Behavior<
129            Addr = A,
130            Ph = Ph,
131            Sends = Sends,
132            Birth = Br,
133            Effect = Actions<A, Ph, Sends, Br>,
134            Done = Exit<A>,
135        > + Send,
136    B::Event: TimeEvent + Send,
137    B::Msg: Send,
138{
139    type Addr = A;
140    type Msg = B::Msg;
141    type Event = AtEvent<B::Event>;
142    type Sends = SendProduct<Sends, ServiceSends<ScheduleAt>>;
143    type Ph = Ph;
144    type Error = B::Error;
145    type Birth = Br;
146    type Effect = Actions<A, Ph, Self::Sends, Br>;
147    type Done = Exit<A>;
148
149    async fn init(&mut self) -> Result<Self::Effect, B::Error> {
150        let actions = self.inner.init().await?;
151        let own = self
152            .scheduled
153            .map_or_else(ServiceSends::empty, |(generation, at)| {
154                ServiceSends::one(ScheduleAt {
155                    id: self.id,
156                    generation,
157                    at,
158                })
159            });
160        Ok(Self::wrap(actions, own))
161    }
162
163    async fn step(&mut self, event: Self::Event) -> Result<Self::Effect, B::Error> {
164        match event {
165            AtEvent::Reached(event)
166                if event.id == self.id && self.scheduled == Some((event.generation, event.at)) =>
167            {
168                self.scheduled = None;
169                let become_ = match (self.on_reached)(&mut self.inner)? {
170                    Step::Continue => Step::Continue,
171                    Step::Goto(never) => match never {},
172                    Step::Stop(exit) => Step::Stop(exit),
173                };
174                Ok(Actions {
175                    sends: SendProduct {
176                        inner: B::Sends::empty(),
177                        own: ServiceSends::empty(),
178                    },
179                    creates: Vec::new(),
180                    become_,
181                })
182            }
183            AtEvent::Reached(event) => match B::Event::time_reached(event) {
184                Some(inner) => self
185                    .inner
186                    .step(inner)
187                    .await
188                    .map(|actions| Self::wrap(actions, ServiceSends::empty())),
189                None => Ok(Actions::cont()),
190            },
191            AtEvent::Inner(event) => self
192                .inner
193                .step(event)
194                .await
195                .map(|actions| Self::wrap(actions, ServiceSends::empty())),
196        }
197    }
198}
199
200impl<B: Behavior> At<B> {
201    fn wrap(
202        actions: Actions<B::Addr, B::Ph, B::Sends, B::Birth>,
203        own: ServiceSends<ScheduleAt>,
204    ) -> AtActions<B> {
205        Actions {
206            sends: SendProduct {
207                inner: actions.sends,
208                own,
209            },
210            creates: actions.creates,
211            become_: actions.become_,
212        }
213    }
214}