1use std::collections::VecDeque;
4
5use behavior::{Actions, Address, Behavior, BirthMode, SendEffects, User, UserEvent};
6use behavior::{Never, Step};
7
8mod sealed {
9 pub trait StaticallyInfallible {}
10}
11
12pub trait StaticallyInfallible: sealed::StaticallyInfallible {}
18
19impl sealed::StaticallyInfallible for Never {}
20impl StaticallyInfallible for Never {}
21
22impl<A, M> sealed::StaticallyInfallible for crate::MachineError<A, M, Never> {}
23impl<A, M> StaticallyInfallible for crate::MachineError<A, M, Never> {}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum StashRoute {
27 Stash,
28 Deliver,
29 Release,
30}
31
32pub trait StashStatus {
35 fn stashed_messages(&self) -> usize;
36}
37
38pub struct Stash<B: Behavior> {
65 inner: B,
66 route: fn(&B, &behavior::BehaviorMessage<B>) -> StashRoute,
67 held: VecDeque<User<behavior::BehaviorAddr<B>, behavior::BehaviorMessage<B>>>,
68}
69
70impl<B: Behavior<Ph = Never>> Stash<B> {
71 #[must_use]
79 pub fn new(inner: B, route: fn(&B, &behavior::BehaviorMessage<B>) -> StashRoute) -> Self {
80 Self {
81 inner,
82 route,
83 held: VecDeque::new(),
84 }
85 }
86
87 #[must_use]
88 pub fn held(&self) -> usize {
89 self.held.len()
90 }
91}
92
93impl<B: Behavior<Ph = Never>> StashStatus for Stash<B> {
94 fn stashed_messages(&self) -> usize {
95 self.held()
96 }
97}
98
99impl<B> behavior::BehaviorBase for Stash<B>
100where
101 B: Behavior<Ph = Never> + behavior::BehaviorBase,
102{
103 type Base = B::Base;
104
105 fn base(&self) -> &Self::Base {
106 self.inner.base()
107 }
108}
109
110impl<B, A, Sends, Br> Stash<B>
111where
112 A: Address,
113 Sends: SendEffects + behavior::SendsFor<B::Event>,
114 Br: BirthMode,
115 B: Behavior<Ph = Never, Sends = Sends, Birth = Br>,
116 B::Error: StaticallyInfallible,
117 B::Protocol: behavior::Protocol<Addr = A>,
118{
119 fn drain_into(
120 &mut self,
121 acc: &mut Actions<behavior::BehaviorAddr<B>, Never, B::Sends, B::Birth>,
122 ) -> Result<(), B::Error> {
123 let mut batch = core::mem::take(&mut self.held);
124 while let Some(user) = batch.pop_front() {
125 match (self.route)(&self.inner, &user.message) {
126 StashRoute::Stash => self.held.push_back(user),
127 StashRoute::Deliver | StashRoute::Release => {
128 let actions = behavior::delegate_transition(
129 &mut self.inner,
130 B::Event::user(user.from, user.message),
131 )?;
132 acc.sends.append(actions.sends);
133 acc.creates.extend(actions.creates);
134 if let Step::Stop(exit) = actions.become_ {
135 self.held.extend(batch);
136 acc.become_ = Step::Stop(exit);
137 return Ok(());
138 }
139 }
140 }
141 }
142 Ok(())
143 }
144}
145
146impl<B, A, Sends, Br> Behavior for Stash<B>
147where
148 A: Address,
149 Sends: SendEffects + behavior::SendsFor<B::Event>,
150 Br: BirthMode,
151 B: Behavior<Ph = Never, Sends = Sends, Birth = Br>,
152 B::Error: StaticallyInfallible,
153 B::Protocol: behavior::Protocol<Addr = A>,
154{
155 type Protocol = B::Protocol;
156 type Event = B::Event;
157 type Sends = Sends;
158 type Ph = Never;
159 type Error = B::Error;
160 type Birth = Br;
161
162 fn init(
163 &mut self,
164 _: behavior::InitializationTurn,
165 ) -> Result<Actions<A, Never, Sends, Br>, Self::Error> {
166 behavior::initialize(&mut self.inner)
167 }
168
169 fn transition(
170 &mut self,
171 _: behavior::ActiveTurn,
172 event: B::Event,
173 ) -> Result<Actions<A, Never, Sends, Br>, Self::Error> {
174 let user = match event.into_user() {
175 Ok(user) => user,
176 Err(other) => return behavior::delegate_transition(&mut self.inner, other),
177 };
178 match (self.route)(&self.inner, &user.message) {
179 StashRoute::Stash => {
180 self.held.push_back(user);
181 Ok(Actions::cont())
182 }
183 StashRoute::Deliver => behavior::delegate_transition(
184 &mut self.inner,
185 B::Event::user(user.from, user.message),
186 ),
187 StashRoute::Release => {
188 let mut actions = behavior::delegate_transition(
189 &mut self.inner,
190 B::Event::user(user.from, user.message),
191 )?;
192 if !matches!(actions.become_, Step::Stop(_)) {
193 self.drain_into(&mut actions)?;
194 }
195 Ok(actions)
196 }
197 }
198 }
199}