Skip to main content

behavior/effects/
sending.rs

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