Skip to main content

behavior/calculus/
behavior.rs

1//! Pure behavior folds from one typed event to explicit transition actions.
2
3use super::user_event::UserEvent;
4use crate::actor::{Address, BirthMode};
5use crate::effects::{Acted, Actions, SendAlgebra};
6
7/// The only successful effect shape admitted by a [`Behavior`] implementation.
8pub type BehaviorActed<B> = Acted<
9    <B as Behavior>::Addr,
10    <B as Behavior>::Ph,
11    <B as Behavior>::Sends,
12    <B as Behavior>::Birth,
13    <B as Behavior>::Error,
14>;
15
16/// Crate-minted capability for defining one initialization fold.
17///
18/// The constructor is private: only the lifecycle boundary can issue this
19/// capability, exactly once for an owned behavior value.
20pub struct InitializationTurn {
21    #[allow(dead_code, reason = "private field prevents external construction")]
22    private: (),
23}
24
25impl InitializationTurn {
26    pub(crate) const fn new() -> Self {
27        Self { private: () }
28    }
29}
30
31/// Crate-minted capability for defining one active mailbox fold.
32///
33/// Values can only be issued by an initialized [`crate::Active`] behavior or
34/// by a concrete core wrapper delegating the same active turn inward.
35pub struct ActiveTurn {
36    #[allow(dead_code, reason = "private field prevents external construction")]
37    private: (),
38}
39
40impl ActiveTurn {
41    pub(crate) const fn new() -> Self {
42        Self { private: () }
43    }
44}
45
46/// A composed pure behavior. `Event` is the complete accepted protocol;
47/// every successful transition returns the declared [`Actions`] value.
48pub trait Behavior {
49    type Addr: Address;
50    type Msg;
51    type Event: UserEvent<Addr = Self::Addr, Message = Self::Msg>;
52    type Sends: SendAlgebra;
53    type Ph;
54    type Error;
55    type Birth: BirthMode;
56
57    /// Produce initialization actions before the first event is accepted.
58    ///
59    /// # Errors
60    ///
61    /// Returns the behavior's declared controlled initialization failure.
62    fn init(&mut self, _turn: InitializationTurn) -> BehaviorActed<Self>
63    where
64        Self: Sized,
65    {
66        Ok(Actions::cont())
67    }
68
69    /// Fold exactly one event into explicit actions and the next behavior.
70    ///
71    /// # Errors
72    ///
73    /// Returns the behavior's declared controlled transition failure.
74    fn transition(&mut self, _turn: ActiveTurn, event: Self::Event) -> BehaviorActed<Self>;
75}
76
77/// Static projection from a composed behavior to its authored base behavior.
78///
79/// Wrappers preserve this associated type, so inspection never depends on
80/// wrapper nesting depth or a positional path.
81pub trait BehaviorBase {
82    type Base;
83
84    fn base(&self) -> &Self::Base;
85}
86
87/// Fold one event through an inner behavior owned by a semantic wrapper.
88///
89/// This is Bombay's derived, canonical boundary for wrapper composition; it is
90/// not an additional actor-model operation. It invokes the inner deterministic
91/// fold exactly once and returns its complete typed action value without
92/// inspecting or transforming it. It does not execute a runtime turn,
93/// interpret effects, or provide an alternate actor executor; top-level runtime
94/// transitions remain the responsibility of the runtime's machine adapter.
95///
96/// # Errors
97///
98/// Returns the inner behavior's controlled transition failure unchanged.
99pub(crate) fn initialize<B: Behavior>(behavior: &mut B) -> BehaviorActed<B> {
100    B::init(behavior, InitializationTurn::new())
101}
102
103pub(crate) fn delegate_transition<B: Behavior>(
104    behavior: &mut B,
105    event: B::Event,
106) -> BehaviorActed<B> {
107    B::transition(behavior, ActiveTurn::new(), event)
108}