Skip to main content

behavior/
effect.rs

1//! Concise action results for ordinary infallible, no-birth behaviors.
2
3use crate::{Actions, Address, MailAddr, Never, NoBirths, Step, Stopped};
4
5/// Effects emitted by one ordinary infallible, no-birth behavior turn.
6///
7/// `Effect` is a truthful shorthand for
8/// `Actions<A, Never, Vec<S>, NoBirths>`. It introduces no runtime operation,
9/// hidden error path, creation capability, or phase transition. Behaviors that
10/// need any of those capabilities use the complete [`Actions`] algebra.
11pub struct Effect<S, A: Address = MailAddr> {
12    actions: Actions<A, Never, Vec<S>, NoBirths>,
13}
14
15impl<S, A: Address> Effect<S, A> {
16    /// Continue after emitting no sends.
17    #[must_use]
18    pub fn none() -> Self {
19        Self {
20            actions: Actions::cont(),
21        }
22    }
23
24    /// Continue after emitting one send value.
25    #[must_use]
26    pub fn send(send: S) -> Self {
27        Self {
28            actions: Actions::send(vec![send]),
29        }
30    }
31
32    /// Continue after emitting the supplied send values in order.
33    #[must_use]
34    pub fn send_all(sends: impl IntoIterator<Item = S>) -> Self {
35        Self {
36            actions: Actions::send(sends.into_iter().collect()),
37        }
38    }
39
40    /// Stop normally after preserving this turn's sends.
41    #[must_use]
42    pub fn stop(mut self) -> Self {
43        self.actions.become_ = Step::Stop(Stopped);
44        self
45    }
46}
47
48impl<S, A: Address> From<Effect<S, A>> for Actions<A, Never, Vec<S>, NoBirths> {
49    fn from(effect: Effect<S, A>) -> Self {
50        effect.actions
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57
58    #[test]
59    fn conversion_preserves_send_order_and_terminal_decision() {
60        let actions: Actions<MailAddr, Never, Vec<u8>, NoBirths> =
61            Effect::send_all([2, 3, 5]).stop().into();
62
63        assert_eq!(actions.sends, [2, 3, 5]);
64        assert!(matches!(actions.become_, Step::Stop(Stopped)));
65        assert!(actions.creates.is_empty());
66    }
67}