1use std::time::Duration;
5
6use tokio::time::Instant;
7
8use crate::behavior::{Address, Behavior, BirthMode, Births};
9use crate::deadlined::{At, AtReaction};
10use crate::protocol::TimerId;
11use crate::receive_timeout::{ReceiveTimeout, ReceiveTimeoutReaction};
12use crate::shutdown::{FinalizeOnShutdown, ShutdownReaction, StopOnShutdown};
13use crate::stashing::{StashRoute, Stashing};
14use crate::supervising::{RestartPolicy, Strategy, Supervising, SupervisionFailureReaction};
15use crate::verdict::Never;
16use crate::watching::{LinkReaction, Watching};
17use crate::{Actions, Base, Fsm, Move, SendAlgebra, State};
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 Spec<B> {
28 behavior: B,
29 next_timer: u64,
30}
31
32impl<S: State<O, Br, E>, O, Br: BirthMode, E> Spec<Base<S, O, Br, E>> {
33 #[must_use]
34 pub fn new(state: S) -> Self {
35 Self {
36 behavior: Base::new(state),
37 next_timer: 0,
38 }
39 }
40}
41
42impl<A, S, M, P, E> Spec<Fsm<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: Fsm::new(state, phase, on),
51 next_timer: 0,
52 }
53 }
54}
55
56impl<B: Behavior> Spec<B> {
57 #[must_use]
58 pub fn from_behavior(behavior: B) -> Self {
59 Self {
60 behavior,
61 next_timer: 0,
62 }
63 }
64
65 #[must_use]
66 pub fn build(self) -> B {
67 self.behavior
68 }
69
70 #[must_use]
71 pub fn behavior(&self) -> &B {
72 &self.behavior
73 }
74
75 #[must_use]
77 pub fn stop_on_shutdown(self) -> Spec<StopOnShutdown<B>> {
78 Spec {
79 behavior: StopOnShutdown::new(self.behavior),
80 next_timer: self.next_timer,
81 }
82 }
83
84 #[must_use]
87 pub fn finalize_on_shutdown(
88 self,
89 finalize: ShutdownReaction<B>,
90 ) -> Spec<FinalizeOnShutdown<B>> {
91 Spec {
92 behavior: FinalizeOnShutdown::new(self.behavior, finalize),
93 next_timer: self.next_timer,
94 }
95 }
96
97 #[must_use]
99 pub fn watch(self, peer: B::Addr, on_stopped: LinkReaction<B>) -> Spec<Watching<B>> {
100 Spec {
101 behavior: Watching::new(self.behavior, peer, on_stopped),
102 next_timer: self.next_timer,
103 }
104 }
105
106 #[must_use]
113 pub fn at(self, when: Option<Instant>, on_reached: AtReaction<B>) -> Spec<At<B>> {
114 Spec {
115 behavior: At::new(self.behavior, TimerId(self.next_timer), when, on_reached),
116 next_timer: self
117 .next_timer
118 .checked_add(1)
119 .expect("timer identity exhausted"),
120 }
121 }
122
123 #[must_use]
136 pub fn receive_timeout(
137 self,
138 after: Duration,
139 on_elapsed: ReceiveTimeoutReaction<B>,
140 ) -> Spec<ReceiveTimeout<B>> {
141 Spec {
142 behavior: ReceiveTimeout::new(
143 self.behavior,
144 TimerId(self.next_timer),
145 after,
146 on_elapsed,
147 ),
148 next_timer: self
149 .next_timer
150 .checked_add(1)
151 .expect("timer identity exhausted"),
152 }
153 }
154
155 #[must_use]
157 pub fn stash(self, route: fn(&B::Msg) -> StashRoute) -> Spec<Stashing<B>>
158 where
159 B: Behavior<Ph = Never>,
160 {
161 Spec {
162 behavior: Stashing::new(self.behavior, route),
163 next_timer: self.next_timer,
164 }
165 }
166
167 #[must_use]
170 pub fn children<C>(self, fleet: (usize, fn(usize) -> C)) -> Spec<Supervising<B, C>>
171 where
172 B: Behavior<Birth = Births<C>>,
173 C: Behavior<Ph = Never, Addr = B::Addr>,
174 <B::Addr as Address>::Nonce: From<u64>,
175 {
176 self.children_with_nonces(identity_nonce, fleet.0, fleet.1)
177 }
178
179 #[must_use]
180 pub fn children_with_nonces<C>(
181 self,
182 nonces: fn(usize) -> <B::Addr as Address>::Nonce,
183 count: usize,
184 build: fn(usize) -> C,
185 ) -> Spec<Supervising<B, C>>
186 where
187 B: Behavior<Birth = Births<C>>,
188 C: Behavior<Ph = Never, Addr = B::Addr>,
189 {
190 Spec {
191 behavior: Supervising::new(
192 self.behavior,
193 nonces,
194 count,
195 build,
196 DEFAULT_STRATEGY,
197 DEFAULT_POLICY,
198 DEFAULT_BUDGET.0,
199 DEFAULT_BUDGET.1,
200 ),
201 next_timer: self.next_timer,
202 }
203 }
204}
205
206impl<B, C> Spec<Supervising<B, C>>
207where
208 B: Behavior<Birth = Births<C>>,
209 C: Behavior<Ph = Never, Addr = B::Addr>,
210{
211 #[must_use]
212 pub fn restart(self, strategy: Strategy) -> Self {
213 Self {
214 behavior: self.behavior.with_strategy(strategy),
215 next_timer: self.next_timer,
216 }
217 }
218
219 #[must_use]
220 pub fn when(self, policy: RestartPolicy) -> Self {
221 Self {
222 behavior: self.behavior.with_policy(policy),
223 next_timer: self.next_timer,
224 }
225 }
226
227 #[must_use]
228 pub fn within(self, maximum: u32, window: Duration) -> Self {
229 Self {
230 behavior: self.behavior.with_budget(maximum, window),
231 next_timer: self.next_timer,
232 }
233 }
234
235 #[must_use]
238 pub fn on_supervision_failure(self, reaction: SupervisionFailureReaction<B>) -> Self {
239 Self {
240 behavior: self.behavior.with_failure_reaction(reaction),
241 next_timer: self.next_timer,
242 }
243 }
244}
245
246impl<B, A, Ph, Sends, Br> Behavior for Spec<B>
247where
248 A: Address + Send,
249 Sends: SendAlgebra,
250 Br: BirthMode,
251 B: Behavior<Addr = A, Ph = Ph, Sends = Sends, Birth = Br> + Send,
252 A::Nonce: Send,
253 B::Msg: Send,
254 B::Event: Send,
255{
256 type Addr = A;
257 type Msg = B::Msg;
258 type Event = B::Event;
259 type Sends = Sends;
260 type Ph = Ph;
261 type Error = B::Error;
262 type Birth = Br;
263
264 async fn init(&mut self) -> Result<Actions<A, Ph, Sends, Br>, B::Error> {
265 self.behavior.init().await
266 }
267
268 async fn step(&mut self, event: B::Event) -> Result<Actions<A, Ph, Sends, Br>, B::Error> {
269 self.behavior.step(event).await
270 }
271}