use std::{
future::Future,
marker::PhantomData,
pin::Pin,
task::{Context, Poll},
};
use futures::{channel::oneshot, ready};
use tower::Service;
use crate::peer_set::set::CancelClientWork;
#[cfg(test)]
mod tests;
#[pin_project]
#[derive(Debug)]
pub(super) struct UnreadyService<K, S, Req> {
pub(super) key: Option<K>,
#[pin]
pub(super) cancel: oneshot::Receiver<CancelClientWork>,
pub(super) service: Option<S>,
pub(super) _req: PhantomData<Req>,
}
#[derive(Debug, Eq, PartialEq)]
pub(super) enum Error<E> {
Inner(E),
Canceled,
CancelHandleDropped(oneshot::Canceled),
}
impl<K, S: Service<Req>, Req> Future for UnreadyService<K, S, Req> {
type Output = Result<(K, S), (K, Error<S::Error>)>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
if let Poll::Ready(oneshot_result) = this.cancel.poll(cx) {
let key = this.key.take().expect("polled after ready");
match oneshot_result {
Ok(CancelClientWork) => return Poll::Ready(Err((key, Error::Canceled))),
Err(canceled_error) => {
return Poll::Ready(Err((key, Error::CancelHandleDropped(canceled_error))))
}
}
}
let res = ready!(this
.service
.as_mut()
.expect("polled after ready")
.poll_ready(cx));
let key = this.key.take().expect("polled after ready");
let svc = this.service.take().expect("polled after ready");
match res {
Ok(()) => Poll::Ready(Ok((key, svc))),
Err(e) => Poll::Ready(Err((key, Error::Inner(e)))),
}
}
}