wasefire_protocol/
connection.rs1use alloc::boxed::Box;
16use alloc::format;
17use core::future::Future;
18use core::pin::Pin;
19
20use anyhow::Context;
21use wasefire_wire::Yoke;
22
23use crate::{Api, ApiResult, Request, Service};
24
25pub type DynFuture<'a, T> = Pin<Box<dyn Future<Output = anyhow::Result<T>> + 'a>>;
26
27pub trait Connection: Send {
28 fn read(&mut self) -> DynFuture<Box<[u8]>>;
30
31 fn write<'a>(&'a mut self, response: &'a [u8]) -> DynFuture<'a, ()>;
33}
34
35impl Connection for Box<dyn Connection> {
36 fn read(&mut self) -> DynFuture<Box<[u8]>> {
37 (**self).read()
38 }
39
40 fn write<'a>(&'a mut self, response: &'a [u8]) -> DynFuture<'a, ()> {
41 (**self).write(response)
42 }
43}
44
45pub trait ConnectionExt: Connection {
46 fn call<S: Service>(
48 &mut self, request: S::Request<'_>,
49 ) -> impl Future<Output = anyhow::Result<Yoke<S::Response<'static>>>> {
50 async { self.call_ref::<S>(&S::request(request)).await }
51 }
52
53 fn call_ref<S: Service>(
54 &mut self, request: &Api<Request>,
55 ) -> impl Future<Output = anyhow::Result<Yoke<S::Response<'static>>>> {
56 async {
57 self.send(request).await.with_context(|| format!("sending {}", S::NAME))?;
58 self.receive::<S>().await.with_context(|| format!("receiving {}", S::NAME))
59 }
60 }
61
62 fn send(&mut self, request: &Api<'_, Request>) -> impl Future<Output = anyhow::Result<()>> {
64 async {
65 let request = request.encode().context("encoding request")?;
66 self.write(&request).await
67 }
68 }
69
70 fn receive<S: Service>(
72 &mut self,
73 ) -> impl Future<Output = anyhow::Result<Yoke<S::Response<'static>>>> {
74 async {
75 let response = self.read().await?;
76 let response = ApiResult::<S>::decode_yoke(response).context("decoding response")?;
77 response.try_map(|x| match x {
78 ApiResult::Ok(x) => Ok(x),
79 ApiResult::Err(error) => Err(anyhow::Error::new(error)),
80 })
81 }
82 }
83}
84
85impl<T: Connection + ?Sized> ConnectionExt for T {}