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