1use std::time::Duration;
5
6use tokio::time::Instant;
7
8use crate::behavior::{Address, Behavior, BirthMode, Births};
9use crate::deadlined::{At, 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>(B);
25
26impl<S: State<O, Br, E>, O, Br: BirthMode, E> Spec<Base<S, O, Br, E>> {
27 #[must_use]
28 pub fn new(state: S) -> Self {
29 Self(Base::new(state))
30 }
31}
32
33impl<A, S, M, P, E> Spec<Fsm<A, S, M, P, E>>
34where
35 A: Address,
36 P: Copy + PartialEq,
37{
38 #[must_use]
39 pub fn machine(state: S, phase: P, on: fn(P, &mut S, &M) -> Result<Move<P>, E>) -> Self {
40 Self(Fsm::new(state, phase, on))
41 }
42}
43
44impl<B: Behavior> Spec<B> {
45 #[must_use]
46 pub fn from_behavior(behavior: B) -> Self {
47 Self(behavior)
48 }
49
50 #[must_use]
51 pub fn build(self) -> B {
52 self.0
53 }
54
55 #[must_use]
56 pub fn behavior(&self) -> &B {
57 &self.0
58 }
59
60 #[must_use]
62 pub fn watch(self, peer: B::Addr, on_stopped: LinkReaction<B>) -> Spec<Watching<B>> {
63 Spec(Watching::new(self.0, peer, on_stopped))
64 }
65
66 #[must_use]
68 pub fn at(self, when: Option<Instant>, on_reached: AtReaction<B>) -> Spec<At<B>> {
69 Spec(At::new(self.0, when, on_reached))
70 }
71
72 #[must_use]
74 pub fn stash(self, route: fn(&B::Msg) -> StashRoute) -> Spec<Stashing<B>>
75 where
76 B: Behavior<Ph = Never>,
77 {
78 Spec(Stashing::new(self.0, route))
79 }
80
81 #[must_use]
84 pub fn children<C>(self, fleet: (usize, fn(usize) -> C)) -> Spec<Supervising<B, C>>
85 where
86 B: Behavior<Birth = Births<C>>,
87 C: Behavior<Ph = Never, Addr = B::Addr>,
88 <B::Addr as Address>::Nonce: From<u64>,
89 {
90 self.children_with_nonces(identity_nonce, fleet.0, fleet.1)
91 }
92
93 #[must_use]
94 pub fn children_with_nonces<C>(
95 self,
96 nonces: fn(usize) -> <B::Addr as Address>::Nonce,
97 count: usize,
98 build: fn(usize) -> C,
99 ) -> Spec<Supervising<B, C>>
100 where
101 B: Behavior<Birth = Births<C>>,
102 C: Behavior<Ph = Never, Addr = B::Addr>,
103 {
104 Spec(Supervising::new(
105 self.0,
106 nonces,
107 count,
108 build,
109 DEFAULT_STRATEGY,
110 DEFAULT_POLICY,
111 DEFAULT_BUDGET.0,
112 DEFAULT_BUDGET.1,
113 ))
114 }
115}
116
117impl<B, C> Spec<Supervising<B, C>>
118where
119 B: Behavior<Birth = Births<C>>,
120 C: Behavior<Ph = Never, Addr = B::Addr>,
121{
122 #[must_use]
123 pub fn restart(self, strategy: Strategy) -> Self {
124 Self(self.0.with_strategy(strategy))
125 }
126
127 #[must_use]
128 pub fn when(self, policy: RestartPolicy) -> Self {
129 Self(self.0.with_policy(policy))
130 }
131
132 #[must_use]
133 pub fn within(self, maximum: u32, window: Duration) -> Self {
134 Self(self.0.with_budget(maximum, window))
135 }
136}
137
138impl<B, A, Ph, Sends, Br> Behavior for Spec<B>
139where
140 A: Address + Send,
141 Sends: SendAlgebra,
142 Br: BirthMode,
143 B: Behavior<
144 Addr = A,
145 Ph = Ph,
146 Sends = Sends,
147 Birth = Br,
148 Effect = Actions<A, Ph, Sends, Br>,
149 Done = Exit<A>,
150 > + Send,
151 A::Nonce: Send,
152 B::Msg: Send,
153 B::Event: Send,
154{
155 type Addr = A;
156 type Msg = B::Msg;
157 type Event = B::Event;
158 type Sends = Sends;
159 type Ph = Ph;
160 type Error = B::Error;
161 type Birth = Br;
162 type Effect = B::Effect;
163 type Done = B::Done;
164
165 async fn init(&mut self) -> Result<Self::Effect, B::Error> {
166 self.0.init().await
167 }
168
169 async fn step(&mut self, event: B::Event) -> Result<Self::Effect, B::Error> {
170 self.0.step(event).await
171 }
172}