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 trait StashStatus {
18 fn stashed_messages(&self) -> usize;
19}
20
21pub struct Stash<B: Behavior> {
22 inner: B,
23 route: fn(&B::Msg) -> StashRoute,
24 held: VecDeque<User<B::Addr, B::Msg>>,
25}
26
27impl<B: Behavior<Ph = Never>> Stash<B> {
28 #[must_use]
29 pub(crate) fn new(inner: B, route: fn(&B::Msg) -> StashRoute) -> Self {
30 Self {
31 inner,
32 route,
33 held: VecDeque::new(),
34 }
35 }
36
37 #[must_use]
38 pub fn held(&self) -> usize {
39 self.held.len()
40 }
41}
42
43impl<B: Behavior<Ph = Never>> StashStatus for Stash<B> {
44 fn stashed_messages(&self) -> usize {
45 self.held()
46 }
47}
48
49impl<B> crate::BehaviorBase for Stash<B>
50where
51 B: Behavior<Ph = Never> + crate::BehaviorBase,
52{
53 type Base = B::Base;
54
55 fn base(&self) -> &Self::Base {
56 self.inner.base()
57 }
58}
59
60impl<B, A, Sends, Br> Stash<B>
61where
62 A: Address,
63 Sends: SendAlgebra,
64 Br: BirthMode,
65 B: Behavior<Addr = A, Ph = Never, Sends = Sends, Birth = Br>,
66{
67 fn drain_into(
68 &mut self,
69 acc: &mut Actions<B::Addr, Never, B::Sends, B::Birth>,
70 ) -> Result<(), B::Error> {
71 let mut batch: VecDeque<_> = self.held.drain(..).collect();
72 while let Some(user) = batch.pop_front() {
73 match (self.route)(&user.message) {
74 StashRoute::Stash => self.held.push_back(user),
75 StashRoute::Deliver | StashRoute::Release => {
76 let actions = crate::calculus::delegate_transition(
77 &mut self.inner,
78 B::Event::user(user.from, user.message),
79 )?;
80 acc.sends.append(actions.sends);
81 acc.creates.extend(actions.creates);
82 if let Step::Stop(exit) = actions.become_ {
83 self.held.extend(batch);
84 acc.become_ = Step::Stop(exit);
85 return Ok(());
86 }
87 }
88 }
89 }
90 Ok(())
91 }
92}
93
94impl<B, A, Sends, Br> Behavior for Stash<B>
95where
96 A: Address,
97 Sends: SendAlgebra,
98 Br: BirthMode,
99 B: Behavior<Addr = A, Ph = Never, Sends = Sends, Birth = Br>,
100{
101 type Addr = A;
102 type Msg = B::Msg;
103 type Event = B::Event;
104 type Sends = Sends;
105 type Ph = Never;
106 type Error = B::Error;
107 type Birth = Br;
108
109 fn init(
110 &mut self,
111 _: crate::InitializationTurn,
112 ) -> Result<Actions<A, Never, Sends, Br>, B::Error> {
113 crate::calculus::initialize(&mut self.inner)
114 }
115
116 fn transition(
117 &mut self,
118 _: crate::ActiveTurn,
119 event: B::Event,
120 ) -> Result<Actions<A, Never, Sends, Br>, B::Error> {
121 let user = match event.into_user() {
122 Ok(user) => user,
123 Err(other) => return crate::calculus::delegate_transition(&mut self.inner, other),
124 };
125 match (self.route)(&user.message) {
126 StashRoute::Stash => {
127 self.held.push_back(user);
128 Ok(Actions::cont())
129 }
130 StashRoute::Deliver => crate::calculus::delegate_transition(
131 &mut self.inner,
132 B::Event::user(user.from, user.message),
133 ),
134 StashRoute::Release => {
135 let mut actions = crate::calculus::delegate_transition(
136 &mut self.inner,
137 B::Event::user(user.from, user.message),
138 )?;
139 if !matches!(actions.become_, Step::Stop(_)) {
140 self.drain_into(&mut actions)?;
141 }
142 Ok(actions)
143 }
144 }
145 }
146}