I'm really struggling to understand why this code doesn't compile
use sarangollo_lib::Game;
use async_std::{self, sync::RwLock};
use tide::{Request, Response};
async fn handle_get_state(req: Request<RwLock<Game>>) -> Response {
let game = req.state().read().await;
let game_state = game.get_state();
let result = tide::Response::new(200).body_json(&game_state);
match result {
Ok(rsp) => rsp,
Err(_) => Response::new(500),
}
}
#[async_std::main]
async fn main() -> Result<(), std::io::Error> {
let game = Game::default();
let state = RwLock::new(game);
let mut app = tide::with_state(state);
app.at("/").get(|_| async move { "Hello, world!" });
app.at("/state").get(|req| async move { handle_get_state(req).await });
app.listen("127.0.0.1:8080").await?;
Ok(())
}
The compiler complains with the following:
Checking sarangollo-lib v0.1.0 (C:\Users\ruben\src\sarangollolib)
error[E0277]: `(dyn futures_io::if_std::AsyncBufRead + std::marker::Send + 'static)` cannot be shared between threads safely
--> src/main.rs:25:22
|
25 | app.at("/state").get(|req| async move { handle_get_state(req).await });
| ^^^ `(dyn futures_io::if_std::AsyncBufRead + std::marker::Send + 'static)` cannot be shared between threads safely
|
= help: the trait `std::marker::Sync` is not implemented for `(dyn futures_io::if_std::AsyncBufRead + std::marker::Send + 'static)`
= note: required because of the requirements on the impl of `std::marker::Sync` for `std::ptr::Unique<(dyn futures_io::if_std::AsyncBufRead + std::marker::Send + 'static)>`
= note: required because it appears within the type `std::boxed::Box<(dyn futures_io::if_std::AsyncBufRead + std::marker::Send + 'static)>`
= note: required because it appears within the type `std::pin::Pin<std::boxed::Box<(dyn futures_io::if_std::AsyncBufRead + std::marker::Send + 'static)>>`
= note: required because it appears within the type `http_service::Body`
= note: required because it appears within the type `http::request::Request<http_service::Body>`
= note: required because it appears within the type `tide::request::Request<async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>>`
= note: required because of the requirements on the impl of `std::marker::Send` for `&tide::request::Request<async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>>`
= note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4> {tide::request::Request<async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>>, &'r tide::request::Request<async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>>, tide::request::Request<async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>>, &'s async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>, &'t0 async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>, impl std::future::Future, impl std::future::Future, ()}`
= note: required because it appears within the type `[static generator@src/main.rs:5:67: 13:2 req:tide::request::Request<async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>> for<'r, 's, 't0, 't1, 't2, 't3, 't4> {tide::request::Request<async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>>, &'r tide::request::Request<async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>>, tide::request::Request<async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>>, &'s async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>, &'t0 async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>, impl std::future::Future, impl std::future::Future, ()}]`
= note: required because it appears within the type `std::future::GenFuture<[static generator@src/main.rs:5:67: 13:2 req:tide::request::Request<async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>> for<'r, 's, 't0, 't1, 't2, 't3, 't4> {tide::request::Request<async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>>, &'r tide::request::Request<async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>>, tide::request::Request<async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>>, &'s async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>, &'t0 async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>, impl std::future::Future, impl std::future::Future, ()}]>`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `{tide::request::Request<async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>>, impl std::future::Future, impl std::future::Future, ()}`
= note: required because it appears within the type `[static generator@src/main.rs:25:43: 25:74 req:tide::request::Request<async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>> {tide::request::Request<async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>>, impl std::future::Future, impl std::future::Future, ()}]`
= note: required because it appears within the type `std::future::GenFuture<[static generator@src/main.rs:25:43: 25:74 req:tide::request::Request<async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>> {tide::request::Request<async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>>, impl std::future::Future, impl std::future::Future, ()}]>`
= note: required because it appears within the type `impl std::future::Future`
= note: required because of the requirements on the impl of `tide::endpoint::Endpoint<async_std::sync::rwlock::RwLock<sarangollo_lib::game::Game>>` for `[closure@src/main.rs:25:26: 25:74]`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.
error: could not compile `sarangollo-lib`.
To learn more, run the command again with --verbose.
However, changing the handler function to the following does compile (notice how reading the Request state and awaiting the read lock are split in two separate lines here)
async fn handle_get_state(req: Request<RwLock<Game>>) -> Response {
let state = req.state();
let game = state.read().await;
let game_state = game.get_state();
let result = tide::Response::new(200).body_json(&game_state);
match result {
Ok(rsp) => rsp,
Err(_) => Response::new(500),
}
}
I presume it has something to do with chaining those requests returning a type that somehow is not Sync (since Request is not Sync by default), which is captured by the underlying Future/Generator that the async function produces.
But I really don't understand why splitting that expression resolves the issue. I would've assumed that the type being awaited on on the fixed code would be the same as the one returned in the faulty code, but that doesn't seem to be the case.
Can someone enlighten me, please?
Thanks!