behavior_actors/activation.rs
1//! Direct, consuming behavior activation.
2
3use behavior::Actions;
4use behavior::Behavior;
5use behavior::BehaviorBase;
6use behavior::{BehaviorActed, Here, InjectEvent, UserEvent, delegate_transition};
7
8/// An initialized behavior and the effects that must be interpreted before
9/// its first mailbox turn.
10pub struct Initialized<B: Behavior> {
11 /// The activated behavior; only this value can fold mailbox events.
12 pub behavior: Active<B>,
13 /// Ordered initialization effects that the Driver interprets before the
14 /// first mailbox event.
15 pub actions: Actions<behavior::BehaviorAddr<B>, B::Ph, B::Sends, B::Birth>,
16}
17
18/// A behavior whose initialization fold has completed exactly once.
19///
20/// `Active<B>` does not implement [`Behavior`], so initialization cannot be
21/// repeated through the public API:
22///
23/// ```compile_fail
24/// let definition = behavior_actors::Machine::<behavior::MailAddr, _, _, _, behavior::Never>::new(
25/// (),
26/// (),
27/// |_, _, _| Ok(behavior_actors::Move::Stay),
28/// );
29/// let active = behavior_actors::Activate::initialize(definition).unwrap().behavior;
30/// behavior_actors::Activate::initialize(active);
31/// ```
32pub struct Active<B: Behavior> {
33 pub(crate) behavior: B,
34}
35
36impl<B: Behavior> Active<B> {
37 /// Inspect the authored base behavior through any wrapper depth.
38 #[must_use]
39 pub fn base(&self) -> &B::Base
40 where
41 B: BehaviorBase,
42 {
43 self.behavior.base()
44 }
45
46 /// Return the number of messages held by a composed stash layer.
47 #[must_use]
48 pub fn stashed(&self) -> usize
49 where
50 B: crate::StashStatus,
51 {
52 self.behavior.stashed_messages()
53 }
54
55 /// Fold exactly one event after initialization.
56 ///
57 /// # Errors
58 ///
59 /// Returns the behavior's declared controlled transition failure.
60 pub fn transition(&mut self, event: B::Event) -> BehaviorActed<B> {
61 delegate_transition(&mut self.behavior, event)
62 }
63
64 /// Fold one user communication after initialization.
65 ///
66 /// # Errors
67 ///
68 /// Returns the behavior's declared controlled transition failure.
69 pub fn receive(
70 &mut self,
71 from: behavior::BehaviorAddr<B>,
72 message: behavior::BehaviorMessage<B>,
73 ) -> BehaviorActed<B> {
74 self.transition(B::Event::user(from, message))
75 }
76
77 /// Fold one statically supported semantic input after initialization.
78 ///
79 /// # Errors
80 ///
81 /// Returns the behavior's declared controlled transition failure.
82 pub fn on<Input>(&mut self, input: Input) -> BehaviorActed<B>
83 where
84 B::Event: InjectEvent<Input, Here>,
85 {
86 self.transition(B::Event::inject_at(input))
87 }
88
89 /// Fold one semantic input through an explicitly proven structural path.
90 pub fn on_path<Input, Path>(&mut self, input: Input) -> BehaviorActed<B>
91 where
92 B::Event: InjectEvent<Input, Path>,
93 {
94 self.transition(B::Event::inject_at(input))
95 }
96}
97
98impl<B: Behavior> core::ops::Deref for Active<B> {
99 type Target = B;
100
101 fn deref(&self) -> &Self::Target {
102 &self.behavior
103 }
104}
105
106/// Consuming initialization for any concrete behavior definition.
107///
108/// This trait makes standalone catalogue templates directly usable without a
109/// wrapper construction. Initialization is a lifecycle transition, not a
110/// wrapper transformation.
111///
112/// A raw definition cannot use the active mailbox API:
113///
114/// ```compile_fail
115/// let mut definition = behavior_actors::Machine::<behavior::MailAddr, _, _, _, behavior::Never>::new(
116/// (),
117/// (),
118/// |_, _, _| Ok(behavior_actors::Move::Stay),
119/// );
120/// definition.receive(behavior::MailAddr(0), 1_u8);
121/// ```
122pub trait Activate: Behavior + Sized {
123 /// Consume this definition, perform its one initialization fold, and
124 /// return the active behavior together with the ordered initialization
125 /// effects.
126 ///
127 /// # Errors
128 ///
129 /// Returns the behavior's controlled initialization failure. A failed
130 /// definition is consumed and cannot be activated or retried.
131 fn initialize(self) -> Result<Initialized<Self>, Self::Error> {
132 let mut behavior = self;
133 let actions = behavior::initialize(&mut behavior)?;
134 Ok(Initialized {
135 behavior: Active { behavior },
136 actions,
137 })
138 }
139}
140
141impl<B: Behavior> Activate for B {}