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.
185pub struct Actions<A: Address, Ph, Sends, Birth: BirthMode> {
186    pub sends: Sends,
187    pub creates: Vec<Create<A, Birth::Child>>,
188    pub become_: Become<A, Ph>,
189}
190
191impl<A: Address, Ph, Sends: SendAlgebra, Birth: BirthMode> Actions<A, Ph, Sends, Birth> {
192    #[must_use]
193    pub fn just(become_: Become<A, Ph>) -> Self {
194        Self {
195            sends: Sends::empty(),
196            creates: Vec::new(),
197            become_,
198        }
199    }
200
201    #[must_use]
202    pub fn cont() -> Self {
203        Self::just(Step::Continue)
204    }
205
206    #[must_use]
207    pub fn stop(exit: Exit<A>) -> Self {
208        Self::just(Step::Stop(exit))
209    }
210
211    #[must_use]
212    pub fn goto(phase: Ph) -> Self {
213        Self::just(Step::Goto(phase))
214    }
215}
216
217pub type Acted<A, Ph, Sends, Birth, E> = Result<Actions<A, Ph, Sends, Birth>, E>;
218
219/// The user-message event at the Agha floor.
220#[derive(Debug, Clone, PartialEq, Eq)]
221pub struct User<A, M> {
222    pub from: A,
223    pub message: M,
224}
225
226/// Construction/extraction of the user lane through a composed event type.
227pub trait UserEvent: Sized {
228    type Addr: Address;
229    type Message;
230
231    fn user(from: Self::Addr, message: Self::Message) -> Self;
232    /// Extract the user lane.
233    ///
234    /// # Errors
235    /// Returns the unchanged event when it belongs to another composed lane.
236    fn into_user(self) -> Result<User<Self::Addr, Self::Message>, Self>;
237}
238
239pub type StateActed<A, Out, Birth, Err> = Acted<A, Never, Vec<Delivery<A, Out>>, Birth, Err>;
240
241pub trait State<Out = Never, Birth = NoBirths, Err = Never>
242where
243    Birth: BirthMode,
244{
245    type Addr: Address;
246    type Msg;
247
248    /// Fold a user message into the Agha triple.
249    ///
250    /// # Errors
251    /// Returns the state's declared controlled failure.
252    #[allow(
253        clippy::type_complexity,
254        reason = "the alias exposes all state protocol seats"
255    )]
256    fn handle(
257        &mut self,
258        from: Self::Addr,
259        message: Self::Msg,
260    ) -> StateActed<Self::Addr, Out, Birth, Err>;
261}
262
263/// A composed pure behavior. `Event` is the complete accepted protocol;
264/// successful transitions always return the same Agha effect algebra.
265pub trait Behavior {
266    type Addr: Address;
267    type Msg;
268    type Event: UserEvent<Addr = Self::Addr, Message = Self::Msg>;
269    type Sends: SendAlgebra;
270    type Ph;
271    type Error;
272    type Birth: BirthMode;
273    type Effect;
274    type Done;
275
276    fn init(&mut self) -> impl Future<Output = Result<Self::Effect, Self::Error>> + Send;
277
278    fn step(
279        &mut self,
280        event: Self::Event,
281    ) -> impl Future<Output = Result<Self::Effect, Self::Error>> + Send;
282}
283
284pub struct Base<S: State<O, Br, E>, O = Never, Br: BirthMode = NoBirths, E = Never> {
285    state: S,
286    marker: PhantomData<fn(O, Br, E)>,
287}
288
289impl<S: State<O, Br, E>, O, Br: BirthMode, E> Base<S, O, Br, E> {
290    #[must_use]
291    pub fn new(state: S) -> Self {
292        Self {
293            state,
294            marker: PhantomData,
295        }
296    }
297
298    #[must_use]
299    pub fn state(&self) -> &S {
300        &self.state
301    }
302}
303
304pub type Transition<S, A, M, O, Br, E> =
305    fn(&mut S, A, M) -> Acted<A, Never, Vec<Delivery<A, O>>, Br, E>;
306
307pub struct FnState<S, A: Address, M, O = Never, Br: BirthMode = NoBirths, E = Never> {
308    pub state: S,
309    pub handle: Transition<S, A, M, O, Br, E>,
310}
311
312impl<S, A: Address, M, O, Br: BirthMode, E> State<O, Br, E> for FnState<S, A, M, O, Br, E> {
313    type Addr = A;
314    type Msg = M;
315
316    fn handle(&mut self, from: A, message: M) -> Acted<A, Never, Vec<Delivery<A, O>>, Br, E> {
317        (self.handle)(&mut self.state, from, message)
318    }
319}
320
321impl<S, A: Address, M, O, Br: BirthMode, E> Base<FnState<S, A, M, O, Br, E>, O, Br, E> {
322    #[must_use]
323    pub fn from_fn(state: S, handle: Transition<S, A, M, O, Br, E>) -> Self {
324        Self::new(FnState { state, handle })
325    }
326}
327
328impl<A: Address, M> UserEvent for User<A, M> {
329    type Addr = A;
330    type Message = M;
331
332    fn user(from: A, message: M) -> Self {
333        Self { from, message }
334    }
335
336    fn into_user(self) -> Result<Self, Self> {
337        Ok(self)
338    }
339}
340
341impl<A: Address, M> TimeEvent for User<A, M> {
342    fn time_reached(_: TimeReached) -> Option<Self> {
343        None
344    }
345}
346
347impl<A: Address, M> PeerEvent<A> for User<A, M> {
348    fn peer_stopped(_: PeerStopped<A>) -> Option<Self> {
349        None
350    }
351}
352
353impl<A: Address, M> ChildEvent<A> for User<A, M> {
354    fn child_stopped(_: ChildStopped<A>) -> Option<Self> {
355        None
356    }
357}
358
359impl<S, O, Br, E> Behavior for Base<S, O, Br, E>
360where
361    S: State<O, Br, E> + Send,
362    S::Addr: Send,
363    S::Msg: Send,
364    Br: BirthMode,
365    Br::Child: Send,
366    E: Send,
367{
368    type Addr = S::Addr;
369    type Msg = S::Msg;
370    type Event = User<S::Addr, S::Msg>;
371    type Sends = Vec<Delivery<S::Addr, O>>;
372    type Ph = Never;
373    type Error = E;
374    type Birth = Br;
375    type Effect = Actions<S::Addr, Never, Self::Sends, Br>;
376    type Done = Exit<S::Addr>;
377
378    async fn init(&mut self) -> Result<Self::Effect, E> {
379        Ok(Actions::cont())
380    }
381
382    async fn step(&mut self, event: Self::Event) -> Result<Self::Effect, E> {
383        self.state.handle(event.from, event.message)
384    }
385}
386
387pub struct Transcript<A: Address, Sends, New> {
388    pub sends: Sends,
389    pub creates: Vec<Create<A, New>>,
390    pub exit: Exit<A>,
391}
392
393/// Drive user-lane messages through a complete behavior protocol.
394///
395/// # Errors
396/// Returns the first controlled behavior failure.
397pub async fn run<B, C, A, Sends, Br>(
398    mut behavior: B,
399    mut mailbox: Consumer<C, B::Msg>,
400    from: A,
401) -> Result<Transcript<A, Sends, Br::Child>, B::Error>
402where
403    A: Address,
404    Sends: SendAlgebra,
405    Br: BirthMode,
406    B: Behavior<
407            Addr = A,
408            Ph = Never,
409            Sends = Sends,
410            Birth = Br,
411            Effect = Actions<A, Never, Sends, Br>,
412            Done = Exit<A>,
413        >,
414{
415    let mut sends = Sends::empty();
416    let mut creates = Vec::new();
417    let initial = behavior.init().await?;
418    sends.append(initial.sends);
419    creates.extend(initial.creates);
420    match initial.become_ {
421        Step::Continue => {}
422        Step::Goto(never) => match never {},
423        Step::Stop(exit) => {
424            return Ok(Transcript {
425                sends,
426                creates,
427                exit,
428            });
429        }
430    }
431    while let Some(received) = mailbox.recv().await {
432        let Received::User(message) = received else {
433            continue;
434        };
435        let actions = behavior.step(B::Event::user(from, message)).await?;
436        sends.append(actions.sends);
437        creates.extend(actions.creates);
438        match actions.become_ {
439            Step::Continue => {}
440            Step::Goto(never) => match never {},
441            Step::Stop(exit) => {
442                return Ok(Transcript {
443                    sends,
444                    creates,
445                    exit,
446                });
447            }
448        }
449    }
450    Ok(Transcript {
451        sends,
452        creates,
453        exit: Exit::Collected,
454    })
455}