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. When creation is rejected, a same-action
19/// [`crate::ObserveChild`] for its nonce is consumed without installing an
20/// observation or emitting [`crate::ChildStopped`], while
21/// [`crate::ObserveCreation`] reports the rejection. A later creation cannot
22/// inherit that consumed observation. Creation order is vector order, and each
23/// concrete send lane retains its own order; this contract does not impose an
24/// order between independent lanes of a [`crate::SendProduct`]. Constructing a
25/// value remains pure.
26pub struct Actions<A: Address, Ph, Sends, Birth: BirthMode> {
27    pub sends: Sends,
28    pub creates: Vec<Create<A, Birth::Child>>,
29    pub become_: Become<A, Ph>,
30}
31
32impl<A: Address, Ph, Sends, Birth: BirthMode> Actions<A, Ph, Sends, Birth> {
33    /// Transform only the send algebra, preserving creation order and the
34    /// next-behavior verdict exactly.
35    #[must_use]
36    pub fn map_sends<Mapped>(
37        self,
38        map: impl FnOnce(Sends) -> Mapped,
39    ) -> Actions<A, Ph, Mapped, Birth> {
40        Actions {
41            sends: map(self.sends),
42            creates: self.creates,
43            become_: self.become_,
44        }
45    }
46
47    /// Transform only the next-behavior verdict, preserving sends and
48    /// creation order exactly.
49    #[must_use]
50    pub fn map_become<NextPh>(
51        self,
52        map: impl FnOnce(Become<A, Ph>) -> Become<A, NextPh>,
53    ) -> Actions<A, NextPh, Sends, Birth> {
54        Actions {
55            sends: self.sends,
56            creates: self.creates,
57            become_: map(self.become_),
58        }
59    }
60}
61
62impl<A: Address, Ph, Sends: SendAlgebra, Birth: BirthMode> Actions<A, Ph, Sends, Birth> {
63    #[must_use]
64    pub const fn new(
65        sends: Sends,
66        creates: Vec<Create<A, Birth::Child>>,
67        become_: Become<A, Ph>,
68    ) -> Self {
69        Self {
70            sends,
71            creates,
72            become_,
73        }
74    }
75
76    #[must_use]
77    pub fn just(become_: Become<A, Ph>) -> Self {
78        Self {
79            sends: Sends::empty(),
80            creates: Vec::new(),
81            become_,
82        }
83    }
84
85    #[must_use]
86    pub fn cont() -> Self {
87        Self::just(Step::Continue)
88    }
89    #[must_use]
90    pub fn stop(exit: Exit<A>) -> Self {
91        Self::just(Step::Stop(exit))
92    }
93    #[must_use]
94    pub fn goto(phase: Ph) -> Self {
95        Self::just(Step::Goto(phase))
96    }
97}
98
99impl<A: Address, Ph, Sends, Birth: BirthMode>
100    From<(Sends, Vec<Create<A, Birth::Child>>, Become<A, Ph>)> for Actions<A, Ph, Sends, Birth>
101{
102    fn from(
103        (sends, creates, become_): (Sends, Vec<Create<A, Birth::Child>>, Become<A, Ph>),
104    ) -> Self {
105        Self {
106            sends,
107            creates,
108            become_,
109        }
110    }
111}
112
113pub type Acted<A, Ph, Sends, Birth, E> = Result<Actions<A, Ph, Sends, Birth>, E>;
114
115#[cfg(test)]
116mod tests {
117    use super::*;
118    use crate::{Births, CreationKind, MailAddr};
119
120    #[test]
121    fn mapping_sends_preserves_creation_order_and_verdict() {
122        let actions: Actions<MailAddr, u8, Vec<u8>, Births<()>> = Actions::new(
123            vec![1, 2],
124            vec![
125                Create::new(3, (), CreationKind::Birth),
126                Create::new(4, (), CreationKind::replacement_of(3)),
127            ],
128            Step::Goto(7),
129        );
130
131        let mapped = actions.map_sends(|sends| sends.len());
132        assert_eq!(mapped.sends, 2);
133        assert_eq!(
134            mapped
135                .creates
136                .iter()
137                .map(|creation| creation.nonce)
138                .collect::<Vec<_>>(),
139            [3, 4]
140        );
141        assert!(matches!(mapped.become_, Step::Goto(7)));
142    }
143
144    #[test]
145    fn mapping_become_preserves_sends_and_creation_order() {
146        let actions: Actions<MailAddr, u8, Vec<u8>, Births<()>> = Actions::new(
147            vec![1, 2],
148            vec![Create::new(3, (), CreationKind::Birth)],
149            Step::Goto(7),
150        );
151
152        let mapped: Actions<MailAddr, Never, Vec<u8>, Births<()>> =
153            actions.map_become(|_| Step::Stop(Exit::Normal));
154        assert_eq!(mapped.sends, [1, 2]);
155        assert_eq!(mapped.creates[0].nonce, 3);
156        assert!(matches!(mapped.become_, Step::Stop(Exit::Normal)));
157    }
158}