I'm stuck trying to share (read-only) data structures across async helpers. What I'm trying to accomplish is create a Hyper server where I pre-generate some data that can be used by all request handlers.
Here is the example from the Hyper getting started guide, extended with what I'm trying to do:
#[tokio::main]
async fn main() {
let address = SocketAddr::from(([127, 0, 0, 1], 3000));
let pages = generate_static_pages();
let make_service = make_service_fn(|_conn| async move {
Ok::<_, Infallible>(service_fn(|req: Request<Body>| async move {
serve(pages, req)
}))
});
let server = Server::bind(&address).serve(make_service);
if let Err(error) = server.await {
eprintln!("server error: {}", error);
}
}
In my case, generate_static_pages()
returns a HashMap<&'static str, Bytes>
with pre-generated pages. Unfortunately, this hash map cannot be generated at compile-time, because that would make things a lot easier. Now, I struggle because pages
cannot be borrowed by the closures: "cannot move out of pages
, a captured variable in an FnMut
closure"
I tried to pass a reference, but that didn't work because Rust cannot infer the variable to live long enough for the closure to use. I then tried to use .clone()
but that doesn't work because it would be called on the variable after it is moved, which it can't. Finally, I tried wrapping in an Arc
, but that doesn't solve it, basically because of the same reason.
What would you advice me to do? Thanks!
If you only want immutable references to the pages then you should be able to use the lazy_static
crate. lazy_static
lets you initialize static variables at runtime - it's quite useful!
Your code would end up looking something like:
use lazy_static::lazy_static;
lazy_static! {
static ref PAGES: HashMap<&'static str, Bytes> = generate_static_pages();
}
#[tokio::main]
async fn main() {
let address = SocketAddr::from(([127, 0, 0, 1], 3000));
let make_service = make_service_fn(|_conn| async move {
Ok::<_, Infallible>(service_fn(|req: Request<Body>| async move {
serve(&PAGES, req)
}))
});
let server = Server::bind(&address).serve(make_service);
if let Err(error) = server.await {
eprintln!("server error: {}", error);
}
}
Also, here's another lazy_static
example.