4

As a very simple example, I'm trying to write a webserver that simply replies

this page has been requested $N times

but I'm having a lot of trouble sharing the mutable state for this to happen. Here's my best attempt:

extern crate hyper;

use hyper::Server;
use hyper::server::Request;
use hyper::server::Response;

struct World {
    count: i64,
}

impl World {
    fn greet(&mut self, req: Request, res: Response) {
        self.count += 1;
        let str: String = format!("this page has been requested {} times", self.count);
        res.send(str.as_bytes()).unwrap();
    }
}

fn main() {
    println!("Started..");

    let mut w = World { count: 0 }; 

    Server::http("127.0.0.1:3001").unwrap()
        .handle(move |req: Request, res: Response| w.greet(req, res) ).unwrap();

}
Ronald Smith
  • 339
  • 2
  • 9

1 Answers1

10

Because request handling may happen in different threads, you need to synchronize access to the global state, for which you need to use things like Mutex:

let w = Mutex::new(World { count: 0 });

Server::http("127.0.0.1:3001").unwrap()
    .handle(move |req: Request, res: Response| w.lock().unwrap().greet(req, res))
    .unwrap();

You can find this out from the signature of Server::handle(): it requires its handler to be Handler + 'static, and Handler itself requires Send + Sync. Therefore, everything this closure captures must also be 'static + Send + Sync, that is, safe to access from multiple threads. Values wrapped into a mutex usually satisfy these requirements (if they don't contain references, of course).

Vladimir Matveev
  • 120,085
  • 34
  • 287
  • 296
  • 2
    By the way: If it's a simple counter, one can also use one of the `Atomic*` types, change the signature to `greet(&self, Request, Response)`, and increment the counter via `fetch_add`. –  Feb 28 '16 at 12:24
  • 1
    I think this answer is out of date. Is there any chance you could update it please? – Joe Feb 05 '18 at 22:55