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