#[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 fn set_pipeline(&mut self) -> crate::Result<()> {
        self.hook.set_pipeline()
    }
}
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)
}