Skip to main content

behavior/
behavior.rs

1//! The pure actor algebra: receive one event, then send, create, and become.
2
3use core::future::Future;
4use core::marker::PhantomData;
5
6use communication::{Consumer, Received};
7
8use crate::Exit;
9use crate::deadlined::{TimeEvent, TimeReached};
10use crate::supervising::{ChildEvent, ChildStopped};
11use crate::verdict::{Never, Step};
12use crate::watching::{PeerEvent, PeerStopped};
13
14/// A pure actor-address namespace.
15pub trait Address: Copy + Eq {
16    type Nonce: Copy + Eq;
17
18    #[must_use]
19    fn birth(self, nonce: Self::Nonce) -> Self;
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
23pub struct MailAddr(pub u64);
24
25impl Address for MailAddr {
26    type Nonce = u64;
27
28    fn birth(self, nonce: u64) -> Self {
29        Self(self.0 ^ nonce.wrapping_mul(0x9E37_79B9_7F4A_7C15))
30    }
31}
32
33/// An address expression. Services are actors supplied by the interpreter;
34/// their concrete addresses never enter the behavior or `Spec` API.
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum Route<A: Address> {
37    Global(A),
38    Child(A::Nonce),
39    Service,
40}
41
42/// A recipient statically coupled to the message it accepts.
43pub struct Recipient<A: Address, M> {
44    route: Route<A>,
45    message: PhantomData<fn(M)>,
46}
47
48impl<A: Address, M> Copy for Recipient<A, M> {}
49
50impl<A: Address, M> Clone for Recipient<A, M> {
51    fn clone(&self) -> Self {
52        *self
53    }
54}
55
56impl<A: Address, M> Recipient<A, M> {
57    #[must_use]
58    pub fn global(address: A) -> Self {
59        Self::from_route(Route::Global(address))
60    }
61
62    #[must_use]
63    pub fn child(nonce: A::Nonce) -> Self {
64        Self::from_route(Route::Child(nonce))
65    }
66
67    #[must_use]
68    pub(crate) fn service() -> Self {
69        Self::from_route(Route::Service)
70    }
71
72    #[must_use]
73    pub fn route(self) -> Route<A> {
74        self.route
75    }
76
77    const fn from_route(route: Route<A>) -> Self {
78        Self {
79            route,
80            message: PhantomData,
81        }
82    }
83}
84
85/// One statically typed send operation.
86#[derive(Clone, PartialEq, Eq)]
87pub struct Delivery<A: Address, M> {
88    pub to: Recipient<A, M>,
89    pub message: M,
90}
91
92impl<A: Address, M> Delivery<A, M> {
93    #[must_use]
94    pub fn new(to: Recipient<A, M>, message: M) -> Self {
95        Self { to, message }
96    }
97}
98
99impl<A: Address, M> PartialEq for Recipient<A, M> {
100    fn eq(&self, other: &Self) -> bool {
101        self.route == other.route
102    }
103}
104
105impl<A: Address, M> Eq for Recipient<A, M> {}
106
107impl<A: Address + core::fmt::Debug, M> core::fmt::Debug for Recipient<A, M>
108where
109    A::Nonce: core::fmt::Debug,
110{
111    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
112        self.route.fmt(f)
113    }
114}
115
116/// A product of independently typed send protocols.
117#[derive(Debug, Clone, PartialEq, Eq)]
118pub struct SendProduct<L, R> {
119    pub inner: L,
120    pub own: R,
121}
122
123/// The monoid required to accumulate sends across transitions.
124pub trait SendAlgebra: Sized {
125    fn empty() -> Self;
126    fn append(&mut self, other: Self);
127}
128
129impl<T> SendAlgebra for Vec<T> {
130    fn empty() -> Self {
131        Vec::new()
132    }
133
134    fn append(&mut self, mut other: Self) {
135        Vec::append(self, &mut other);
136    }
137}
138
139impl<L: SendAlgebra, R: SendAlgebra> SendAlgebra for SendProduct<L, R> {
140    fn empty() -> Self {
141        Self {
142            inner: L::empty(),
143            own: R::empty(),
144        }
145    }
146
147    fn append(&mut self, other: Self) {
148        self.inner.append(other.inner);
149        self.own.append(other.own);
150    }
151}
152
153/// Fresh actor creation. Replacement at an existing address is deliberately
154/// absent; stable restart is derived with a proxy actor.
155#[derive(Debug, Clone, PartialEq, Eq)]
156pub struct Create<A: Address, New> {
157    pub nonce: A::Nonce,
158    pub child: New,
159}
160
161/// A type-level description of the creation leg of the actor algebra.
162pub trait BirthMode {
163    type Child;
164}
165
166/// This behavior cannot emit child births.
167#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
168pub struct NoBirths;
169
170impl BirthMode for NoBirths {
171    type Child = Never;
172}
173
174/// This behavior may emit births of `C`.
175#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
176pub struct Births<C>(PhantomData<fn() -> C>);
177
178impl<C> BirthMode for Births<C> {
179    type Child = C;
180}
181
182pub type Become<A, Ph = Never> = Step<Ph, Exit<A>>;
183
184/// Exactly Agha's effect triple, with a Bombay interpretation-order policy.
185///
186/// An interpreter installs every fresh actor in `creates` before interpreting
187/// any delivery in `sends` from this value. This makes recipients created by a
188/// transition available to that transition's sends, including service
189/// protocols that observe a fresh child. Creation order is vector order, and
190/// each concrete send lane retains its own order; this contract does not
191/// impose an order between independent lanes of a [`SendProduct`].
192///
193/// The ordering rule belongs to the interpreter boundary. Constructing an
194/// `Actions` value remains pure and performs none of its effects.
195pub struct Actions<A: Address, Ph, Sends, Birth: BirthMode> {
196    pub sends: Sends,
197    pub creates: Vec<Create<A, Birth::Child>>,
198    pub become_: Become<A, Ph>,
199}
200
201impl<A: Address, Ph, Sends: SendAlgebra, Birth: BirthMode> Actions<A, Ph, Sends, Birth> {
202    #[must_use]
203    pub fn just(become_: Become<A, Ph>) -> Self {
204        Self {
205            sends: Sends::empty(),
206            creates: Vec::new(),
207            become_,
208        }
209    }
210
211    #[must_use]
212    pub fn cont() -> Self {
213        Self::just(Step::Continue)
214    }
215
216    #[must_use]
217    pub fn stop(exit: Exit<A>) -> Self {
218        Self::just(Step::Stop(exit))
219    }
220
221    #[must_use]
222    pub fn goto(phase: Ph) -> Self {
223        Self::just(Step::Goto(phase))
224    }
225}
226
227pub type Acted<A, Ph, Sends, Birth, E> = Result<Actions<A, Ph, Sends, Birth>, E>;
228
229/// The user-message event at the Agha floor.
230#[derive(Debug, Clone, PartialEq, Eq)]
231pub struct User<A, M> {
232    pub from: A,
233    pub message: M,
234}
235
236/// Construction/extraction of the user lane through a composed event type.
237pub trait UserEvent: Sized {
238    type Addr: Address;
239    type Message;
240
241    fn user(from: Self::Addr, message: Self::Message) -> Self;
242    /// Extract the user lane.
243    ///
244    /// # Errors
245    /// Returns the unchanged event when it belongs to another composed lane.
246    fn into_user(self) -> Result<User<Self::Addr, Self::Message>, Self>;
247}
248
249pub type StateActed<A, Out, Birth, Err> = Acted<A, Never, Vec<Delivery<A, Out>>, Birth, Err>;
250
251pub trait State<Out = Never, Birth = NoBirths, Err = Never>
252where
253    Birth: BirthMode,
254{
255    type Addr: Address;
256    type Msg;
257
258    /// Fold a user message into the Agha triple.
259    ///
260    /// # Errors
261    /// Returns the state's declared controlled failure.
262    #[allow(
263        clippy::type_complexity,
264        reason = "the alias exposes all state protocol seats"
265    )]
266    fn handle(
267        &mut self,
268        from: Self::Addr,
269        message: Self::Msg,
270    ) -> StateActed<Self::Addr, Out, Birth, Err>;
271}
272
273/// A composed pure behavior. `Event` is the complete accepted protocol;
274/// successful transitions always return the same Agha effect algebra.
275pub trait Behavior {
276    type Addr: Address;
277    type Msg;
278    type Event: UserEvent<Addr = Self::Addr, Message = Self::Msg>;
279    type Sends: SendAlgebra;
280    type Ph;
281    type Error;
282    type Birth: BirthMode;
283    type Effect;
284    type Done;
285
286    fn init(&mut self) -> impl Future<Output = Result<Self::Effect, Self::Error>> + Send;
287
288    fn step(
289        &mut self,
290        event: Self::Event,
291    ) -> impl Future<Output = Result<Self::Effect, Self::Error>> + Send;
292}
293
294pub struct Base<S: State<O, Br, E>, O = Never, Br: BirthMode = NoBirths, E = Never> {
295    state: S,
296    marker: PhantomData<fn(O, Br, E)>,
297}
298
299impl<S: State<O, Br, E>, O, Br: BirthMode, E> Base<S, O, Br, E> {
300    #[must_use]
301    pub fn new(state: S) -> Self {
302        Self {
303            state,
304            marker: PhantomData,
305        }
306    }
307
308    #[must_use]
309    pub fn state(&self) -> &S {
310        &self.state
311    }
312}
313
314pub type Transition<S, A, M, O, Br, E> =
315    fn(&mut S, A, M) -> Acted<A, Never, Vec<Delivery<A, O>>, Br, E>;
316
317pub struct FnState<S, A: Address, M, O = Never, Br: BirthMode = NoBirths, E = Never> {
318    pub state: S,
319    pub handle: Transition<S, A, M, O, Br, E>,
320}
321
322impl<S, A: Address, M, O, Br: BirthMode, E> State<O, Br, E> for FnState<S, A, M, O, Br, E> {
323    type Addr = A;
324    type Msg = M;
325
326    fn handle(&mut self, from: A, message: M) -> Acted<A, Never, Vec<Delivery<A, O>>, Br, E> {
327        (self.handle)(&mut self.state, from, message)
328    }
329}
330
331impl<S, A: Address, M, O, Br: BirthMode, E> Base<FnState<S, A, M, O, Br, E>, O, Br, E> {
332    #[must_use]
333    pub fn from_fn(state: S, handle: Transition<S, A, M, O, Br, E>) -> Self {
334        Self::new(FnState { state, handle })
335    }
336}
337
338impl<A: Address, M> UserEvent for User<A, M> {
339    type Addr = A;
340    type Message = M;
341
342    fn user(from: A, message: M) -> Self {
343        Self { from, message }
344    }
345
346    fn into_user(self) -> Result<Self, Self> {
347        Ok(self)
348    }
349}
350
351impl<A: Address, M> TimeEvent for User<A, M> {
352    fn time_reached(_: TimeReached) -> Option<Self> {
353        None
354    }
355}
356
357impl<A: Address, M> PeerEvent<A> for User<A, M> {
358    fn peer_stopped(_: PeerStopped<A>) -> Option<Self> {
359        None
360    }
361}
362
363impl<A: Address, M> ChildEvent<A> for User<A, M> {
364    fn child_stopped(_: ChildStopped<A>) -> Option<Self> {
365        None
366    }
367}
368
369impl<S, O, Br, E> Behavior for Base<S, O, Br, E>
370where
371    S: State<O, Br, E> + Send,
372    S::Addr: Send,
373    S::Msg: Send,
374    Br: BirthMode,
375    Br::Child: Send,
376    E: Send,
377{
378    type Addr = S::Addr;
379    type Msg = S::Msg;
380    type Event = User<S::Addr, S::Msg>;
381    type Sends = Vec<Delivery<S::Addr, O>>;
382    type Ph = Never;
383    type Error = E;
384    type Birth = Br;
385    type Effect = Actions<S::Addr, Never, Self::Sends, Br>;
386    type Done = Exit<S::Addr>;
387
388    async fn init(&mut self) -> Result<Self::Effect, E> {
389        Ok(Actions::cont())
390    }
391
392    async fn step(&mut self, event: Self::Event) -> Result<Self::Effect, E> {
393        self.state.handle(event.from, event.message)
394    }
395}
396
397pub struct Transcript<A: Address, Sends, New> {
398    pub sends: Sends,
399    pub creates: Vec<Create<A, New>>,
400    pub exit: Exit<A>,
401}
402
403/// Drive user-lane messages through a complete behavior protocol.
404///
405/// # Errors
406/// Returns the first controlled behavior failure.
407pub async fn run<B, C, A, Sends, Br>(
408    mut behavior: B,
409    mut mailbox: Consumer<C, B::Msg>,
410    from: A,
411) -> Result<Transcript<A, Sends, Br::Child>, B::Error>
412where
413    A: Address,
414    Sends: SendAlgebra,
415    Br: BirthMode,
416    B: Behavior<
417            Addr = A,
418            Ph = Never,
419            Sends = Sends,
420            Birth = Br,
421            Effect = Actions<A, Never, Sends, Br>,
422            Done = Exit<A>,
423        >,
424{
425    let mut sends = Sends::empty();
426    let mut creates = Vec::new();
427    let initial = behavior.init().await?;
428    sends.append(initial.sends);
429    creates.extend(initial.creates);
430    match initial.become_ {
431        Step::Continue => {}
432        Step::Goto(never) => match never {},
433        Step::Stop(exit) => {
434            return Ok(Transcript {
435                sends,
436                creates,
437                exit,
438            });
439        }
440    }
441    while let Some(received) = mailbox.recv().await {
442        let Received::User(message) = received else {
443            continue;
444        };
445        let actions = behavior.step(B::Event::user(from, message)).await?;
446        sends.append(actions.sends);
447        creates.extend(actions.creates);
448        match actions.become_ {
449            Step::Continue => {}
450            Step::Goto(never) => match never {},
451            Step::Stop(exit) => {
452                return Ok(Transcript {
453                    sends,
454                    creates,
455                    exit,
456                });
457            }
458        }
459    }
460    Ok(Transcript {
461        sends,
462        creates,
463        exit: Exit::Collected,
464    })
465}