Description
I'm trying to use join_all
to parallelize some async work.
Because my stub
function returns a non-Send
error type, I consume the error before passing it to join_all
using a .map
combinator (I have also tried map_err(|e| ())
).
The join_all
result is then dispatched to tokio:
#![feature(await_macro, async_await, futures_api)]
use futures::future::{FutureExt, TryFutureExt};
/* Cargo.toml dependencies:
tokio = {version = "0.1", features = ["async-await-preview"]}
futures-preview = { version = "0.3.0-alpha" }
*/
async fn stub() -> Result<(), Box<dyn std::error::Error + 'static>> { Ok(()) }
fn main() {
tokio::run_async(async {
tokio::await!(futures::future::join_all((1..10).map(|n| {
stub().map(|r| r.is_ok()).boxed()
})));
});
}
This fails badly, with rustc trying to teach me type theory:
error: implementation of `std::marker::Send` is not general enough
--> src/main.rs:12:5
|
12 | tokio::run_async(async {
| ^^^^^^^^^^^^^^^^
|
= note: `std::marker::Send` would have to be implemented for the type `std::ptr::Unique<futures_util::future::join_all::ElemState<std::pin::Pin<std::boxed::Box<futures_util::try_future::map_err::MapErr<impl core::future::future::Future, [closure@src/main.rs:14:28: 14:34]>>>>>`, for any lifetime `'0`
= note: but `std::marker::Send` is actually implemented for the type `std::ptr::Unique<futures_util::future::join_all::ElemState<std::pin::Pin<std::boxed::Box<futures_util::try_future::map_err::MapErr<impl core::future::future::Future, [closure@src/main.rs:14:28: 14:34]>>>>>`, for some specific lifetime `'1`
However I eventually figured out that if I replace the call to .map(|r| r.is_ok())
by this fut_is_ok
wrapper function, everything is fine:
// [...]
async fn fut_is_ok(f: impl std::future::Future<Output=Result<(), Box<dyn std::error::Error + 'static>>>) -> bool {
await!(f).is_ok()
}
fn main() {
tokio::run_async(async {
tokio::await!(futures::future::join_all((1..10).map(|n| {
fut_is_ok(stub()).boxed()
})));
});
}
At this point I am already thoroughly confused, but to add to the fun the following things also make the error go away:
- Making
stub
returnResult<(), ()>
(without removing themap
call) - Making
stub
return aSend
error, but only if the map call is removed - Awaiting only one future instead of doing a
join_all
I suspect that somewhere deep in its type parameters the combinator version is still somehow keeping track of the non-Send
type I'm trying to map
away, whereas the free function does not.
Is this error about std::marker::Send
expected behavior, and is there some core async/await concept I'm grossly misunderstanding here?