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 named send lane retains its own order; this contract does not
24/// impose an order between independent lanes. Constructing a value remains
25/// 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, Ph, Sends, Birth> core::fmt::Debug for Actions<A, Ph, Sends, Birth>
33where
34    A: Address + core::fmt::Debug,
35    A::Nonce: core::fmt::Debug,
36    Ph: core::fmt::Debug,
37    Sends: core::fmt::Debug,
38    Birth: BirthMode,
39    Birth::Child: core::fmt::Debug,
40{
41    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
42        formatter
43            .debug_struct("Actions")
44            .field("sends", &self.sends)
45            .field("creates", &self.creates)
46            .field("become", &self.become_)
47            .finish()
48    }
49}
50
51impl<A, Ph, Sends, Birth> PartialEq for Actions<A, Ph, Sends, Birth>
52where
53    A: Address + PartialEq,
54    A::Nonce: PartialEq,
55    Ph: PartialEq,
56    Sends: PartialEq,
57    Birth: BirthMode,
58    Birth::Child: PartialEq,
59{
60    fn eq(&self, other: &Self) -> bool {
61        self.sends == other.sends && self.creates == other.creates && self.become_ == other.become_
62    }
63}
64
65impl<A, Ph, Sends, Birth> Eq for Actions<A, Ph, Sends, Birth>
66where
67    A: Address + Eq,
68    A::Nonce: Eq,
69    Ph: Eq,
70    Sends: Eq,
71    Birth: BirthMode,
72    Birth::Child: Eq,
73{
74}
75
76impl<A: Address, Ph, Sends, Birth: BirthMode> Actions<A, Ph, Sends, Birth> {
77    /// Transform only the send algebra, preserving creation order and the
78    /// next-behavior verdict exactly.
79    #[must_use]
80    pub fn map_sends<Mapped>(
81        self,
82        map: impl FnOnce(Sends) -> Mapped,
83    ) -> Actions<A, Ph, Mapped, Birth> {
84        Actions {
85            sends: map(self.sends),
86            creates: self.creates,
87            become_: self.become_,
88        }
89    }
90
91    /// Transform only the next-behavior verdict, preserving sends and
92    /// creation order exactly.
93    #[must_use]
94    pub fn map_become<NextPh>(
95        self,
96        map: impl FnOnce(Become<A, Ph>) -> Become<A, NextPh>,
97    ) -> Actions<A, NextPh, Sends, Birth> {
98        Actions {
99            sends: self.sends,
100            creates: self.creates,
101            become_: map(self.become_),
102        }
103    }
104}
105
106impl<A: Address, Ph, Sends: SendAlgebra, Birth: BirthMode> Actions<A, Ph, Sends, Birth> {
107    #[must_use]
108    pub const fn new(
109        sends: Sends,
110        creates: Vec<Create<A, Birth::Child>>,
111        become_: Become<A, Ph>,
112    ) -> Self {
113        Self {
114            sends,
115            creates,
116            become_,
117        }
118    }
119
120    #[must_use]
121    pub fn just(become_: Become<A, Ph>) -> Self {
122        Self {
123            sends: Sends::empty(),
124            creates: Vec::new(),
125            become_,
126        }
127    }
128
129    #[must_use]
130    pub fn cont() -> Self {
131        Self::just(Step::Continue)
132    }
133    #[must_use]
134    pub fn stop(exit: Exit<A>) -> Self {
135        Self::just(Step::Stop(exit))
136    }
137    #[must_use]
138    pub fn goto(phase: Ph) -> Self {
139        Self::just(Step::Goto(phase))
140    }
141
142    /// Continue after emitting the complete declared send product.
143    #[must_use]
144    pub fn send(sends: Sends) -> Self {
145        Self::new(sends, Vec::new(), Step::Continue)
146    }
147
148    /// Continue after staging the complete declared creation product.
149    #[must_use]
150    pub fn create(creates: Vec<Create<A, Birth::Child>>) -> Self {
151        Self::new(Sends::empty(), creates, Step::Continue)
152    }
153}
154
155impl<A: Address, Ph, Sends, Birth: BirthMode>
156    From<(Sends, Vec<Create<A, Birth::Child>>, Become<A, Ph>)> for Actions<A, Ph, Sends, Birth>
157{
158    fn from(
159        (sends, creates, become_): (Sends, Vec<Create<A, Birth::Child>>, Become<A, Ph>),
160    ) -> Self {
161        Self {
162            sends,
163            creates,
164            become_,
165        }
166    }
167}
168
169pub type Acted<A, Ph, Sends, Birth, E> = Result<Actions<A, Ph, Sends, Birth>, E>;
170
171#[cfg(test)]
172mod tests {
173    use super::*;
174    use crate::{Births, CreationKind, MailAddr};
175
176    #[test]
177    fn mapping_sends_preserves_creation_order_and_verdict() {
178        let actions: Actions<MailAddr, u8, Vec<u8>, Births<()>> = Actions::new(
179            vec![1, 2],
180            vec![
181                Create::new(3, (), CreationKind::Birth),
182                Create::new(4, (), CreationKind::replacement_of(3)),
183            ],
184            Step::Goto(7),
185        );
186
187        let mapped = actions.map_sends(|sends| sends.len());
188        assert_eq!(mapped.sends, 2);
189        assert_eq!(
190            mapped
191                .creates
192                .iter()
193                .map(|creation| creation.nonce)
194                .collect::<Vec<_>>(),
195            [3, 4]
196        );
197        assert!(matches!(mapped.become_, Step::Goto(7)));
198    }
199
200    #[test]
201    fn mapping_become_preserves_sends_and_creation_order() {
202        let actions: Actions<MailAddr, u8, Vec<u8>, Births<()>> = Actions::new(
203            vec![1, 2],
204            vec![Create::new(3, (), CreationKind::Birth)],
205            Step::Goto(7),
206        );
207
208        let mapped: Actions<MailAddr, Never, Vec<u8>, Births<()>> =
209            actions.map_become(|_| Step::Stop(Exit::Normal));
210        assert_eq!(mapped.sends, [1, 2]);
211        assert_eq!(mapped.creates[0].nonce, 3);
212        assert!(matches!(mapped.become_, Step::Stop(Exit::Normal)));
213    }
214}