Skip to main content

behavior/
stash.rs

1//! Pure message holding and replay composition.
2
3use 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}