1use std::time::Duration;
5
6use tokio::time::Instant;
7
8use crate::behavior::{Address, Behavior, BirthMode, Births};
9use crate::next::Never;
10use crate::protocol::TimerId;
11use crate::shutdown::{FinalizeOnShutdown, ShutdownReaction, StopOnShutdown};
12use crate::stash::{Stash, StashRoute};
13use crate::supervision::{RestartPolicy, Strategy, SupervisionFailureReaction, Supervisor};
14use crate::timing::{Deadline, DeadlineReaction};
15use crate::timing::{ReceiveTimeout, ReceiveTimeoutReaction};
16use crate::watch::{LinkReaction, Watch};
17use crate::{Actions, Handler, Machine, Move, Pure, SendAlgebra};
18
19const DEFAULT_STRATEGY: Strategy = Strategy::OneForOne;
20const DEFAULT_POLICY: RestartPolicy = RestartPolicy::Transient;
21const DEFAULT_BUDGET: (u32, Duration) = (1, Duration::from_secs(5));
22
23fn identity_nonce<N: From<u64>>(index: usize) -> N {
24 N::from(u64::try_from(index).expect("fleet index fits u64"))
25}
26
27pub struct Compose<B> {
28 behavior: B,
29 next_timer: u64,
30}
31
32impl<S: Handler<O, Br, E>, O, Br: BirthMode, E> Compose<Pure<S, O, Br, E>> {
33 #[must_use]
34 pub fn new(state: S) -> Self {
35 Self {
36 behavior: Pure::new(state),
37 next_timer: 0,
38 }
39 }
40}
41
42impl<A, S, M, P, E> Compose<Machine<A, S, M, P, E>>
43where
44 A: Address,
45 P: Copy + PartialEq,
46{
47 #[must_use]
48 pub fn machine(state: S, phase: P, on: fn(P, &mut S, &M) -> Result<Move<P>, E>) -> Self {
49 Self {
50 behavior: Machine::new(state, phase, on),
51 next_timer: 0,
52 }
53 }
54}
55
56impl<B: Behavior> Compose<B> {
57 fn map_behavior<Mapped>(self, map: impl FnOnce(B) -> Mapped) -> Compose<Mapped> {
58 Compose {
59 behavior: map(self.behavior),
60 next_timer: self.next_timer,
61 }
62 }
63
64 fn map_timer<Mapped>(self, map: impl FnOnce(B, TimerId) -> Mapped) -> Compose<Mapped> {
65 let timer = TimerId(self.next_timer);
66 Compose {
67 behavior: map(self.behavior, timer),
68 next_timer: self
69 .next_timer
70 .checked_add(1)
71 .expect("timer identity exhausted"),
72 }
73 }
74
75 #[must_use]
76 pub fn from_behavior(behavior: B) -> Self {
77 Self {
78 behavior,
79 next_timer: 0,
80 }
81 }
82
83 #[must_use]
84 pub fn build(self) -> B {
85 self.behavior
86 }
87
88 #[must_use]
89 pub fn behavior(&self) -> &B {
90 &self.behavior
91 }
92
93 #[must_use]
95 pub fn stop_on_shutdown(self) -> Compose<StopOnShutdown<B>> {
96 self.map_behavior(StopOnShutdown::new)
97 }
98
99 #[must_use]
102 pub fn finalize_on_shutdown(
103 self,
104 finalize: ShutdownReaction<B>,
105 ) -> Compose<FinalizeOnShutdown<B>> {
106 self.map_behavior(|behavior| FinalizeOnShutdown::new(behavior, finalize))
107 }
108
109 #[must_use]
111 pub fn watch(self, peer: B::Addr, on_stopped: LinkReaction<B>) -> Compose<Watch<B>> {
112 self.map_behavior(|behavior| Watch::new(behavior, peer, on_stopped))
113 }
114
115 #[must_use]
122 pub fn deadline(
123 self,
124 when: Option<Instant>,
125 on_reached: DeadlineReaction<B>,
126 ) -> Compose<Deadline<B>> {
127 self.map_timer(|behavior, timer| Deadline::new(behavior, timer, when, on_reached))
128 }
129
130 #[must_use]
143 pub fn receive_timeout(
144 self,
145 after: Duration,
146 on_elapsed: ReceiveTimeoutReaction<B>,
147 ) -> Compose<ReceiveTimeout<B>> {
148 self.map_timer(|behavior, timer| ReceiveTimeout::new(behavior, timer, after, on_elapsed))
149 }
150
151 #[must_use]
153 pub fn stash(self, route: fn(&B::Msg) -> StashRoute) -> Compose<Stash<B>>
154 where
155 B: Behavior<Ph = Never>,
156 {
157 self.map_behavior(|behavior| Stash::new(behavior, route))
158 }
159
160 #[must_use]
163 pub fn children<C>(self, fleet: (usize, fn(usize) -> C)) -> Compose<Supervisor<B, C>>
164 where
165 B: Behavior<Birth = Births<C>>,
166 C: Behavior<Ph = Never, Addr = B::Addr>,
167 <B::Addr as Address>::Nonce: From<u64>,
168 {
169 self.children_with_nonces(identity_nonce, fleet.0, fleet.1)
170 }
171
172 #[must_use]
173 pub fn children_with_nonces<C>(
174 self,
175 nonces: fn(usize) -> <B::Addr as Address>::Nonce,
176 count: usize,
177 build: fn(usize) -> C,
178 ) -> Compose<Supervisor<B, C>>
179 where
180 B: Behavior<Birth = Births<C>>,
181 C: Behavior<Ph = Never, Addr = B::Addr>,
182 {
183 self.map_behavior(|behavior| {
184 Supervisor::new(
185 behavior,
186 nonces,
187 count,
188 build,
189 DEFAULT_STRATEGY,
190 DEFAULT_POLICY,
191 DEFAULT_BUDGET.0,
192 DEFAULT_BUDGET.1,
193 )
194 })
195 }
196}
197
198impl<B, C> Compose<Supervisor<B, C>>
199where
200 B: Behavior<Birth = Births<C>>,
201 C: Behavior<Ph = Never, Addr = B::Addr>,
202{
203 #[must_use]
204 pub fn restart(self, strategy: Strategy) -> Self {
205 Self {
206 behavior: self.behavior.with_strategy(strategy),
207 next_timer: self.next_timer,
208 }
209 }
210
211 #[must_use]
212 pub fn when(self, policy: RestartPolicy) -> Self {
213 Self {
214 behavior: self.behavior.with_policy(policy),
215 next_timer: self.next_timer,
216 }
217 }
218
219 #[must_use]
220 pub fn within(self, maximum: u32, window: Duration) -> Self {
221 Self {
222 behavior: self.behavior.with_budget(maximum, window),
223 next_timer: self.next_timer,
224 }
225 }
226
227 #[must_use]
230 pub fn on_supervision_failure(self, reaction: SupervisionFailureReaction<B>) -> Self {
231 Self {
232 behavior: self.behavior.with_failure_reaction(reaction),
233 next_timer: self.next_timer,
234 }
235 }
236}
237
238impl<B, A, Ph, Sends, Br> Behavior for Compose<B>
239where
240 A: Address,
241 Sends: SendAlgebra,
242 Br: BirthMode,
243 B: Behavior<Addr = A, Ph = Ph, Sends = Sends, Birth = Br>,
244{
245 type Addr = A;
246 type Msg = B::Msg;
247 type Event = B::Event;
248 type Sends = Sends;
249 type Ph = Ph;
250 type Error = B::Error;
251 type Birth = Br;
252
253 fn init(&mut self) -> Result<Actions<A, Ph, Sends, Br>, B::Error> {
254 self.behavior.init()
255 }
256
257 fn transition(&mut self, event: B::Event) -> Result<Actions<A, Ph, Sends, Br>, B::Error> {
258 self.behavior.transition(event)
259 }
260}