1use std::time::Duration;
5
6use std::time::Instant;
7
8use crate::Actions;
9use crate::BehaviorBase;
10use crate::behavior::{Address, Behavior, Births};
11use crate::calculus::{BehaviorActed, EventInput, UserEvent, delegate_transition};
12use crate::next::Never;
13use crate::protocol::TimerId;
14use crate::shutdown::{FinalizeOnShutdown, ShutdownReaction, StopOnShutdown};
15use crate::stash::{Stash, StashRoute};
16use crate::supervision::{RestartPolicy, Strategy, SupervisionFailureReaction, Supervisor};
17use crate::timing::{Deadline, DeadlineReaction};
18use crate::timing::{ReceiveTimeout, ReceiveTimeoutReaction};
19use crate::watch::{LinkReaction, Watch};
20
21const DEFAULT_STRATEGY: Strategy = Strategy::OneForOne;
22const DEFAULT_POLICY: RestartPolicy = RestartPolicy::Transient;
23const DEFAULT_BUDGET: (u32, Duration) = (1, Duration::from_secs(5));
24
25pub struct Compose<B> {
37 behavior: B,
38}
39
40pub struct Initialized<B: Behavior> {
43 pub behavior: Active<B>,
44 pub actions: Actions<B::Addr, B::Ph, B::Sends, B::Birth>,
45}
46
47pub struct Active<B: Behavior> {
61 pub(crate) behavior: B,
62}
63
64impl<B: Behavior> Active<B> {
65 #[must_use]
66 pub fn base(&self) -> &B::Base
67 where
68 B: BehaviorBase,
69 {
70 self.behavior.base()
71 }
72
73 #[must_use]
74 pub fn stashed(&self) -> usize
75 where
76 B: crate::StashStatus,
77 {
78 self.behavior.stashed_messages()
79 }
80
81 pub fn transition(&mut self, event: B::Event) -> BehaviorActed<B> {
83 delegate_transition(&mut self.behavior, event)
84 }
85
86 pub fn receive(&mut self, from: B::Addr, message: B::Msg) -> BehaviorActed<B> {
88 self.transition(B::Event::user(from, message))
89 }
90
91 pub fn on<Input>(&mut self, input: Input) -> BehaviorActed<B>
93 where
94 B::Event: EventInput<Input>,
95 {
96 self.transition(B::Event::inject(input))
97 }
98}
99
100impl<B: Behavior> core::ops::Deref for Active<B> {
101 type Target = B;
102
103 fn deref(&self) -> &Self::Target {
104 &self.behavior
105 }
106}
107
108impl<B> Compose<B> {
109 #[must_use]
112 pub const fn new(behavior: B) -> Self {
113 Self { behavior }
114 }
115}
116
117impl<B: Behavior> Compose<B> {
118 fn map_behavior<Mapped>(self, map: impl FnOnce(B) -> Mapped) -> Compose<Mapped> {
119 Compose {
120 behavior: map(self.behavior),
121 }
122 }
123
124 fn try_map_behavior<Mapped, E>(
125 self,
126 map: impl FnOnce(B) -> Result<Mapped, E>,
127 ) -> Result<Compose<Mapped>, E> {
128 map(self.behavior).map(|behavior| Compose { behavior })
129 }
130
131 #[must_use]
132 pub fn base(&self) -> &B::Base
133 where
134 B: BehaviorBase,
135 {
136 self.behavior.base()
137 }
138
139 #[must_use]
140 pub fn definition(&self) -> &B {
141 &self.behavior
142 }
143
144 pub fn initialize(self) -> Result<Initialized<B>, B::Error> {
153 let mut behavior = self.behavior;
154 let actions = crate::calculus::initialize(&mut behavior)?;
155 Ok(Initialized {
156 behavior: Active { behavior },
157 actions,
158 })
159 }
160
161 #[must_use]
163 pub fn stop_on_shutdown(self) -> Compose<StopOnShutdown<B>> {
164 self.map_behavior(StopOnShutdown::new)
165 }
166
167 #[must_use]
170 pub fn finalize_on_shutdown(
171 self,
172 finalize: ShutdownReaction<B>,
173 ) -> Compose<FinalizeOnShutdown<B>> {
174 self.map_behavior(|behavior| FinalizeOnShutdown::new(behavior, finalize))
175 }
176
177 #[must_use]
179 pub fn watch(self, peer: B::Addr, on_stopped: LinkReaction<B>) -> Compose<Watch<B>> {
180 self.map_behavior(|behavior| Watch::new(behavior, peer, on_stopped))
181 }
182
183 #[must_use]
186 pub fn deadline(
187 self,
188 timer: TimerId,
189 when: Option<Instant>,
190 on_reached: DeadlineReaction<B>,
191 ) -> Compose<Deadline<B>> {
192 self.map_behavior(|behavior| Deadline::new(behavior, timer, when, on_reached))
193 }
194
195 #[must_use]
204 pub fn receive_timeout(
205 self,
206 timer: TimerId,
207 after: Duration,
208 on_elapsed: ReceiveTimeoutReaction<B>,
209 ) -> Compose<ReceiveTimeout<B>> {
210 self.map_behavior(|behavior| ReceiveTimeout::new(behavior, timer, after, on_elapsed))
211 }
212
213 #[must_use]
215 pub fn stash(self, route: fn(&B::Msg) -> StashRoute) -> Compose<Stash<B>>
216 where
217 B: Behavior<Ph = Never>,
218 {
219 self.map_behavior(|behavior| Stash::new(behavior, route))
220 }
221
222 #[must_use]
226 pub fn children<C>(
227 self,
228 nonces: fn(usize) -> <B::Addr as Address>::Nonce,
229 count: usize,
230 build: fn(usize) -> Option<C>,
231 ) -> Result<Compose<Supervisor<B, C>>, crate::FleetError<<B::Addr as Address>::Nonce>>
232 where
233 B: Behavior<Birth = Births<C>>,
234 C: Behavior<Ph = Never, Addr = B::Addr>,
235 <B::Addr as Address>::Nonce: From<u64>,
236 {
237 self.try_map_behavior(|behavior| {
238 Supervisor::new(
239 behavior,
240 nonces,
241 count,
242 build,
243 DEFAULT_STRATEGY,
244 DEFAULT_POLICY,
245 DEFAULT_BUDGET.0,
246 DEFAULT_BUDGET.1,
247 )
248 })
249 }
250}
251
252impl<B, C> Compose<Supervisor<B, C>>
253where
254 B: Behavior<Birth = Births<C>>,
255 C: Behavior<Ph = Never, Addr = B::Addr>,
256 <B::Addr as Address>::Nonce: From<u64>,
257{
258 #[must_use]
259 pub fn restart(self, strategy: Strategy) -> Self {
260 Self {
261 behavior: self.behavior.with_strategy(strategy),
262 }
263 }
264
265 #[must_use]
266 pub fn when(self, policy: RestartPolicy) -> Self {
267 Self {
268 behavior: self.behavior.with_policy(policy),
269 }
270 }
271
272 #[must_use]
273 pub fn within(self, maximum: u32, window: Duration) -> Self {
274 Self {
275 behavior: self.behavior.with_budget(maximum, window),
276 }
277 }
278
279 #[must_use]
282 pub fn on_supervision_failure(self, reaction: SupervisionFailureReaction<B>) -> Self {
283 Self {
284 behavior: self.behavior.with_failure_reaction(reaction),
285 }
286 }
287}