proxima_primitives/pipe/
alloc_tier.rs1use alloc::boxed::Box;
16use alloc::rc::Rc;
17use alloc::sync::Arc;
18use core::future::Future;
19use core::pin::Pin;
20
21use proxima_core::ProximaError;
22
23use crate::pipe::primitives::{Pipe, SendPipe};
24
25pub type BoxFuture<'a, Output> = Pin<Box<dyn Future<Output = Output> + 'a>>;
27
28pub type SendBoxFuture<'a, Output> = Pin<Box<dyn Future<Output = Output> + Send + 'a>>;
30
31pub trait DynPipe<In, Out> {
35 fn call_dyn(&self, input: In) -> BoxFuture<'_, Result<Out, ProximaError>>;
38}
39
40impl<P> DynPipe<P::In, P::Out> for P
41where
42 P: Pipe,
43 ProximaError: From<P::Err>,
44{
45 fn call_dyn(&self, input: P::In) -> BoxFuture<'_, Result<P::Out, ProximaError>> {
46 Box::pin(async move { self.call(input).await.map_err(ProximaError::from) })
47 }
48}
49
50pub type LocalPipeHandle<In, Out> = Rc<dyn DynPipe<In, Out>>;
52
53pub fn into_local_handle<P>(pipe: P) -> LocalPipeHandle<P::In, P::Out>
55where
56 P: Pipe + 'static,
57 ProximaError: From<P::Err>,
58{
59 Rc::new(pipe)
60}
61
62pub trait SendDynPipe<In, Out>: Send + Sync {
66 fn call_dyn(&self, input: In) -> SendBoxFuture<'_, Result<Out, ProximaError>>;
69}
70
71impl<P> SendDynPipe<P::In, P::Out> for P
72where
73 P: SendPipe,
74 P::In: Send,
75 ProximaError: From<P::Err>,
76{
77 fn call_dyn(&self, input: P::In) -> SendBoxFuture<'_, Result<P::Out, ProximaError>> {
78 Box::pin(async move { self.call(input).await.map_err(ProximaError::from) })
79 }
80}
81
82pub type PipeHandle<In, Out> = Arc<dyn SendDynPipe<In, Out>>;
84
85pub fn into_handle<P>(pipe: P) -> PipeHandle<P::In, P::Out>
87where
88 P: SendPipe,
89 P::In: Send,
90 ProximaError: From<P::Err>,
91{
92 Arc::new(pipe)
93}
94
95impl<In: 'static, Out: 'static> SendPipe for dyn SendDynPipe<In, Out> {
102 type In = In;
103 type Out = Out;
104 type Err = ProximaError;
105
106 fn call(&self, input: In) -> impl Future<Output = Result<Out, ProximaError>> + Send {
107 self.call_dyn(input)
108 }
109}
110
111impl<In: 'static, Out: 'static> Pipe for dyn SendDynPipe<In, Out> {
116 type In = In;
117 type Out = Out;
118 type Err = ProximaError;
119
120 fn call(&self, input: In) -> impl Future<Output = Result<Out, ProximaError>> {
121 self.call_dyn(input)
122 }
123}
124
125impl<In, Out> Pipe for dyn DynPipe<In, Out> {
126 type In = In;
127 type Out = Out;
128 type Err = ProximaError;
129
130 fn call(&self, input: In) -> impl Future<Output = Result<Out, ProximaError>> {
131 self.call_dyn(input)
132 }
133}
134
135impl<Inner> SendPipe for Arc<Inner>
140where
141 Inner: SendPipe + ?Sized,
142{
143 type In = Inner::In;
144 type Out = Inner::Out;
145 type Err = Inner::Err;
146
147 fn call(
148 &self,
149 input: Self::In,
150 ) -> impl core::future::Future<Output = Result<Self::Out, Self::Err>> + Send {
151 Inner::call(self, input)
152 }
153}
154
155impl<Inner> Pipe for Arc<Inner>
156where
157 Inner: Pipe + ?Sized,
158{
159 type In = Inner::In;
160 type Out = Inner::Out;
161 type Err = Inner::Err;
162
163 fn call(
164 &self,
165 input: Self::In,
166 ) -> impl core::future::Future<Output = Result<Self::Out, Self::Err>> {
167 Inner::call(self, input)
168 }
169}
170
171impl<Inner> Pipe for Rc<Inner>
172where
173 Inner: Pipe + ?Sized,
174{
175 type In = Inner::In;
176 type Out = Inner::Out;
177 type Err = Inner::Err;
178
179 fn call(
180 &self,
181 input: Self::In,
182 ) -> impl core::future::Future<Output = Result<Self::Out, Self::Err>> {
183 Inner::call(self, input)
184 }
185}
186
187#[cfg(test)]
188#[allow(clippy::unwrap_used, clippy::expect_used)]
189mod tests {
190 use super::{SendDynPipe, into_handle, into_local_handle};
191 use crate::block_on;
192 use crate::pipe::primitives::{Pipe, SendPipe};
193 use core::future::Future;
194
195 struct Tagger(u64);
199
200 impl Pipe for Tagger {
201 type In = u64;
202 type Out = u64;
203 type Err = proxima_core::ProximaError;
204
205 fn call(
206 &self,
207 input: u64,
208 ) -> impl Future<Output = Result<u64, proxima_core::ProximaError>> {
209 let tag = self.0;
210 async move { Ok(input + tag) }
211 }
212 }
213
214 impl SendPipe for Tagger {
215 type In = u64;
216 type Out = u64;
217 type Err = proxima_core::ProximaError;
218
219 fn call(
220 &self,
221 input: u64,
222 ) -> impl Future<Output = Result<u64, proxima_core::ProximaError>> + Send {
223 let tag = self.0;
224 async move { Ok(input + tag) }
225 }
226 }
227
228 #[test]
229 fn local_handle_erases_a_no_send_pipe() {
230 let handle = into_local_handle(Tagger(10));
231 let out = block_on(handle.call_dyn(5)).expect("erased local dispatch");
232 assert_eq!(out, 15);
233 }
234
235 #[test]
236 fn send_handle_erases_a_cross_core_pipe() {
237 let handle = into_handle(Tagger(100));
238 let out =
239 block_on(SendDynPipe::call_dyn(handle.as_ref(), 5)).expect("erased send dispatch");
240 assert_eq!(out, 105);
241 }
242
243 fn assert_send_sync<Type: Send + Sync>(_: &Type) {}
244
245 #[test]
246 fn send_handle_is_send_and_sync() {
247 let handle = into_handle(Tagger(1));
248 assert_send_sync(&handle);
249 }
250}