3

I want use Hyper to implement a web service. I copied code from the hello world example and it succeeded. When I try to to add a data access object to the HelloWorld struct, I get an error, and I don't know how to fix it. How do add a trait member to a Hyper server?

extern crate futures;
extern crate hyper;

use futures::future::Future;
use hyper::header::ContentLength;
use hyper::server::{Http, Request, Response, Service};

trait Dao {}

struct MysqlDao;

impl Dao for MysqlDao {}

struct HelloWorld {
    dao: Box<Dao>,
}

const PHRASE: &'static str = "Hello, World!";

impl Service for HelloWorld {
    // boilerplate hooking up hyper's server types
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    // The future representing the eventual Response your call will
    // resolve to. This can change to whatever Future you need.
    type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;

    fn call(&self, _req: Request) -> Self::Future {
        // We're currently ignoring the Request
        // And returning an 'ok' Future, which means it's ready
        // immediately, and build a Response with the 'PHRASE' body.
        Box::new(futures::future::ok(
            Response::new()
                .with_header(ContentLength(PHRASE.len() as u64))
                .with_body(PHRASE),
        ))
    }
}

fn main() {
    let addr = "127.0.0.1:3000".parse().unwrap();
    let dao = Box::new(MysqlDao);
    let server = Http::new().bind(&addr, || Ok(HelloWorld { dao })).unwrap();
    server.run().unwrap();
}

The error info:

error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
  --> src/main.rs:44:42
   |
44 |     let server = Http::new().bind(&addr, || Ok(HelloWorld { dao })).unwrap();
   |                              ----        ^^^^^^^^^^^^^^^^^^^^^^^^^
   |                              |
   |                              the requirement to implement `Fn` derives from here
   |
note: closure is `FnOnce` because it moves the variable `dao` out of its environment
  --> src/main.rs:44:61
   |
44 |     let server = Http::new().bind(&addr, || Ok(HelloWorld { dao })).unwrap();
   |                                                             ^^^
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
llxxbb
  • 1,241
  • 1
  • 10
  • 16
  • It is not clear what exactly you are asking. The compiler is telling you that you have to provide a type that meets a certain set of restrictions and you are not. Perhaps you are looking for [When does a closure implement Fn, FnMut and FnOnce](https://stackoverflow.com/q/30177395/155423)? For sharing stuff between handlers, maybe you wanted [How do I share a HashMap between Hyper handlers](https://stackoverflow.com/q/38042592/155423)? – Shepmaster Feb 13 '18 at 13:56
  • 1
    @Shepmaster thanks a lot. I viewed the links you provided, I think these are not my case. The problem is "closure that implements the `Fn` trait", I don't know how to fix it in HelloWorld ! – llxxbb Feb 14 '18 at 11:49
  • 1
    The second link is *very* close to your problem, and if you completely understand the first link, you should be able to adapt the solution to the second to your situation. Or in other words, the first link explains why you get the compiler error you do, and the second how to fix it. – Sebastian Redl Feb 15 '18 at 09:24
  • 1
    @SebastianRedl, I read the links carefully, and I know the things what they said, but I just couldn't make it work. could you help me fixing my code? I would appreciate very much! – llxxbb Feb 17 '18 at 06:41

1 Answers1

2

I made these changes to the HelloWorld struct:

struct HelloWorld<'a> {
    dao: &'a Dao,
}

I also changed the let server statement to:

let server = Http::new()
    .bind(&addr, move || Ok(HelloWorld { dao: &dao }))
    .unwrap();

The entire code:

extern crate futures;
extern crate hyper;

use futures::future::Future;
use hyper::header::ContentLength;
use hyper::server::{Http, Request, Response, Service};

trait Dao {}

struct MysqlDao;

impl Dao for MysqlDao {}

struct HelloWorld<'a> {
    dao: &'a Dao,
}

const PHRASE: &'static str = "Hello, World!";

impl<'a> Service for HelloWorld<'a> {
    // boilerplate hooking up hyper's server types
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    // The future representing the eventual Response your call will
    // resolve to. This can change to whatever Future you need.
    type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;

    fn call(&self, _req: Request) -> Self::Future {
        // We're currently ignoring the Request
        // And returning an 'ok' Future, which means it's ready
        // immediately, and build a Response with the 'PHRASE' body.
        Box::new(futures::future::ok(
            Response::new()
                .with_header(ContentLength(PHRASE.len() as u64))
                .with_body(PHRASE),
        ))
    }
}

fn main() {
    let addr = "127.0.0.1:3000".parse().unwrap();
    let dao = MysqlDao;
    let server = Http::new()
        .bind(&addr, move || Ok(HelloWorld { dao: &dao }))
        .unwrap();
    server.run().unwrap();
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
llxxbb
  • 1,241
  • 1
  • 10
  • 16