1use std::time::Duration;
5
6use tokio::time::Instant;
7
8use crate::behavior::{Address, Behavior, BirthMode, Births};
9use crate::deadlined::{At, AtId, AtReaction};
10use crate::stashing::{StashRoute, Stashing};
11use crate::supervising::{RestartPolicy, Strategy, Supervising};
12use crate::verdict::Never;
13use crate::watching::{LinkReaction, Watching};
14use crate::{Actions, Base, Exit, Fsm, Move, SendAlgebra, State};
15
16const DEFAULT_STRATEGY: Strategy = Strategy::OneForOne;
17const DEFAULT_POLICY: RestartPolicy = RestartPolicy::Transient;
18const DEFAULT_BUDGET: (u32, Duration) = (1, Duration::from_secs(5));
19
20fn identity_nonce<N: From<u64>>(index: usize) -> N {
21 N::from(u64::try_from(index).expect("fleet index fits u64"))
22}
23
24pub struct Spec<B> {
25 behavior: B,
26 next_timer: u64,
27}
28
29impl<S: State<O, Br, E>, O, Br: BirthMode, E> Spec<Base<S, O, Br, E>> {
30 #[must_use]
31 pub fn new(state: S) -> Self {
32 Self {
33 behavior: Base::new(state),
34 next_timer: 0,
35 }
36 }
37}
38
39impl<A, S, M, P, E> Spec<Fsm<A, S, M, P, E>>
40where
41 A: Address,
42 P: Copy + PartialEq,
43{
44 #[must_use]
45 pub fn machine(state: S, phase: P, on: fn(P, &mut S, &M) -> Result<Move<P>, E>) -> Self {
46 Self {
47 behavior: Fsm::new(state, phase, on),
48 next_timer: 0,
49 }
50 }
51}
52
53impl<B: Behavior> Spec<B> {
54 #[must_use]
55 pub fn from_behavior(behavior: B) -> Self {
56 Self {
57 behavior,
58 next_timer: 0,
59 }
60 }
61
62 #[must_use]
63 pub fn build(self) -> B {
64 self.behavior
65 }
66
67 #[must_use]
68 pub fn behavior(&self) -> &B {
69 &self.behavior
70 }
71
72 #[must_use]
74 pub fn watch(self, peer: B::Addr, on_stopped: LinkReaction<B>) -> Spec<Watching<B>> {
75 Spec {
76 behavior: Watching::new(self.behavior, peer, on_stopped),
77 next_timer: self.next_timer,
78 }
79 }
80
81 #[must_use]
88 pub fn at(self, when: Option<Instant>, on_reached: AtReaction<B>) -> Spec<At<B>> {
89 Spec {
90 behavior: At::new(self.behavior, AtId(self.next_timer), when, on_reached),
91 next_timer: self
92 .next_timer
93 .checked_add(1)
94 .expect("timer identity exhausted"),
95 }
96 }
97
98 #[must_use]
100 pub fn stash(self, route: fn(&B::Msg) -> StashRoute) -> Spec<Stashing<B>>
101 where
102 B: Behavior<Ph = Never>,
103 {
104 Spec {
105 behavior: Stashing::new(self.behavior, route),
106 next_timer: self.next_timer,
107 }
108 }
109
110 #[must_use]
113 pub fn children<C>(self, fleet: (usize, fn(usize) -> C)) -> Spec<Supervising<B, C>>
114 where
115 B: Behavior<Birth = Births<C>>,
116 C: Behavior<Ph = Never, Addr = B::Addr>,
117 <B::Addr as Address>::Nonce: From<u64>,
118 {
119 self.children_with_nonces(identity_nonce, fleet.0, fleet.1)
120 }
121
122 #[must_use]
123 pub fn children_with_nonces<C>(
124 self,
125 nonces: fn(usize) -> <B::Addr as Address>::Nonce,
126 count: usize,
127 build: fn(usize) -> C,
128 ) -> Spec<Supervising<B, C>>
129 where
130 B: Behavior<Birth = Births<C>>,
131 C: Behavior<Ph = Never, Addr = B::Addr>,
132 {
133 Spec {
134 behavior: Supervising::new(
135 self.behavior,
136 nonces,
137 count,
138 build,
139 DEFAULT_STRATEGY,
140 DEFAULT_POLICY,
141 DEFAULT_BUDGET.0,
142 DEFAULT_BUDGET.1,
143 ),
144 next_timer: self.next_timer,
145 }
146 }
147}
148
149impl<B, C> Spec<Supervising<B, C>>
150where
151 B: Behavior<Birth = Births<C>>,
152 C: Behavior<Ph = Never, Addr = B::Addr>,
153{
154 #[must_use]
155 pub fn restart(self, strategy: Strategy) -> Self {
156 Self {
157 behavior: self.behavior.with_strategy(strategy),
158 next_timer: self.next_timer,
159 }
160 }
161
162 #[must_use]
163 pub fn when(self, policy: RestartPolicy) -> Self {
164 Self {
165 behavior: self.behavior.with_policy(policy),
166 next_timer: self.next_timer,
167 }
168 }
169
170 #[must_use]
171 pub fn within(self, maximum: u32, window: Duration) -> Self {
172 Self {
173 behavior: self.behavior.with_budget(maximum, window),
174 next_timer: self.next_timer,
175 }
176 }
177}
178
179impl<B, A, Ph, Sends, Br> Behavior for Spec<B>
180where
181 A: Address + Send,
182 Sends: SendAlgebra,
183 Br: BirthMode,
184 B: Behavior<
185 Addr = A,
186 Ph = Ph,
187 Sends = Sends,
188 Birth = Br,
189 Effect = Actions<A, Ph, Sends, Br>,
190 Done = Exit<A>,
191 > + Send,
192 A::Nonce: Send,
193 B::Msg: Send,
194 B::Event: Send,
195{
196 type Addr = A;
197 type Msg = B::Msg;
198 type Event = B::Event;
199 type Sends = Sends;
200 type Ph = Ph;
201 type Error = B::Error;
202 type Birth = Br;
203 type Effect = B::Effect;
204 type Done = B::Done;
205
206 async fn init(&mut self) -> Result<Self::Effect, B::Error> {
207 self.behavior.init().await
208 }
209
210 async fn step(&mut self, event: B::Event) -> Result<Self::Effect, B::Error> {
211 self.behavior.step(event).await
212 }
213}