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