behavior/lib.rs
1//! Pure, typed actor-behavior primitives.
2//!
3//! [`Protocol`] is stable public destination identity (`Addr` plus `Msg`). A
4//! [`Behavior`] separately owns state and folds its complete [`Behavior::Event`]
5//! algebra into exactly [`Actions`]: sends, fresh creations, and its next
6//! behavior or termination. A protocol is not a behavior, and `Behavior` is not
7//! a `Protocol` supertrait. Higher capabilities extend internal event and
8//! effect algebras while transparent wrappers preserve [`Behavior::Protocol`].
9//!
10//! Finite mailbox execution belongs to a runtime or test driver, not to this
11//! one-turn behavior algebra.
12//!
13//! ```compile_fail,E0405
14//! fn requires_reducer<T: behavior::ActionReducer>() {}
15//! ```
16//!
17//! Capability-restricted action products use the existing `Actions` algebra;
18//! there is no second convenience wrapper with an overlapping contract.
19//!
20//! ```compile_fail
21//! fn accepts_duplicate(_: behavior::Effect<u8>) {}
22//! ```
23
24// The `#[behavior]` expansion emits `::behavior::…` paths; this alias lets the
25// expansion resolve inside this crate too.
26extern crate self as behavior;
27
28mod actor;
29mod effects;
30mod next;
31mod transition;
32mod user_event;
33
34pub use actor::{
35 Address, AllocationRejection, BirthMode, BirthNodeAppend, BirthNodeAt, BirthNodeLogicalHosts,
36 BirthNodeProtocols, BirthProtocol, BirthProtocolAt, BirthProtocolHead, BirthProtocolProduct,
37 BirthProtocolTail, BirthProtocols, Births, ChildChoice, ChildCons, ChildCreationOutcome,
38 ChildCreationProduct, ChildCreationSettled, ChildDelivery, ChildDeliveryReason, ChildHead,
39 ChildInput, ChildInputReason, ChildNamespaceExhausted, ChildOccurrence, ChildOccurrenceProduct,
40 ChildOccurrenceProductAt, ChildOccurrenceResolution, ChildOccurrenceShape, ChildOccurrences,
41 ChildPosition, ChildProduct, ChildReport, ChildRole, ChildTail, Children, CreateChild,
42 CreationCorrelation, CreationId, CreationKind, CreationRejection, CreationSequence, Creations,
43 DeclaredChildOccurrence, Delivery, DispatchBirth, EndpointAddress, EstablishChild,
44 EstablishedActor, EstablishedCreation, EstablishedDelivery, EstablishedRecipient,
45 ExactDeliveryReason, InterpretEstablished, LogicalDeliveryReason, MailAddr, NoBirthProtocols,
46 NoBirths, NoChildren, Recipient, ResolveChildOccurrence, ResolvedChild, ResolvedChildPosition,
47 RetirementBirths, RoleChild, RoleProtocol, RoutedCreation, StructuralChildOccurrence,
48};
49pub use effects::{
50 Acted, ActionItem, ActionItemResult, ActionSettlement, ActionSettlements, Actions, AppendSend,
51 Become, BehaviorSettlements, ClassifySettlement, CreationEvent, CreationSettlement,
52 CreationSettlements, CreationsSettled, InterpretCreations, InterpretItem, InterpretSends,
53 Interpretation, InterpreterFault, InterpreterRequest, InterpreterRequests, ItemSettlement,
54 LogicalDeliveryProtocols, NoReturnToEmitter, NoSends, Own, ParentReportReason, ReportToParent,
55 RetirementCreationSettlement, ReturnsToEmitter, SendEffects, SendInput, SendLayer,
56 SendSettlements, SendsFor, SettledItem, SettlementStatus, SourceAction, SourceActions,
57 SourceAdmission, SourceCustody, SourceSettlementCustody, SourceSettlements, settle_item,
58};
59pub use next::{Never, Step, Stopped};
60pub use transition::{
61 ActiveTurn, Behavior, BehaviorActed, BehaviorAddr, BehaviorBase, BehaviorLayer,
62 BehaviorMessage, InitializationTurn, LogicalHostRequirements, MessageProtocol, Protocol,
63 delegate_transition, initialize,
64};
65pub use user_event::{
66 ChildInputIngress, ComposedEvent, EventIngress, EventLayer, Here, Ingress, InjectEvent, Inside,
67 RecoverEvent, User, UserEvent,
68};
69
70/// Generate the nominal protocol, closed effect products, and exact `Behavior`
71/// wiring for an inherent impl. `addr` and `message` are required. Omitting
72/// `sends`, `births`, or `error` selects the capability-free `NoSends`,
73/// `NoBirths`, or `Never` type respectively.
74///
75/// A `sends = { lane: Product }` declaration generates a module-private
76/// `ActorSends`; `sends = pub { lane: Product }` exports it for a public actor.
77/// Its lane selectors, settlement product, and fluent trait have the same
78/// visibility. Each field contributes its logical-host protocols in declared
79/// order, including duplicates, through [`LogicalDeliveryProtocols`]. The
80/// product also derives structural `SendEffects`, `SendsFor`,
81/// [`SendSettlements`], and `InterpretSends` implementations. The settlement
82/// product keeps the same semantic field names and one runtime-independent
83/// type. The macro also generates an
84/// `ActorActions` extension trait with one fluent `send_lane` method per named
85/// lane. Each method delegates to [`AppendSend`], changing only the send leg
86/// while preserving creations and the exact next-behavior verdict. A
87/// `births = { lane: Child }` declaration generates `ActorChildren` as the
88/// exact closed child algebra. One child remains its direct concrete type;
89/// multiple alternatives form `ChildChoice` in declaration order. The macro
90/// also generates one nominal role per declaration and an `ActorChild`
91/// namespace for those roles. Every role implements both [`ChildRole`] for its
92/// authored parent and [`ChildOccurrence`] for sealed resolution against that
93/// parent or a topology-transparent wrapper. Creation remains an authored
94/// [`Creations`] or [`Children`] value and is never performed by the macro.
95///
96/// Invalid receivers are rejected at compile time.
97/// A birth-owning generated actor must also select the exact creation-settlement
98/// disposition; there is no implicit discard or generated no-op receiver.
99///
100/// ```compile_fail
101/// struct Child;
102/// #[behavior::behavior(addr = behavior::MailAddr, message = behavior::Never)]
103/// impl Child {
104/// fn receive(
105/// &mut self,
106/// _: behavior::MailAddr,
107/// message: behavior::Never,
108/// ) -> behavior::BehaviorActed<Self> {
109/// match message {}
110/// }
111/// }
112/// struct MissingCreationSettlementDisposition;
113/// #[behavior::behavior(
114/// addr = behavior::MailAddr,
115/// message = behavior::Never,
116/// births = { child: Child },
117/// )]
118/// impl MissingCreationSettlementDisposition {
119/// fn receive(
120/// &mut self,
121/// _: behavior::MailAddr,
122/// message: behavior::Never,
123/// ) -> behavior::BehaviorActed<Self> {
124/// match message {}
125/// }
126/// }
127/// ```
128///
129/// ```compile_fail
130///
131/// struct Invalid;
132/// #[behavior::behavior(
133/// addr = behavior::MailAddr,
134/// message = u8,
135/// )]
136/// impl Invalid {
137/// fn init(&self) -> behavior::BehaviorActed<Self> {
138/// Ok(behavior::Actions::cont())
139/// }
140/// fn receive(&mut self, _: behavior::MailAddr, _: u8) -> behavior::BehaviorActed<Self> {
141/// Ok(behavior::Actions::cont())
142/// }
143/// }
144/// ```
145///
146/// Missing receive methods are rejected by the macro itself:
147///
148/// ```compile_fail
149/// struct Missing;
150/// #[behavior::behavior(
151/// addr = behavior::MailAddr,
152/// message = u8,
153/// )]
154/// impl Missing {
155/// }
156/// ```
157///
158/// Async behavior methods cannot introduce an erased or alternate execution
159/// path:
160///
161/// ```compile_fail
162/// struct Async;
163/// #[behavior::behavior(
164/// addr = behavior::MailAddr,
165/// message = u8,
166/// )]
167/// impl Async {
168/// async fn init(&mut self) -> behavior::BehaviorActed<Self> {
169/// Ok(behavior::Actions::cont())
170/// }
171/// fn receive(&mut self, _: behavior::MailAddr, _: u8) -> behavior::BehaviorActed<Self> {
172/// Ok(behavior::Actions::cont())
173/// }
174/// }
175/// ```
176///
177/// Undeclared send lanes have no selector and cannot be emitted:
178///
179/// ```compile_fail
180/// struct Sender;
181/// #[behavior::behavior(addr = behavior::MailAddr, message = (), sends = { replies: Vec<u8> })]
182/// impl Sender {
183/// fn receive(&mut self, _: behavior::MailAddr, _: ()) -> behavior::BehaviorActed<Self> {
184/// let mut sends: SenderSends = behavior::SendEffects::empty();
185/// behavior::SendEffects::send::<_, SenderSendsUndeclared>(&mut sends, 1);
186/// Ok(behavior::Actions::send(sends))
187/// }
188/// }
189/// ```
190///
191/// Generated lane methods accept only inputs supported by that lane:
192///
193/// ```compile_fail
194/// struct Sender;
195/// #[behavior::behavior(addr = behavior::MailAddr, message = (), sends = { replies: Vec<u8> })]
196/// impl Sender {
197/// fn receive(&mut self, _: behavior::MailAddr, _: ()) -> behavior::BehaviorActed<Self> {
198/// Ok(behavior::Actions::cont().send_replies("not a u8"))
199/// }
200/// }
201/// ```
202///
203/// A child absent from the declared closed birth product cannot be created:
204///
205/// ```compile_fail
206/// struct Declared;
207/// #[behavior::behavior(addr = behavior::MailAddr, message = behavior::Never)]
208/// impl Declared {
209/// fn receive(&mut self, _: behavior::MailAddr, message: behavior::Never) -> behavior::BehaviorActed<Self> {
210/// match message {}
211/// }
212/// }
213/// struct Other;
214/// #[behavior::behavior(addr = behavior::MailAddr, message = behavior::Never)]
215/// impl Other {
216/// fn receive(&mut self, _: behavior::MailAddr, message: behavior::Never) -> behavior::BehaviorActed<Self> {
217/// match message {}
218/// }
219/// }
220/// struct Root { creations: behavior::CreationSequence }
221/// #[behavior::behavior(
222/// addr = behavior::MailAddr,
223/// message = (),
224/// births = { declared: Declared },
225/// creation_settlements = retain_for_retirement,
226/// )]
227/// impl Root {
228/// fn receive(&mut self, _: behavior::MailAddr, _: ()) -> behavior::BehaviorActed<Self> {
229/// let id = self.creations.issue().expect("fixture creation ID");
230/// Ok(behavior::Actions::create(behavior::Creations::one(behavior::CreateChild::birth(id, Other))))
231/// }
232/// }
233/// ```
234///
235/// Every generated send lane remains a separate interpreter obligation:
236///
237/// ```compile_fail
238/// struct Root;
239/// type AuditProtocol = behavior::MessageProtocol<behavior::MailAddr, u8>;
240/// type MetricsProtocol = behavior::MessageProtocol<behavior::MailAddr, u16>;
241/// #[behavior::behavior(addr = behavior::MailAddr, message = (), sends = {
242/// audit: Vec<behavior::Delivery<AuditProtocol>>,
243/// metrics: Vec<behavior::Delivery<MetricsProtocol>>,
244/// })]
245/// impl Root {
246/// fn receive(&mut self, _: behavior::MailAddr, _: ()) -> behavior::BehaviorActed<Self> {
247/// Ok(behavior::Actions::cont())
248/// }
249/// }
250/// struct Incomplete;
251/// impl<RootEvent, Path> behavior::InterpretItem<behavior::Delivery<AuditProtocol>, RootEvent, Path> for Incomplete {
252/// fn interpret_item(&mut self, _: behavior::Delivery<AuditProtocol>) -> impl core::future::Future<
253/// Output = behavior::ItemSettlement<behavior::Delivery<AuditProtocol>, (), behavior::Never, behavior::Never>,
254/// > + Send {
255/// async { behavior::ItemSettlement::Accepted(()) }
256/// }
257/// }
258/// fn require_complete()
259/// where
260/// RootSends: behavior::InterpretSends<Incomplete, behavior::User<behavior::MailAddr, ()>, behavior::Here>,
261/// {}
262/// ```
263///
264/// Generated child products likewise require one [`EstablishChild`]
265/// implementation for every declared alternative. [`DispatchBirth`] owns the
266/// compile-denial example so this crate overview does not duplicate it.
267///
268/// Two declared roles remain distinct even when they use the same behavior:
269///
270/// ```compile_fail
271/// struct Worker;
272/// #[behavior::behavior(addr = behavior::MailAddr, message = ())]
273/// impl Worker {
274/// fn receive(&mut self, _: behavior::MailAddr, _: ()) -> behavior::BehaviorActed<Self> {
275/// Ok(behavior::Actions::cont())
276/// }
277/// }
278/// struct Root;
279/// #[behavior::behavior(addr = behavior::MailAddr, message = behavior::Never, births = {
280/// primary: Worker,
281/// backup: Worker,
282/// }, creation_settlements = retain_for_retirement)]
283/// impl Root {
284/// fn receive(&mut self, _: behavior::MailAddr, message: behavior::Never) -> behavior::BehaviorActed<Self> {
285/// match message {}
286/// }
287/// }
288/// fn requires_primary(
289/// _: behavior::ChildDelivery<<Worker as behavior::Behavior>::Protocol, RootChildrenPrimary>,
290/// ) {}
291/// let mut sequence = behavior::CreationSequence::new();
292/// let id = sequence.issue().expect("fixture creation ID");
293/// let backup = behavior::ChildDelivery::<<Worker as behavior::Behavior>::Protocol, RootChildrenBackup>::after(id, ());
294/// requires_primary(backup);
295/// ```
296///
297/// Named topology selectors accept only the child declared for that parent
298/// role, which lets an application builder remain entirely static:
299///
300/// ```compile_fail
301/// struct Worker;
302/// #[behavior::behavior(addr = behavior::MailAddr, message = behavior::Never)]
303/// impl Worker {
304/// fn receive(&mut self, _: behavior::MailAddr, message: behavior::Never) -> behavior::BehaviorActed<Self> {
305/// match message {}
306/// }
307/// }
308/// struct Query;
309/// #[behavior::behavior(addr = behavior::MailAddr, message = behavior::Never)]
310/// impl Query {
311/// fn receive(&mut self, _: behavior::MailAddr, message: behavior::Never) -> behavior::BehaviorActed<Self> {
312/// match message {}
313/// }
314/// }
315/// struct Root;
316/// #[behavior::behavior(
317/// addr = behavior::MailAddr,
318/// message = behavior::Never,
319/// births = { workers: Worker },
320/// creation_settlements = retain_for_retirement,
321/// )]
322/// impl Root {
323/// fn receive(&mut self, _: behavior::MailAddr, message: behavior::Never) -> behavior::BehaviorActed<Self> {
324/// match message {}
325/// }
326/// }
327/// fn child<Parent, Role>(_: Role, _: Role::Child)
328/// where
329/// Parent: behavior::Behavior,
330/// Role: behavior::ChildRole<Parent>,
331/// {}
332/// child::<Root, _>(RootChild::Workers, Query);
333/// ```
334pub use behavior_macros::behavior;