1use std::collections::VecDeque;
4
5use crate::behavior::{Actions, Address, Behavior, BirthMode, SendAlgebra, User, UserEvent};
6use crate::next::{Never, Step};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum StashRoute {
10 Stash,
11 Deliver,
12 Release,
13}
14
15pub struct Stash<B: Behavior> {
16 inner: B,
17 route: fn(&B::Msg) -> StashRoute,
18 held: VecDeque<User<B::Addr, B::Msg>>,
19}
20
21impl<B: Behavior<Ph = Never>> Stash<B> {
22 #[must_use]
23 pub fn new(inner: B, route: fn(&B::Msg) -> StashRoute) -> Self {
24 Self {
25 inner,
26 route,
27 held: VecDeque::new(),
28 }
29 }
30
31 #[must_use]
32 pub fn inner(&self) -> &B {
33 &self.inner
34 }
35
36 #[must_use]
37 pub fn held(&self) -> usize {
38 self.held.len()
39 }
40}
41
42impl<B, A, Sends, Br> Stash<B>
43where
44 A: Address,
45 Sends: SendAlgebra,
46 Br: BirthMode,
47 B: Behavior<Addr = A, Ph = Never, Sends = Sends, Birth = Br>,
48{
49 fn drain_into(
50 &mut self,
51 acc: &mut Actions<B::Addr, Never, B::Sends, B::Birth>,
52 ) -> Result<(), B::Error> {
53 let mut batch: VecDeque<_> = self.held.drain(..).collect();
54 while let Some(user) = batch.pop_front() {
55 match (self.route)(&user.message) {
56 StashRoute::Stash => self.held.push_back(user),
57 StashRoute::Deliver | StashRoute::Release => {
58 let actions = self
59 .inner
60 .transition(B::Event::user(user.from, user.message))?;
61 acc.sends.append(actions.sends);
62 acc.creates.extend(actions.creates);
63 if let Step::Stop(exit) = actions.become_ {
64 self.held.extend(batch);
65 acc.become_ = Step::Stop(exit);
66 return Ok(());
67 }
68 }
69 }
70 }
71 Ok(())
72 }
73}
74
75impl<B, A, Sends, Br> Behavior for Stash<B>
76where
77 A: Address,
78 Sends: SendAlgebra,
79 Br: BirthMode,
80 B: Behavior<Addr = A, Ph = Never, Sends = Sends, Birth = Br>,
81{
82 type Addr = A;
83 type Msg = B::Msg;
84 type Event = B::Event;
85 type Sends = Sends;
86 type Ph = Never;
87 type Error = B::Error;
88 type Birth = Br;
89
90 fn init(&mut self) -> Result<Actions<A, Never, Sends, Br>, B::Error> {
91 self.inner.init()
92 }
93
94 fn transition(&mut self, event: B::Event) -> Result<Actions<A, Never, Sends, Br>, B::Error> {
95 let user = match event.into_user() {
96 Ok(user) => user,
97 Err(other) => return self.inner.transition(other),
98 };
99 match (self.route)(&user.message) {
100 StashRoute::Stash => {
101 self.held.push_back(user);
102 Ok(Actions::cont())
103 }
104 StashRoute::Deliver => self
105 .inner
106 .transition(B::Event::user(user.from, user.message)),
107 StashRoute::Release => {
108 let mut actions = self
109 .inner
110 .transition(B::Event::user(user.from, user.message))?;
111 if !matches!(actions.become_, Step::Stop(_)) {
112 self.drain_into(&mut actions)?;
113 }
114 Ok(actions)
115 }
116 }
117 }
118}