behavior/transition.rs
1//! Pure behavior folds from one typed event to explicit transition actions.
2
3use crate::actor::{Address, BirthMode};
4use crate::effects::{Acted, Actions, SendEffects};
5use crate::user_event::UserEvent;
6
7/// Reusable zero-state protocol identity for messages `M` addressed by `A`.
8///
9/// This value has no runtime operations. It lets an actor template publish its
10/// communication signature independently of the concrete state/fold type that
11/// currently implements that signature.
12pub struct MessageProtocol<A: Address, M>(core::marker::PhantomData<fn(A, M)>);
13
14impl<A: Address, M> Protocol for MessageProtocol<A, M> {
15 type Addr = A;
16 type Msg = M;
17}
18
19/// The statically known address and message signature of an actor protocol.
20///
21/// This signature is deliberately independent of [`Behavior`]'s transition
22/// algebra. A [`Recipient`](crate::Recipient) or [`Delivery`](crate::Delivery)
23/// needs to prove only which address namespace and message type it names; it
24/// must not recursively prove the destination's sends, births, phases, or
25/// transition implementation. That separation permits closed static actor
26/// topologies in which a root sends to an actor whose reply path returns to the
27/// same root.
28pub trait Protocol {
29 type Addr: Address;
30 type Msg;
31}
32
33/// The only successful effect shape admitted by a [`Behavior`] implementation.
34pub type BehaviorActed<B> = Acted<
35 BehaviorAddr<B>,
36 <B as Behavior>::Ph,
37 <B as Behavior>::Sends,
38 <B as Behavior>::Birth,
39 <B as Behavior>::Error,
40>;
41
42/// Address namespace projected from a behavior's stable public protocol.
43pub type BehaviorAddr<B> = <<B as Behavior>::Protocol as Protocol>::Addr;
44
45/// Public message algebra projected from a behavior's stable protocol.
46pub type BehaviorMessage<B> = <<B as Behavior>::Protocol as Protocol>::Msg;
47
48/// Capability for defining one initialization fold.
49///
50/// The constructor is private: only the lifecycle boundary can issue this
51/// capability, exactly once for an owned behavior value.
52pub struct InitializationTurn {
53 #[allow(dead_code, reason = "private field prevents external construction")]
54 private: (),
55}
56
57impl InitializationTurn {
58 pub(crate) const fn new() -> Self {
59 Self { private: () }
60 }
61}
62
63/// Capability for defining one active mailbox fold.
64///
65/// Values are issued only by the lifecycle and wrapper-composition boundaries.
66pub struct ActiveTurn {
67 #[allow(dead_code, reason = "private field prevents external construction")]
68 private: (),
69}
70
71impl ActiveTurn {
72 pub(crate) const fn new() -> Self {
73 Self { private: () }
74 }
75}
76
77/// A composed pure behavior. `Event` is the complete accepted input algebra;
78/// the separately declared [`Protocol`] is stable public destination identity,
79/// and every successful transition returns the declared [`Actions`] value.
80///
81/// The public protocol must exactly match the address and user-message lane:
82///
83/// ```compile_fail
84/// use behavior::{Actions, ActiveTurn, Behavior, BehaviorActed, MailAddr, MessageProtocol,
85/// Never, NoBirths, Protocol, User};
86/// struct Wrong;
87/// impl Protocol for Wrong {
88/// type Addr = MailAddr;
89/// type Msg = String;
90/// }
91/// struct Counter;
92/// impl Protocol for Counter {
93/// type Addr = MailAddr;
94/// type Msg = u8;
95/// }
96/// impl Behavior for Counter {
97/// type Protocol = Wrong;
98/// type Event = User<MailAddr, u8>;
99/// type Sends = Vec<Never>;
100/// type Ph = Never;
101/// type Error = Never;
102/// type Birth = NoBirths;
103/// fn transition(&mut self, _: ActiveTurn, _: Self::Event) -> BehaviorActed<Self> {
104/// Ok(Actions::cont())
105/// }
106/// }
107/// ```
108pub trait Behavior {
109 /// Stable public communication identity owned by this actor template.
110 ///
111 /// Behavior wrappers must preserve this type unless their documented
112 /// purpose is to adapt the public message protocol. The equality bound
113 /// prevents a behavior from consuming a different address or user-message
114 /// signature than the protocol established for its actor identity.
115 type Protocol: Protocol;
116
117 type Event: UserEvent<Addr = BehaviorAddr<Self>, Message = BehaviorMessage<Self>>;
118 type Sends: SendEffects + crate::SendsFor<Self::Event>;
119 type Ph;
120 type Error;
121 type Birth: BirthMode;
122
123 /// Produce initialization actions before the first event is accepted.
124 ///
125 /// # Errors
126 ///
127 /// Returns the behavior's declared controlled initialization failure.
128 fn init(&mut self, _turn: InitializationTurn) -> BehaviorActed<Self>
129 where
130 Self: Sized,
131 {
132 Ok(Actions::cont())
133 }
134
135 /// Fold exactly one event into explicit actions and the next behavior.
136 ///
137 /// # Errors
138 ///
139 /// Returns the behavior's declared controlled transition failure.
140 fn transition(&mut self, _turn: ActiveTurn, event: Self::Event) -> BehaviorActed<Self>;
141}
142
143/// Static projection from a composed behavior to its authored base behavior.
144///
145/// Wrappers preserve this associated type, so inspection never depends on
146/// wrapper nesting depth or a positional path.
147pub trait BehaviorBase {
148 type Base;
149
150 fn base(&self) -> &Self::Base;
151}
152
153/// Initialize an inner behavior owned by a semantic composition.
154///
155/// This is Bombay's derived, canonical boundary for wrapper composition; it is
156/// not an additional actor-model operation. It invokes the inner initialization
157/// fold exactly once and returns its complete typed action value without
158/// inspecting or transforming it. It does not execute a runtime turn,
159/// interpret effects, or provide an alternate actor executor; top-level runtime
160/// transitions remain the responsibility of the runtime's machine adapter.
161///
162/// # Errors
163///
164/// Returns the inner behavior's controlled transition failure unchanged.
165#[doc(hidden)]
166pub fn initialize<B: Behavior>(behavior: &mut B) -> BehaviorActed<B> {
167 B::init(behavior, InitializationTurn::new())
168}
169
170/// Fold one event through an inner behavior owned by a semantic wrapper.
171///
172/// This invokes the inner deterministic fold exactly once and returns its
173/// complete typed action value without interpreting it.
174///
175/// # Errors
176///
177/// Returns the inner behavior's controlled transition failure unchanged.
178#[doc(hidden)]
179pub fn delegate_transition<B: Behavior>(behavior: &mut B, event: B::Event) -> BehaviorActed<B> {
180 B::transition(behavior, ActiveTurn::new(), event)
181}