Skip to main content

behavior/effects/
actions.rs

1//! The explicit result of one actor behavior transition.
2
3use super::sending::SendAlgebra;
4use crate::Exit;
5use crate::actor::{Address, BirthMode, Create};
6use crate::next::{Never, Step};
7
8pub type Become<A, Ph = Never> = Step<Ph, Exit<A>>;
9
10/// Bombay's typed realization of the actor transition effects: communications,
11/// fresh actor creation, and next behavior or termination.
12///
13/// An interpreter resolves every fresh creation in `creates` before
14/// interpreting any ordinary delivery or [`crate::ServiceSends`] request in
15/// `sends` from this value. A successful resolution installs and binds the
16/// child; a rejected resolution binds nothing. This ordering lets a same-action
17/// [`crate::ObserveCreation`] request return the committed result rather than
18/// the behavior's intent. Creation order is vector order, and each concrete
19/// send lane retains its own order; this contract does not impose an order
20/// between independent lanes of a [`crate::SendProduct`]. Constructing a value
21/// remains pure.
22pub struct Actions<A: Address, Ph, Sends, Birth: BirthMode> {
23    pub sends: Sends,
24    pub creates: Vec<Create<A, Birth::Child>>,
25    pub become_: Become<A, Ph>,
26}
27
28impl<A: Address, Ph, Sends, Birth: BirthMode> Actions<A, Ph, Sends, Birth> {
29    /// Transform only the send algebra, preserving creation order and the
30    /// next-behavior verdict exactly.
31    #[must_use]
32    pub fn map_sends<Mapped>(
33        self,
34        map: impl FnOnce(Sends) -> Mapped,
35    ) -> Actions<A, Ph, Mapped, Birth> {
36        Actions {
37            sends: map(self.sends),
38            creates: self.creates,
39            become_: self.become_,
40        }
41    }
42
43    /// Transform only the next-behavior verdict, preserving sends and
44    /// creation order exactly.
45    #[must_use]
46    pub fn map_become<NextPh>(
47        self,
48        map: impl FnOnce(Become<A, Ph>) -> Become<A, NextPh>,
49    ) -> Actions<A, NextPh, Sends, Birth> {
50        Actions {
51            sends: self.sends,
52            creates: self.creates,
53            become_: map(self.become_),
54        }
55    }
56}
57
58impl<A: Address, Ph, Sends: SendAlgebra, Birth: BirthMode> Actions<A, Ph, Sends, Birth> {
59    #[must_use]
60    pub const fn new(
61        sends: Sends,
62        creates: Vec<Create<A, Birth::Child>>,
63        become_: Become<A, Ph>,
64    ) -> Self {
65        Self {
66            sends,
67            creates,
68            become_,
69        }
70    }
71
72    #[must_use]
73    pub fn just(become_: Become<A, Ph>) -> Self {
74        Self {
75            sends: Sends::empty(),
76            creates: Vec::new(),
77            become_,
78        }
79    }
80
81    #[must_use]
82    pub fn cont() -> Self {
83        Self::just(Step::Continue)
84    }
85    #[must_use]
86    pub fn stop(exit: Exit<A>) -> Self {
87        Self::just(Step::Stop(exit))
88    }
89    #[must_use]
90    pub fn goto(phase: Ph) -> Self {
91        Self::just(Step::Goto(phase))
92    }
93}
94
95impl<A: Address, Ph, Sends, Birth: BirthMode>
96    From<(Sends, Vec<Create<A, Birth::Child>>, Become<A, Ph>)> for Actions<A, Ph, Sends, Birth>
97{
98    fn from(
99        (sends, creates, become_): (Sends, Vec<Create<A, Birth::Child>>, Become<A, Ph>),
100    ) -> Self {
101        Self {
102            sends,
103            creates,
104            become_,
105        }
106    }
107}
108
109pub type Acted<A, Ph, Sends, Birth, E> = Result<Actions<A, Ph, Sends, Birth>, E>;
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114    use crate::{Births, CreationKind, MailAddr};
115
116    #[test]
117    fn mapping_sends_preserves_creation_order_and_verdict() {
118        let actions: Actions<MailAddr, u8, Vec<u8>, Births<()>> = Actions::new(
119            vec![1, 2],
120            vec![
121                Create::new(3, (), CreationKind::Birth),
122                Create::new(4, (), CreationKind::replacement_of(3)),
123            ],
124            Step::Goto(7),
125        );
126
127        let mapped = actions.map_sends(|sends| sends.len());
128        assert_eq!(mapped.sends, 2);
129        assert_eq!(
130            mapped
131                .creates
132                .iter()
133                .map(|creation| creation.nonce)
134                .collect::<Vec<_>>(),
135            [3, 4]
136        );
137        assert!(matches!(mapped.become_, Step::Goto(7)));
138    }
139
140    #[test]
141    fn mapping_become_preserves_sends_and_creation_order() {
142        let actions: Actions<MailAddr, u8, Vec<u8>, Births<()>> = Actions::new(
143            vec![1, 2],
144            vec![Create::new(3, (), CreationKind::Birth)],
145            Step::Goto(7),
146        );
147
148        let mapped: Actions<MailAddr, Never, Vec<u8>, Births<()>> =
149            actions.map_become(|_| Step::Stop(Exit::Normal));
150        assert_eq!(mapped.sends, [1, 2]);
151        assert_eq!(mapped.creates[0].nonce, 3);
152        assert!(matches!(mapped.become_, Step::Stop(Exit::Normal)));
153    }
154}