#[cfg(feature = "alloc")]
use core::future::Future;
#[cfg(feature = "alloc")]
use core::marker::PhantomData;
#[cfg(feature = "rpc_try")]
use core::ops::Try;
#[cfg(feature = "alloc")]
use core::pin::Pin;
#[cfg(feature = "alloc")]
use core::task::Poll;
use crate::any_pointer;
#[cfg(feature = "alloc")]
use crate::private::capability::{ClientHook, ParamsHook, RequestHook, ResponseHook, ResultsHook};
#[cfg(feature = "alloc")]
use crate::traits::{Owned, Pipelined};
#[cfg(feature = "alloc")]
use crate::{Error, MessageSize};
#[cfg(feature = "alloc")]
#[must_use = "futures do nothing unless polled"]
pub struct Promise<T, E> {
inner: PromiseInner<T, E>,
}
#[cfg(feature = "alloc")]
enum PromiseInner<T, E> {
Immediate(Result<T, E>),
Deferred(Pin<alloc::boxed::Box<dyn Future<Output = core::result::Result<T, E>> + 'static>>),
Empty,
}
#[cfg(feature = "alloc")]
impl<T, E> Unpin for PromiseInner<T, E> {}
#[cfg(feature = "alloc")]
impl<T, E> Promise<T, E> {
pub fn ok(value: T) -> Self {
Self {
inner: PromiseInner::Immediate(Ok(value)),
}
}
pub fn err(error: E) -> Self {
Self {
inner: PromiseInner::Immediate(Err(error)),
}
}
pub fn from_future<F>(f: F) -> Self
where
F: Future<Output = core::result::Result<T, E>> + 'static,
{
Self {
inner: PromiseInner::Deferred(alloc::boxed::Box::pin(f)),
}
}
}
#[cfg(feature = "alloc")]
impl<T, E> Future for Promise<T, E> {
type Output = core::result::Result<T, E>;
fn poll(self: Pin<&mut Self>, cx: &mut ::core::task::Context) -> Poll<Self::Output> {
match self.get_mut().inner {
PromiseInner::Empty => panic!("Promise polled after done."),
ref mut imm @ PromiseInner::Immediate(_) => {
match core::mem::replace(imm, PromiseInner::Empty) {
PromiseInner::Immediate(r) => Poll::Ready(r),
_ => unreachable!(),
}
}
PromiseInner::Deferred(ref mut f) => f.as_mut().poll(cx),
}
}
}
#[cfg(feature = "alloc")]
#[cfg(feature = "rpc_try")]
impl<T> core::ops::Try for Promise<T, crate::Error> {
type Output = Self;
type Residual = Result<core::convert::Infallible, crate::Error>;
fn from_output(output: Self::Output) -> Self {
output
}
fn branch(self) -> core::ops::ControlFlow<Self::Residual, Self::Output> {
unimplemented!();
}
}
#[cfg(feature = "alloc")]
#[cfg(feature = "rpc_try")]
impl<T> core::ops::FromResidual for Promise<T, crate::Error> {
fn from_residual(residual: <Self as Try>::Residual) -> Self {
match residual {
Ok(_) => unimplemented!(),
Err(e) => Self::err(e),
}
}
}
#[cfg(feature = "alloc")]
#[must_use]
pub struct RemotePromise<Results>
where
Results: Pipelined + Owned + 'static,
{
pub promise: Promise<Response<Results>, crate::Error>,
pub pipeline: Results::Pipeline,
}
#[cfg(feature = "alloc")]
pub struct Response<Results> {
pub marker: PhantomData<Results>,
pub hook: alloc::boxed::Box<dyn ResponseHook>,
}
#[cfg(feature = "alloc")]
impl<Results> Response<Results>
where
Results: Pipelined + Owned,
{
pub fn new(hook: alloc::boxed::Box<dyn ResponseHook>) -> Self {
Self {
marker: PhantomData,
hook,
}
}
pub fn get(&self) -> crate::Result<Results::Reader<'_>> {
self.hook.get()?.get_as()
}
}
#[cfg(feature = "alloc")]
pub struct Request<Params, Results> {
pub marker: PhantomData<(Params, Results)>,
pub hook: alloc::boxed::Box<dyn RequestHook>,
}
#[cfg(feature = "alloc")]
impl<Params, Results> Request<Params, Results>
where
Params: Owned,
{
pub fn new(hook: alloc::boxed::Box<dyn RequestHook>) -> Self {
Self {
hook,
marker: PhantomData,
}
}
pub fn get(&mut self) -> Params::Builder<'_> {
self.hook.get().get_as().unwrap()
}
pub fn set(&mut self, from: Params::Reader<'_>) -> crate::Result<()> {
self.hook.get().set_as(from)
}
}
#[cfg(feature = "alloc")]
impl<Params, Results> Request<Params, Results>
where
Results: Pipelined + Owned + 'static + Unpin,
<Results as Pipelined>::Pipeline: FromTypelessPipeline,
{
pub fn send(self) -> RemotePromise<Results> {
let RemotePromise {
promise, pipeline, ..
} = self.hook.send();
let typed_promise = Promise::from_future(async move {
Ok(Response {
hook: promise.await?.hook,
marker: PhantomData,
})
});
RemotePromise {
promise: typed_promise,
pipeline: FromTypelessPipeline::new(pipeline),
}
}
}
#[cfg(feature = "alloc")]
pub struct Params<T> {
pub marker: PhantomData<T>,
pub hook: alloc::boxed::Box<dyn ParamsHook>,
}
#[cfg(feature = "alloc")]
impl<T> Params<T> {
pub fn new(hook: alloc::boxed::Box<dyn ParamsHook>) -> Self {
Self {
marker: PhantomData,
hook,
}
}
pub fn get(&self) -> crate::Result<T::Reader<'_>>
where
T: Owned,
{
self.hook.get()?.get_as()
}
}
#[cfg(feature = "alloc")]
pub struct Results<T> {
pub marker: PhantomData<T>,
pub hook: alloc::boxed::Box<dyn ResultsHook>,
}
#[cfg(feature = "alloc")]
impl<T> Results<T>
where
T: Owned,
{
pub fn new(hook: alloc::boxed::Box<dyn ResultsHook>) -> Self {
Self {
marker: PhantomData,
hook,
}
}
pub fn get(&mut self) -> T::Builder<'_> {
self.hook.get().unwrap().get_as().unwrap()
}
pub fn set(&mut self, other: T::Reader<'_>) -> crate::Result<()> {
self.hook.get().unwrap().set_as(other)
}
}
pub trait FromTypelessPipeline {
fn new(typeless: any_pointer::Pipeline) -> Self;
}
#[cfg(feature = "alloc")]
pub trait FromClientHook {
fn new(hook: alloc::boxed::Box<dyn ClientHook>) -> Self;
fn into_client_hook(self) -> alloc::boxed::Box<dyn ClientHook>;
fn as_client_hook(&self) -> &dyn ClientHook;
fn cast_to<T: FromClientHook + Sized>(self) -> T
where
Self: Sized,
{
FromClientHook::new(self.into_client_hook())
}
}
#[cfg(feature = "alloc")]
pub struct Client {
pub hook: alloc::boxed::Box<dyn ClientHook>,
}
#[cfg(feature = "alloc")]
impl Client {
pub fn new(hook: alloc::boxed::Box<dyn ClientHook>) -> Self {
Self { hook }
}
pub fn new_call<Params, Results>(
&self,
interface_id: u64,
method_id: u16,
size_hint: Option<MessageSize>,
) -> Request<Params, Results> {
let typeless = self.hook.new_call(interface_id, method_id, size_hint);
Request {
hook: typeless.hook,
marker: PhantomData,
}
}
pub fn when_resolved(&self) -> Promise<(), Error> {
self.hook.when_resolved()
}
}
#[cfg(feature = "alloc")]
pub trait Server {
fn dispatch_call(
&mut self,
interface_id: u64,
method_id: u16,
params: Params<any_pointer::Owned>,
results: Results<any_pointer::Owned>,
) -> Promise<(), Error>;
}
#[cfg(feature = "alloc")]
pub trait FromServer<S>: FromClientHook {
type Dispatch: Server + 'static + core::ops::DerefMut<Target = S>;
fn from_server(s: S) -> Self::Dispatch;
}
#[cfg(feature = "alloc")]
pub async fn get_resolved_cap<C: FromClientHook>(cap: C) -> C {
let mut hook = cap.into_client_hook();
let _ = hook.when_resolved().await;
while let Some(resolved) = hook.get_resolved() {
hook = resolved;
}
FromClientHook::new(hook)
}