Wrapping error from inner future
⚓ Rust 📅 2026-01-15 👤 surdeus 👁️ 2I am trying to wrap an error from a future but I cannot wrap my head around the error returned by the compiler.
I vaguely understand it is becuase of the error types are different between the Future trait and/or the Service trait. The suggestion from the compiler didn't solve the problem.
I learned the wrapping idea from this similar question but I failed to adapt it to Future trait.
use pin_project_lite::pin_project;
use std::pin::Pin;
use std::task::ready;
use std::task::{Context, Poll};
use tower::{Layer, Service};
type Response = http::Response<String>;
enum ResponseError<E> {
Local(&'static str),
Inner(E),
}
pin_project! {
struct ResponseFuture<F> {
#[pin]
inner: F,
}
}
impl<F, E> Future for ResponseFuture<F>
where
F: Future<Output = Result<Response, ResponseError<E>>>,
{
type Output = F::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
let res = ready!(this.inner.poll(cx))?;
// I need to change the error based on some condition
if res.status() == 300 {
return Poll::Ready(Err(ResponseError::Local("some error")));
}
Poll::Ready(Ok(res))
}
}
struct ResponseErrorService<S> {
inner: S,
}
impl<S, Request> Service<http::Request<Request>> for ResponseErrorService<S>
where
S: Service<http::Request<Request>, Response = Response>,
{
type Response = S::Response;
type Error = ResponseError<S::Error>;
type Future = ResponseFuture<S::Future>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.poll_ready(cx).map_err(ResponseError::Inner)
}
fn call(&mut self, request: http::Request<Request>) -> Self::Future {
ResponseFuture {
inner: self.inner.call(request),
}
}
}
struct ResponseErrorLayer;
impl<S> Layer<S> for ResponseErrorLayer {
type Service = ResponseErrorService<S>;
fn layer(&self, inner: S) -> Self::Service {
Self::Service { inner }
}
}
error[E0271]: expected `ResponseFuture<<S as Service<Request<Request>>>::Future>` to be a future that resolves to `Result<Response<String>, ResponseError<<S as Service<Request<Request>>>::Error>>`, but it resolves to `Result<Response<String>, <S as Service<Request<Request>>>::Error>`
--> src/lib.rs:51:19
|
51 | type Future = ResponseFuture<S::Future>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<ResponseFuture<...> as Future>::Output == Result<..., ...>`
|
note: expected this to be `Result<http::Response<String>, ResponseError<<S as Service<http::Request<Request>>>::Error>>`
--> src/lib.rs:25:19
|
25 | type Output = F::Output;
| ^^^^^^^^^
= note: expected enum `Result<_, ResponseError<<S as Service<http::Request<Request>>>::Error>>`
found enum `Result<_, <S as Service<http::Request<Request>>>::Error>`
note: required by a bound in `tower::Service::Future`
--> /playground/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tower-service-0.3.3/src/lib.rs:319:25
|
319 | type Future: Future<Output = Result<Self::Response, Self::Error>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Service::Future`
= note: the full name for the type has been written to '/playground/target/debug/deps/playground-0f4c4e4ebcfac284.long-type-13754277701042178790.txt'
= note: consider using `--verbose` to print the full type name to the console
help: consider constraining the associated type `<S as Service<http::Request<Request>>>::Error` to `ResponseError<<S as Service<http::Request<Request>>>::Error>`
|
47 | S: Service<http::Request<Request>, Response = Response, Error = ResponseError<<S as Service<http::Request<Request>>>::Error>>,
| ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
error[E0271]: expected `<S as Service<Request<Request>>>::Future` to be a future that resolves to `Result<Response<String>, ResponseError<_>>`, but it resolves to `Result<Response<String>, <S as Service<Request<Request>>>::Error>`
--> src/lib.rs:51:19
|
51 | type Future = ResponseFuture<S::Future>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `ResponseError<_>`, found associated type
|
= note: expected enum `Result<_, ResponseError<_>>`
found enum `Result<_, <S as Service<http::Request<Request>>>::Error>`
note: required for `ResponseFuture<<S as Service<http::Request<Request>>>::Future>` to implement `std::future::Future`
--> src/lib.rs:21:12
|
21 | impl<F, E> Future for ResponseFuture<F>
| ^^^^^^ ^^^^^^^^^^^^^^^^^
22 | where
23 | F: Future<Output = Result<Response, ResponseError<E>>>,
| ------------------------------------------- unsatisfied trait bound introduced here
note: required by a bound in `tower::Service::Future`
--> /playground/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tower-service-0.3.3/src/lib.rs:319:18
|
319 | type Future: Future<Output = Result<Self::Response, Self::Error>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Service::Future`
help: consider constraining the associated type `<S as Service<http::Request<Request>>>::Error` to `ResponseError<_>`
|
47 | S: Service<http::Request<Request>, Response = Response, Error = ResponseError<_>>,
| ++++++++++++++++++++++++++
2 posts - 2 participants
🏷️ Rust_feed