Skip to main content

behavior/effects/
sending.rs

1//! Typed send products and their accumulation contract.
2
3/// The lane owned by the current named send product.
4pub enum Own {}
5
6/// Static evidence that a send algebra contains one request lane.
7///
8/// Implementations append the input exactly once to that lane and leave every
9/// other lane unchanged. `Path` distinguishes repeated request types without
10/// erasing their position or choosing a lane at runtime.
11///
12/// [`Own`] selects a named product's own semantic lane. Composed behavior
13/// lanes are accessed through that product's named `behavior` field; Bombay
14/// deliberately has no positional path language for nested products.
15pub trait SendInput<Input, Path> {
16    fn emit(&mut self, input: Input);
17}
18
19/// The operation required to accumulate sends across transitions.
20pub trait SendAlgebra: Sized {
21    fn empty() -> Self;
22    fn append(&mut self, other: Self);
23
24    #[must_use]
25    fn combine(mut self, other: Self) -> Self {
26        self.append(other);
27        self
28    }
29
30    /// Append one request to its statically selected semantic lane.
31    fn send<Input, Path>(&mut self, input: Input)
32    where
33        Self: SendInput<Input, Path>,
34    {
35        <Self as SendInput<Input, Path>>::emit(self, input);
36    }
37
38    /// Build a send product containing one request in its selected lane.
39    #[must_use]
40    fn sending<Input, Path>(input: Input) -> Self
41    where
42        Self: SendInput<Input, Path>,
43    {
44        let mut sends = Self::empty();
45        sends.send(input);
46        sends
47    }
48}
49
50impl<T> SendAlgebra for Vec<T> {
51    fn empty() -> Self {
52        Vec::new()
53    }
54
55    fn append(&mut self, mut other: Self) {
56        Vec::append(self, &mut other);
57    }
58}
59
60impl<T> SendInput<T, Own> for Vec<T> {
61    fn emit(&mut self, input: T) {
62        self.push(input);
63    }
64}
65
66/// Requests interpreted by the runtime local to the emitting actor.
67///
68/// Unlike [`crate::Delivery`], a service request has no actor address. Its
69/// recipient is definitionally the interpreter of the actor whose transition
70/// emitted it. This distinct send lane lets interpreters route ordinary
71/// deliveries and local services with disjoint static implementations.
72#[derive(Debug, Clone, PartialEq, Eq)]
73pub struct ServiceSends<M> {
74    requests: Vec<M>,
75}
76
77impl<M> ServiceSends<M> {
78    #[must_use]
79    pub fn new(requests: Vec<M>) -> Self {
80        Self { requests }
81    }
82    #[must_use]
83    pub fn one(request: M) -> Self {
84        Self::new(vec![request])
85    }
86    #[must_use]
87    pub fn as_slice(&self) -> &[M] {
88        &self.requests
89    }
90    pub fn iter(&self) -> core::slice::Iter<'_, M> {
91        self.requests.iter()
92    }
93    #[must_use]
94    pub fn len(&self) -> usize {
95        self.requests.len()
96    }
97    #[must_use]
98    pub fn is_empty(&self) -> bool {
99        self.requests.is_empty()
100    }
101    pub fn extend(&mut self, requests: impl IntoIterator<Item = M>) {
102        self.requests.extend(requests);
103    }
104    #[must_use]
105    pub fn into_requests(self) -> Vec<M> {
106        self.requests
107    }
108}
109
110impl<M> core::ops::Index<usize> for ServiceSends<M> {
111    type Output = M;
112    fn index(&self, index: usize) -> &Self::Output {
113        &self.requests[index]
114    }
115}
116
117impl<M> IntoIterator for ServiceSends<M> {
118    type Item = M;
119    type IntoIter = std::vec::IntoIter<M>;
120    fn into_iter(self) -> Self::IntoIter {
121        self.requests.into_iter()
122    }
123}
124
125impl<'a, M> IntoIterator for &'a ServiceSends<M> {
126    type Item = &'a M;
127    type IntoIter = core::slice::Iter<'a, M>;
128    fn into_iter(self) -> Self::IntoIter {
129        self.requests.iter()
130    }
131}
132
133impl<M> SendAlgebra for ServiceSends<M> {
134    fn empty() -> Self {
135        Self::new(Vec::new())
136    }
137    fn append(&mut self, mut other: Self) {
138        self.requests.append(&mut other.requests);
139    }
140}
141
142impl<M> SendInput<M, Own> for ServiceSends<M> {
143    fn emit(&mut self, input: M) {
144        self.requests.push(input);
145    }
146}
147
148#[cfg(test)]
149mod tests {
150    use super::*;
151
152    #[test]
153    fn send_algebra_obeys_identity_and_associativity() {
154        let values = vec![1, 2];
155        assert_eq!(Vec::new().combine(values.clone()), values);
156        assert_eq!(values.clone().combine(Vec::new()), values);
157
158        let left = vec![1].combine(vec![2]).combine(vec![3]);
159        let right = vec![1].combine(vec![2].combine(vec![3]));
160        assert_eq!(left, right);
161    }
162}