Skip to main content

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 {}