1use core::future::Future;
4use core::mem;
5use core::pin::pin;
6use core::time::Duration;
7
8use anyhow::Context as _;
9use bytes::{Bytes, BytesMut};
10use futures::TryStreamExt as _;
11use tokio::io::AsyncWriteExt as _;
12use tokio::{select, try_join};
13use tokio_util::codec::{Encoder as _, FramedRead};
14use tracing::{Instrument as _, debug, instrument, trace};
15
16use crate::frame::{Incoming, Outgoing};
17use crate::{BufferedIncoming, Deferred as _, TupleDecode, TupleEncode};
18
19pub trait Invoke: Send + Sync {
25 type Context: Send + Sync;
27
28 fn invoke<P>(
30 &self,
31 cx: Self::Context,
32 instance: &str,
33 func: &str,
34 params: Bytes,
35 paths: impl AsRef<[P]> + Send,
36 ) -> impl Future<Output = anyhow::Result<(Outgoing, Incoming)>> + Send
37 where
38 P: AsRef<[Option<usize>]> + Send + Sync;
39}
40
41#[derive(Clone, Copy, Debug, Eq, PartialEq)]
43pub struct Timeout<'a, T: ?Sized> {
44 pub inner: &'a T,
46 pub timeout: Duration,
48}
49
50impl<T: Invoke> Invoke for Timeout<'_, T> {
51 type Context = T::Context;
52
53 #[instrument(level = "trace", skip(self, cx, params, paths))]
54 async fn invoke<P>(
55 &self,
56 cx: Self::Context,
57 instance: &str,
58 func: &str,
59 params: Bytes,
60 paths: impl AsRef<[P]> + Send,
61 ) -> anyhow::Result<(Outgoing, Incoming)>
62 where
63 P: AsRef<[Option<usize>]> + Send + Sync,
64 {
65 tokio::time::timeout(
66 self.timeout,
67 self.inner.invoke(cx, instance, func, params, paths),
68 )
69 .await
70 .context("invocation timed out")?
71 }
72}
73
74#[derive(Clone, Copy, Debug, Eq, PartialEq)]
76pub struct TimeoutOwned<T> {
77 pub inner: T,
79 pub timeout: Duration,
81}
82
83impl<T: Invoke> Invoke for TimeoutOwned<T> {
84 type Context = T::Context;
85
86 #[instrument(level = "trace", skip(self, cx, params, paths))]
87 async fn invoke<P>(
88 &self,
89 cx: Self::Context,
90 instance: &str,
91 func: &str,
92 params: Bytes,
93 paths: impl AsRef<[P]> + Send,
94 ) -> anyhow::Result<(Outgoing, Incoming)>
95 where
96 P: AsRef<[Option<usize>]> + Send + Sync,
97 {
98 self.inner
99 .timeout(self.timeout)
100 .invoke(cx, instance, func, params, paths)
101 .await
102 }
103}
104
105pub trait InvokeExt: Invoke {
107 #[instrument(level = "trace", skip(self, cx, params, paths))]
109 fn invoke_values<P, Params, Results, Paths>(
110 &self,
111 cx: Self::Context,
112 instance: &str,
113 func: &str,
114 params: Params,
115 paths: Paths,
116 ) -> impl Future<
117 Output = anyhow::Result<(
118 Results,
119 Option<
120 impl Future<Output = anyhow::Result<()>>
121 + Send
122 + 'static
123 + use<Self, P, Params, Results, Paths>,
124 >,
125 )>,
126 > + Send
127 where
128 Paths: AsRef<[P]> + Send,
129 P: AsRef<[Option<usize>]> + Send + Sync,
130 Params: TupleEncode + Send,
131 Results: TupleDecode + Send,
132 <Params::Encoder as tokio_util::codec::Encoder<Params>>::Error:
133 std::error::Error + Send + Sync + 'static,
134 <Results::Decoder as tokio_util::codec::Decoder>::Error:
135 std::error::Error + Send + Sync + 'static,
136 {
137 async {
138 let mut buf = BytesMut::default();
139 let mut enc = Params::Encoder::default();
140 trace!("encoding parameters");
141 enc.encode(params, &mut buf)
142 .context("failed to encode parameters")?;
143 debug!("invoking function");
144 let (mut outgoing, incoming) = self
145 .invoke(cx, instance, func, buf.freeze(), paths)
146 .await
147 .context("failed to invoke function")?;
148 trace!("shutdown synchronous parameter channel");
149 outgoing
150 .shutdown()
151 .await
152 .context("failed to shutdown synchronous parameter channel")?;
153 let mut tx = enc.take_deferred().map(|tx| {
154 tokio::spawn(
155 async {
156 debug!("transmitting async parameters");
157 tx(outgoing, Vec::default())
158 .await
159 .context("failed to write async parameters")
160 }
161 .in_current_span(),
162 )
163 });
164
165 let mut dec = FramedRead::new(incoming, Results::Decoder::default());
166 let results = async {
167 debug!("receiving sync results");
168 dec.try_next()
169 .await
170 .context("failed to receive sync results")?
171 .context("incomplete results")
172 };
173 let results = match tx.take() {
174 Some(mut fut) => {
175 let mut results = pin!(results);
176 select! {
177 res = &mut results => {
178 tx = Some(fut);
179 res?
180 }
181 res = &mut fut => {
182 res??;
183 results.await?
184 }
185 }
186 }
187 _ => results.await?,
188 };
189 trace!("received sync results");
190 let buffer = mem::take(dec.read_buffer_mut());
191 let rx = dec.decoder_mut().take_deferred();
192 let incoming = BufferedIncoming {
193 buffer,
194 inner: dec.into_inner(),
195 };
196 Ok((
197 results,
198 (tx.is_some() || rx.is_some()).then_some(
199 async {
200 match (tx, rx) {
201 (Some(tx), Some(rx)) => {
202 try_join!(
203 async {
204 debug!("receiving async results");
205 rx(incoming, Vec::default())
206 .await
207 .context("receiving async results failed")
208 },
209 async {
210 tx.await.context("transmitting async parameters failed")?
211 }
212 )?;
213 }
214 (Some(tx), None) => {
215 tx.await.context("transmitting async parameters failed")??;
216 }
217 (None, Some(rx)) => {
218 debug!("receiving async results");
219 rx(incoming, Vec::default())
220 .await
221 .context("receiving async results failed")?;
222 }
223 _ => {}
224 }
225 Ok(())
226 }
227 .in_current_span(),
228 ),
229 ))
230 }
231 }
232
233 #[instrument(level = "trace", skip_all)]
236 fn invoke_values_blocking<P, Params, Results>(
237 &self,
238 cx: Self::Context,
239 instance: &str,
240 func: &str,
241 params: Params,
242 paths: impl AsRef<[P]> + Send,
243 ) -> impl Future<Output = anyhow::Result<Results>> + Send
244 where
245 P: AsRef<[Option<usize>]> + Send + Sync,
246 Params: TupleEncode + Send,
247 Results: TupleDecode + Send,
248 <Params::Encoder as tokio_util::codec::Encoder<Params>>::Error:
249 std::error::Error + Send + Sync + 'static,
250 <Results::Decoder as tokio_util::codec::Decoder>::Error:
251 std::error::Error + Send + Sync + 'static,
252 {
253 async {
254 let (ret, io) = self
255 .invoke_values(cx, instance, func, params, paths)
256 .await?;
257 if let Some(io) = io {
258 trace!("awaiting I/O completion");
259 io.await?;
260 }
261 Ok(ret)
262 }
263 }
264
265 fn timeout(&self, timeout: Duration) -> Timeout<'_, Self> {
268 Timeout {
269 inner: self,
270 timeout,
271 }
272 }
273
274 fn timeout_owned(self, timeout: Duration) -> TimeoutOwned<Self>
276 where
277 Self: Sized,
278 {
279 TimeoutOwned {
280 inner: self,
281 timeout,
282 }
283 }
284}
285
286impl<T: Invoke> InvokeExt for T {}
287
288#[allow(dead_code)]
289#[cfg(test)]
290mod tests {
291 use core::future::Future;
292 use core::pin::Pin;
293
294 use std::sync::Arc;
295
296 use bytes::Bytes;
297 use futures::{Stream, StreamExt as _};
298
299 use super::*;
300
301 #[allow(clippy::manual_async_fn)]
302 fn invoke_values_send<T>() -> impl Future<
303 Output = anyhow::Result<(
304 Pin<Box<dyn Stream<Item = Vec<Pin<Box<dyn Future<Output = String> + Send>>>> + Send>>,
305 )>,
306 > + Send
307 where
308 T: Invoke<Context = ()> + Default,
309 {
310 async {
311 let wrpc = T::default();
312 let ((r0,), _) = wrpc
313 .invoke_values(
314 (),
315 "wrpc-test:integration/async",
316 "with-streams",
317 (),
318 [[None].as_slice()],
319 )
320 .await?;
321 Ok(r0)
322 }
323 }
324
325 async fn call_invoke<T: Invoke>(
326 i: &T,
327 cx: T::Context,
328 paths: Arc<[Arc<[Option<usize>]>]>,
329 ) -> anyhow::Result<(Outgoing, Incoming)> {
330 i.invoke(cx, "foo", "bar", Bytes::default(), &paths).await
331 }
332
333 async fn call_invoke_async<T>() -> anyhow::Result<(Pin<Box<dyn Stream<Item = Bytes> + Send>>,)>
334 where
335 T: Invoke<Context = ()> + Default,
336 {
337 let wrpc = T::default();
338 let ((r0,), _) = wrpc
339 .invoke_values(
340 (),
341 "wrpc-test:integration/async",
342 "with-streams",
343 (),
344 [
345 [Some(1), Some(2)].as_slice(),
346 [None].as_slice(),
347 [Some(42)].as_slice(),
348 ],
349 )
350 .await?;
351 Ok(r0)
352 }
353
354 trait Handler {
355 fn foo() -> impl Future<Output = anyhow::Result<()>>;
356 }
357
358 impl<T> Handler for T
359 where
360 T: Invoke<Context = ()> + Default,
361 {
362 async fn foo() -> anyhow::Result<()> {
363 let (st,) = call_invoke_async::<Self>().await?;
364 st.collect::<Vec<_>>().await;
365 Ok(())
366 }
367 }
368}