Skip to content

Instantly share code, notes, and snippets.

@dacut
Created September 30, 2022 18:37
Show Gist options
  • Save dacut/a4602b4ae38308a8a5a9b3ee3ba1ce20 to your computer and use it in GitHub Desktop.
Save dacut/a4602b4ae38308a8a5a9b3ee3ba1ce20 to your computer and use it in GitHub Desktop.
Rust HRTB bug
use {
std::{
future::Future,
pin::Pin,
task::{Context, Poll},
},
tower::{BoxError, Service, ServiceExt},
};
pub struct WrapperService<Pre, Handler, ErrorHandler>
where
Pre: Service<String, Response = String, Error = BoxError> + Clone + Send + 'static,
Pre::Future: Send,
Handler: Service<String, Response = String, Error = BoxError> + Clone + Send + 'static,
Handler::Future: Send,
ErrorHandler: Service<BoxError, Response = String, Error = BoxError> + Clone + Send + 'static,
ErrorHandler::Future: Send,
{
pre: Pre,
handler: Handler,
error_handler: ErrorHandler,
}
impl<Pre, Handler, ErrorHandler> Service<String> for WrapperService<Pre, Handler, ErrorHandler>
where
Pre: Service<String, Response = String, Error = BoxError> + Clone + Send + 'static,
Pre::Future: Send,
Handler: Service<String, Response = String, Error = BoxError> + Clone + Send + 'static,
Handler::Future: Send,
ErrorHandler: Service<BoxError, Response = String, Error = BoxError> + Clone + Send + 'static,
ErrorHandler::Future: Send,
{
type Response = String;
type Error = BoxError;
type Future = Pin<Box<dyn Future<Output = Result<String, BoxError>> + Send>>;
fn poll_ready(&mut self, _cx: &mut Context) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: String) -> Self::Future {
let pre = self.pre.clone();
let handler = self.handler.clone();
let error_handler = self.error_handler.clone();
Box::pin(async move {
match pre.oneshot(req).await {
Ok(req) => handler.oneshot(req).await,
Err(e) => error_handler.oneshot(e).await,
}
})
// error: higher-ranked lifetime error
// note: could not prove `for<'a, 'b, 'c> Pin<Box<impl for<'a> Future<Output = Result<String, Box<(dyn std::error::Error + Send + Sync + 'a)>>>>>: CoerceUnsized<Pin<Box<(dyn Future<for<'b> Output = Result<String, Box<(dyn std::error::Error + Send + Sync + 'b)>>> + Send + 'c)>>>`
}
}
fn main() {
println!("Hello, world!");
}
@dacut
Copy link
Author

dacut commented Sep 30, 2022

This appears to fix it:

impl<Pre, Handler, ErrorHandler> Service<String> for WrapperService<Pre, Handler, ErrorHandler>
where
    Pre: Service<String, Response = String, Error = BoxError> + Clone + Send + 'static,
    Pre::Future: Send,
    Handler: Service<String, Response = String, Error = BoxError> + Clone + Send + 'static,
    Handler::Future: Send,
    ErrorHandler: Service<Box<dyn Error + Send + Sync>, Response = String, Error = BoxError> + Clone + Send + 'static,
    for<'a> <ErrorHandler as Service<Box<dyn Error + Send + Sync + 'a>>>::Future: Send,
{
    type Response = String;
    type Error = BoxError;
    type Future = Pin<Box<dyn Future<Output = Result<String, BoxError>> + Send>>;

    fn poll_ready(&mut self, _cx: &mut Context) -> Poll<Result<(), Self::Error>> {
        Poll::Ready(Ok(()))
    }

    fn call(&mut self, req: String) -> Self::Future {
        let pre = self.pre.clone();
        let handler = self.handler.clone();
        let error_handler = self.error_handler.clone();

        Box::pin(async move {
            match pre.oneshot(req).await {
                Ok(req) => handler.oneshot(req).await,
                Err(e) => error_handler.oneshot(e).await,
            }
        })
        // error: higher-ranked lifetime error
        // note: could not prove `for<'a, 'b, 'c> Pin<Box<impl for<'a> Future<Output = Result<String, Box<(dyn std::error::Error + Send + Sync + 'a)>>>>>: CoerceUnsized<Pin<Box<(dyn Future<for<'b> Output = Result<String, Box<(dyn std::error::Error + Send + Sync + 'b)>>> + Send + 'c)>>>`
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment