use std::fmt;
use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
use tower_service::Service;
pub fn future_service<F, S, R, E>(future: F) -> FutureService<F, S>
where
F: Future<Output = Result<S, E>> + Unpin,
S: Service<R, Error = E>,
{
FutureService::new(future)
}
#[derive(Clone)]
pub struct FutureService<F, S> {
state: State<F, S>,
}
impl<F, S> FutureService<F, S> {
pub fn new(future: F) -> Self {
Self {
state: State::Future(future),
}
}
}
impl<F, S> fmt::Debug for FutureService<F, S>
where
S: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FutureService")
.field("state", &format_args!("{:?}", self.state))
.finish()
}
}
#[derive(Clone)]
enum State<F, S> {
Future(F),
Service(S),
}
impl<F, S> fmt::Debug for State<F, S>
where
S: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
State::Future(_) => f
.debug_tuple("State::Future")
.field(&format_args!("<{}>", std::any::type_name::<F>()))
.finish(),
State::Service(svc) => f.debug_tuple("State::Service").field(svc).finish(),
}
}
}
impl<F, S, R, E> Service<R> for FutureService<F, S>
where
F: Future<Output = Result<S, E>> + Unpin,
S: Service<R, Error = E>,
{
type Response = S::Response;
type Error = E;
type Future = S::Future;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
loop {
self.state = match &mut self.state {
State::Future(fut) => {
let fut = Pin::new(fut);
let svc = futures_core::ready!(fut.poll(cx)?);
State::Service(svc)
}
State::Service(svc) => return svc.poll_ready(cx),
};
}
}
fn call(&mut self, req: R) -> Self::Future {
if let State::Service(svc) = &mut self.state {
svc.call(req)
} else {
panic!("FutureService::call was called before FutureService::poll_ready")
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::util::{future_service, ServiceExt};
use crate::Service;
use futures::future::{ready, Ready};
use std::convert::Infallible;
#[tokio::test]
async fn pending_service_debug_impl() {
let mut pending_svc = future_service(ready(Ok(DebugService)));
assert_eq!(
format!("{:?}", pending_svc),
"FutureService { state: State::Future(<futures_util::future::ready::Ready<core::result::Result<tower::util::future_service::tests::DebugService, core::convert::Infallible>>>) }"
);
pending_svc.ready_and().await.unwrap();
assert_eq!(
format!("{:?}", pending_svc),
"FutureService { state: State::Service(DebugService) }"
);
}
#[derive(Debug)]
struct DebugService;
impl Service<()> for DebugService {
type Response = ();
type Error = Infallible;
type Future = Ready<Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Ok(()).into()
}
fn call(&mut self, _req: ()) -> Self::Future {
ready(Ok(()))
}
}
}