Use struct method in hyper service struct impl

46 views Asked by At

I want to use my struct method in hyper .14 service struct impl, to simplify access to request data by a struct instead of passing them to functions, in Hyper doc stated that : "Trait hyper::service::Service as An asynchronous function from a Request to a Response. The Service trait is a simplified interface making it easy to write network applications in a modular and reusable way, decoupled from the underlying protocol. It is one of Tower’s fundamental abstractions." but when I want to use async method of my struct in hyper service struct impl return this error:

error: lifetime may not live long enough
  --> examples/service_struct_impl.rs:36:9
   |
35 |     fn call(&mut self, req: Request<Body>) -> Self::Future {
   |             - let's call the lifetime of this reference `'1`
36 |         Box::pin(self.start_process(req))
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`

This is my code:

use hyper::service::Service;
use hyper::{Body, Request, Response, Server};
use hyper::StatusCode;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};

type Counter = i32;
type GenericError = Box<dyn std::error::Error + Send + Sync + 'static>;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let addr = ([127, 0, 0, 1], 3000).into();

    let server = Server::bind(&addr).serve(MakeSvc { counter: 81818 });
    println!("Listening on http://{}", addr);

    server.await?;
    Ok(())
}

struct Svc {
    counter: Counter,
}

impl Service<Request<Body>> for Svc {
    type Response = Response<Body>;
    type Error = GenericError;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;

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

    fn call(&mut self, req: Request<Body>) -> Self::Future {
        Box::pin(self.start_process(req))
    }
}

impl Svc {
    async fn start_process(
        &mut self,
        req: Request<Body>
    ) -> Result<Response<Body>, GenericError> {
        Ok(Response::builder()
            .status(StatusCode::INTERNAL_SERVER_ERROR)
            .body(Body::from(format!("Counter is: {}", self.counter)))?)
    }
}

struct MakeSvc {
    counter: Counter,
}

impl<T> Service<T> for MakeSvc {
    type Response = Svc;
    type Error = GenericError;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;

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

    fn call(&mut self, _: T) -> Self::Future {
        let counter = self.counter.clone();
        let fut = async move { Ok(Svc { counter }) };
        Box::pin(fut)
    }
}

1

There are 1 answers

0
Chayim Friedman On

The future returned from Service::call() cannot borrow from self.

You can, for example, clone() the counter in call() and move it to the async closure:

impl Service<Request<Body>> for Svc {
    type Response = Response<Body>;
    type Error = GenericError;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;

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

    fn call(&mut self, req: Request<Body>) -> Self::Future {
        Box::pin(Self::start_process(self.counter.clone(), req))
    }
}

impl Svc {
    async fn start_process(
        counter: Counter,
        req: Request<Body>,
    ) -> Result<Response<Body>, GenericError> {
        Ok(Response::builder()
            .status(StatusCode::INTERNAL_SERVER_ERROR)
            .body(Body::from(format!("Counter is: {}", counter)))?)
    }
}