How can I call a Pinned future from an actix handler? - rust

I have an async trait method which returns a std Future:
Pin<Box<dyn Future<Output = Result<Vec<ResultType>, Box<(dyn Error + 'static)>>> + Send>>
ResultType is an associated type of the trait which is Sync + Send.
Note that this type is not Unpin.
I want to call this from an actix handler, then do something with the result.
For example:
impl StreamHandler<ws::Message, ws::ProtocolError> for MyActor {
fn handle(&mut self, msg: ws::Message) {
let fut = get_future();
let actor_fut = fut
.into_actor(&self)
.map(|r, _actor, ctx| {
ctx.text(r.map(|| ...))
});
ctx.spawn(actor_fut);
}
}
This fails because into_actor takes ownership of the future, which is not allowed by Pin. The cleaned error message looks like:
error[E0599]: no method named `into_actor` found for type `Pin<Box<dyn Future<Output = Result<Vec<ResultType>, Box<dyn Error>>> + Send>>` in the current scope
--> src/app_socket.rs:194:26
|
194 | .into_actor(&self)
| ^^^^^^^^^^ method not found in `Pin<Box<dyn Future<Output = Result<Vec<ResultType>, Box<dyn Error>>> + Send>>`
|
= note: the method `into_actor` exists but the following trait bounds were not satisfied:
`&dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send : WrapFuture<_>`
`&dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send : WrapStream<_>`
`&mut dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send : WrapFuture<_>`
`&mut dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send : WrapStream<_>`
`&mut Pin<std::boxed::Box<dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send>> : WrapFuture<_>`
`&mut Pin<std::boxed::Box<dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send>> : WrapStream<_>`
`&Pin<std::boxed::Box<dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send>> : WrapFuture<_>`
`&Pin<std::boxed::Box<dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send>> : WrapStream<_>`
`dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send : WrapFuture<_>`
`dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send : WrapStream<_>`
`Pin<std::boxed::Box<dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send>> : WrapFuture<_>`
`Pin<std::boxed::Box<dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send>> : WrapStream<_>`
How can I do this?

The actual problem was not that the future was pinned, but that it implemented the wrong future trait.
This section on Pinning explains that poll is implemented for Pin<ref T: Future>.
Hence, the into_actor signature self: impl Future -> WrapFuture<_> was fine. The problem was that the async method returned a future implementing std::future::Future while into_actor expected futures01::future::Future.
Calling .compat() on the future before calling .into_actor fixes the problem.
See this post for more detail about converting futures.

Related

How can I allow lifetime arguments on this type parameter?

I have this code:
lambda: &(dyn for<'b> Fn(
PlayerCreateLambdaArgs<'b>,
) -> Pin<Box<dyn Future<Output = Result<DomainPlayer, String>> + Send + 'b>>
+ Sync
+ '_)
and I would like to create a type for lambda to use it like:
lambda: &Lambda<'_, PlayerCreateLambdaArgs<'a>, DomainPlayer>,
I tried to use:
pub type Lambda<'a, Args, Res> = dyn for<'b> Fn(Args<'b>) -> Pin<Box<dyn Future<Output = Result<Res, String>> + Send + 'b>> + Sync + 'a;
but I'm getting this error:
error[E0109]: lifetime arguments are not allowed on type parameter `Args`
--> src/main.rs:56:54
|
56 | pub type Lambda<'a, Args, Res> = dyn for<'b> Fn(Args<'b>) -> Pin<Box<dyn Future<Output = Result<Res, String>> + Send + 'b>>
| ---- ^^ lifetime argument not allowed
| |
| not allowed on type parameter `Args`
|
note: type parameter `Args` defined here
--> src/main.rs:56:21
|
56 | pub type Lambda<'a, Args, Res> = dyn for<'b> Fn(Args<'b>) -> Pin<Box<dyn Future<Output = Result<Res, String>> + Send + 'b>>
| ^^^^
error[E0582]: binding for associated type `Output` references lifetime `'b`, which does not appear in the trait input types
--> src/main.rs:56:62
|
56 | pub type Lambda<'a, Args, Res> = dyn for<'b> Fn(Args<'b>) -> Pin<Box<dyn Future<Output = Result<Res, String>> + Send + 'b>>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Some errors have detailed explanations: E0109, E0582.
For more information about an error, try `rustc --explain E0109`.
How can I allow lifetime args on type parameter Args?

push on SelectAll Stream

I would like to have a struct for handling some streams. All streams share the same Item. The logic is the following: I need to create a unique stream that contains all items that came from all other streams. I need also to add "new" stream to the "main" stream. I don't care from which stream the next item comes from.
For doing that, I see there's the select_all function that should do the logic described above.
pub struct WsPool {
merge: Arc<Mutex<SelectAll<Box<dyn Stream<Item=MyItem> + Send + 'static>>>>,
}
impl WsPool {
pub fn new() -> Self {
Self {
merge: Arc::new(Mutex::new(SelectAll::new())),
}
}
pub fn add(&self, s: Box<dyn Stream<Item = MyItem> + Send + 'static>) {
let mut merge = self.merge.lock().unwrap();
merge.push(s);
}
pub async fn process(&self) {
loop {
let mut merge = self.merge.lock().unwrap();
let item = merge.await.next();
}
}
}
But I receive these errors:
error[E0277]: `std::sync::MutexGuard<'_, futures::stream::SelectAll<Box<(dyn futures::Stream<Item = MyItem> + std::marker::Send + 'static)>>>` is not a future
--> src/ws_pool.rs:30:24
|
30 | let item = merge.await.next();
| ^^^^^^^^^^^ `std::sync::MutexGuard<'_, futures::stream::SelectAll<Box<(dyn futures::Stream<Item = MyItem> + std::marker::Send + 'static)>>>` is not a future
|
= help: the trait `futures::Future` is not implemented for `std::sync::MutexGuard<'_, futures::stream::SelectAll<Box<(dyn futures::Stream<Item = MyItem> + std::marker::Send + 'static)>>>`
note: required by `futures::Future::poll`
--> /home/allevo/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/future/future.rs:99:5
|
99 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: `(dyn futures::Stream<Item = MyItem> + std::marker::Send + 'static)` cannot be unpinned
--> src/ws_pool.rs:17:40
|
17 | merge: Arc::new(Mutex::new(SelectAll::new())),
| ^^^^^^^^^^^^^^^^ the trait `Unpin` is not implemented for `(dyn futures::Stream<Item = MyItem> + std::marker::Send + 'static)`
|
= note: consider using `Box::pin`
= note: required because of the requirements on the impl of `futures::Stream` for `Box<(dyn futures::Stream<Item = MyItem> + std::marker::Send + 'static)>`
note: required by `futures::stream::SelectAll::<St>::new`
--> /home/allevo/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.17/src/stream/select_all.rs:47:5
|
47 | pub fn new() -> Self {
| ^^^^^^^^^^^^^^^^^^^^
error[E0599]: the method `push` exists for struct `std::sync::MutexGuard<'_, futures::stream::SelectAll<Box<(dyn futures::Stream<Item = MyItem> + std::marker::Send + 'static)>>>`, but its trait bounds were not satisfied
--> src/ws_pool.rs:24:15
|
24 | merge.push(s);
| ^^^^ method cannot be called on `std::sync::MutexGuard<'_, futures::stream::SelectAll<Box<(dyn futures::Stream<Item = MyItem> + std::marker::Send + 'static)>>>` due to unsatisfied trait bounds
|
::: /home/allevo/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/boxed.rs:172:1
|
172 | / pub struct Box<
173 | | T: ?Sized,
174 | | #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
175 | | >(Unique<T>, A);
| |________________- doesn't satisfy `_: futures::Stream`
|
= note: the following trait bounds were not satisfied:
`Box<(dyn futures::Stream<Item = MyItem> + std::marker::Send + 'static)>: futures::Stream`
What am I doing wrong? Otherwise how can I store multiple streams and iterate over them?
Your first problem is a simple mixup. You want to await the next value, not the stream itself:
let item = merge.next().await;
The resulting errors are all because SelectAll<Box<dyn Stream + Send + 'static>> does not implement Stream. If you look at the impl Stream for SelectAll, it is constrained that the inner stream type implements Unpin.
You can fix this by adding it to the bounds:
use std::marker::Unpin;
// vvvvv
Arc<Mutex<SelectAll<Box<dyn Stream<Item=MyItem> + Unpin + Send + 'static>>>>
Or a better solution is to just pin the streams:
use std::pin::Pin;
// vvv
Arc<Mutex<SelectAll<Pin<Box<dyn Stream<Item=MyItem> + Send + 'static>>>>>
The difference is the latter can accept more Stream types. You just have to use Box::pin when adding them.
See it working on the Playground.

Wrap an async function

The AWS Lambda Runtime for rust requires handlers be like async fn handler(event: Value, cx: Context) -> Result<Value, Error>. It handles the errors you return internally, but I don't like how it logs them. I want to create a function that I can pass a handler function and it returns me a wrapped version, which just calls the original, inspects its results, maybe logs, and returns the results. This has proved ... difficult.
I've managed to do it with a macro, but I can't work out how to make a real function do it. Any help would be much appreciated. Code:
use anyhow::{Result};
use lambda_runtime::{handler_fn, Context, Error};
use serde_json::{Value};
// handler
async fn handler(event: Value, cx: Context) -> Result<Value> {
Ok(())
}
// non-generic version (works)
async fn wrapper(event: Value, cx: Context) -> Result<Value> {
let res = handler(event, cx).await;
if let Err(e) = &res {
log::error!("got error from handler: {:?}", &e);
}
res
}
// macro (works)
macro_rules! wrap_handler {
($f:ident) => {{
|e: Value, c: Context| async {
let res = $f(e, c).await;
if let Err(e) = &res {
log::error!("got error from handler: {:?}", &e);
}
res
}
}};
}
// attempt at generic wrapper-creator fn
// should take the function to wrap, and return a Fn wrapping it
use std::future::Future;
use std::pin::Pin;
pub fn make_wrapper<F, FO>(
f: F,
) -> Box<dyn Fn(Value, Context) -> Pin<Box<dyn Future<Output = Result<Value>> + 'static>> + 'static>
where
F: Fn(Value, Context) -> FO + 'static,
FO: Future<Output = Result<Value>> + 'static,
{
use std::sync::Arc;
let af = Arc::new(f);
Box::new(move |v: Value, c: Context| {
let my_f = af.clone();
Box::pin(async move {
//
my_f(v, c).await
})
})
}
// main
#[tokio::main]
async fn main() -> Result<(), Error> {
// use the non-generic version
let func = handler_fn(wrapper);
// OR
// use the macro
let func = handler_fn(wrap_handler!(handler));
// OR
// use the generic wrapper function
let func = handler_fn(make_wrapper(handler));
lambda_runtime::run(func).await?;
Ok(())
}
The error with my latest attempt (the fn in the code above) is:
error[E0277]: `dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>` cannot be sent between threads safely
--> src/bin/classify-partition.rs:126:25
|
126 | lambda_runtime::run(func).await?;
| ^^^^ `dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>` cannot be sent between threads safely
|
::: /home/miles/.cargo/registry/src/github.com-1ecc6299db9ec823/lambda_runtime-0.3.0/src/lib.rs:294:24
|
294 | F: Handler<A, B> + Send + Sync + 'static,
| ---- required by this bound in `run`
|
= help: the trait `Send` is not implemented for `dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>`
= note: required because of the requirements on the impl of `Send` for `Unique<dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>>`
= note: required because it appears within the type `Box<dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>>`
= note: required because it appears within the type `HandlerFn<Box<dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>>>`
error[E0277]: `dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>` cannot be shared between threads safely
--> src/bin/classify-partition.rs:126:25
|
126 | lambda_runtime::run(func).await?;
| ^^^^ `dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>` cannot be shared between threads safely
|
::: /home/miles/.cargo/registry/src/github.com-1ecc6299db9ec823/lambda_runtime-0.3.0/src/lib.rs:294:31
|
294 | F: Handler<A, B> + Send + Sync + 'static,
| ---- required by this bound in `run`
|
= help: the trait `Sync` is not implemented for `dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>`
= note: required because of the requirements on the impl of `Sync` for `Unique<dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>>`
= note: required because it appears within the type `Box<dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>>`
= note: required because it appears within the type `HandlerFn<Box<dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>>>`
error[E0277]: `(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)` cannot be sent between threads safely
--> src/bin/classify-partition.rs:126:25
|
126 | lambda_runtime::run(func).await?;
| ^^^^ `(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)` cannot be sent between threads safely
|
= help: the trait `Send` is not implemented for `(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)`
= note: required because of the requirements on the impl of `Send` for `Unique<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>`
= note: required because it appears within the type `Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>`
= note: required because it appears within the type `Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>`
= note: required because of the requirements on the impl of `Handler<Value, Value>` for `HandlerFn<Box<dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>>>`
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0277`.
error: could not compile `enrichment-service-functions`
To learn more, run the command again with --verbose.

How can I put an async function into a map in Rust?

I cannot handle async functions when writing an async router for hyper.
This code:
use std::collections::HashMap;
use std::future::Future;
type BoxedResult<T> = Result<T, Box<dyn std::error::Error + Send + Sync>>;
type CalcFn = Box<dyn Fn(i32, i32) -> dyn Future<Output = BoxedResult<i32>>>;
async fn add(a: i32, b: i32) -> BoxedResult<i32> {
Ok(a + b)
}
async fn sub(a: i32, b: i32) -> BoxedResult<i32> {
Ok(a - b)
}
fn main() {
let mut map: HashMap<&str, CalcFn> = Default::default();
map.insert("add", Box::new(add));
map.insert("sub", Box::new(sub));
println!("map size: {}", map.len());
}
Generates the following compiler error:
error[E0271]: type mismatch resolving `<fn(i32, i32) -> impl std::future::Future {add} as std::ops::FnOnce<(i32, i32)>>::Output == dyn std::future::Future<Output = std::result::Result<i32, std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>>`
--> src/main.rs:17:23
|
17 | map.insert("add", Box::new(add));
| ^^^^^^^^^^^^^ expected opaque type, found trait std::future::Future
|
= note: expected type `impl std::future::Future`
found type `dyn std::future::Future<Output = std::result::Result<i32, std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>>`
= note: required for the cast to the object type `dyn std::ops::Fn(i32, i32) -> dyn std::future::Future<Output = std::result::Result<i32, std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>>`
error[E0271]: type mismatch resolving `<fn(i32, i32) -> impl std::future::Future {sub} as std::ops::FnOnce<(i32, i32)>>::Output == dyn std::future::Future<Output = std::result::Result<i32, std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>>`
--> src/main.rs:18:23
|
18 | map.insert("sub", Box::new(sub));
| ^^^^^^^^^^^^^ expected opaque type, found trait std::future::Future
|
= note: expected type `impl std::future::Future`
found type `dyn std::future::Future<Output = std::result::Result<i32, std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>>`
= note: required for the cast to the object type `dyn std::ops::Fn(i32, i32) -> dyn std::future::Future<Output = std::result::Result<i32, std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>>`
It seems there is a conflict between impl Future and dyn Future, but I have no idea how to handle it.
This happens because impl Future is a concrete unique type while dyn Future is an abstract type. HashMap expects the abstract type since it can only hold instances of a single type.
If we can box the return type of the async functions, we will able to add these futures into a HashMap.
First we need to change the type of CalcFn:
type CalcFn = Box<dyn Fn(i32, i32) -> Pin<Box<dyn Future<Output = i32>>>>;
Then this can do the trick:
let mut map: HashMap<&str, CalcFn> = Default::default();
map.insert("add", Box::new(|a, b| Box::pin(add(a, b))));
map.insert("sub", Box::new(|a, b| Box::pin(sub(a, b))));
println!("map size: {}", map.len());
//map.get("add").unwrap()(2, 3).await
This complete example
simplified Future's Item type, using an i32 instead of a Result. Please also check the full code for your case.
You can also use types from the futures crate like LocalBoxFuture and BoxFuture created by the FutureExt::boxed and FutureExt::boxed_local methods respectively:
use futures::future::{FutureExt, LocalBoxFuture}; // 0.3.5
use std::collections::HashMap;
type BoxedResult<T> = Result<T, Box<dyn std::error::Error + Send + Sync>>;
type CalcFn = Box<dyn Fn(i32, i32) -> LocalBoxFuture<'static, BoxedResult<i32>>>;
async fn add(a: i32, b: i32) -> BoxedResult<i32> {
Ok(a + b)
}
async fn sub(a: i32, b: i32) -> BoxedResult<i32> {
Ok(a - b)
}
async fn example() {
let mut map: HashMap<&str, CalcFn> = Default::default();
map.insert("add", Box::new(|a, b| add(a, b).boxed()));
map.insert("sub", Box::new(|a, b| sub(a, b).boxed()));
println!("map size: {}", map.len());
//map.get("add").unwrap()(2, 3).await
}

How to join_all from a Vec of closures that return asyncs?

I want to generate a Vec of .awaits and execute them with join_all:
use futures::future::join_all; // 0.3.5
use std::future::Future;
async fn hello(name: &str) -> String {
format!("Hello {}!", name)
}
async fn main() {
let urls = vec!["Peter", "Hans", "Jake"];
let mut requests: Vec<Box<dyn Fn() -> Box<dyn Future<Output = String>>>> = vec![];
for url in urls {
requests.push(Box::new(|| Box::new(hello(&url))));
}
let responses: Vec<String> = join_all(requests).await;
println!("Response: {:?}", responses);
}
I get the error message:
error[E0277]: `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>` cannot be unpinned
--> src/main.rs:15:45
|
15 | let responses : Vec<String> = join_all(requests).await;
| ^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>`
|
::: /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.5/src/future/join_all.rs:83:14
|
83 | I::Item: Future,
| ------ required by this bound in `futures::future::join_all`
|
= note: required because of the requirements on the impl of `futures::Future` for `std::boxed::Box<dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>>`
error[E0277]: `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>` is not a future
--> src/main.rs:15:45
|
15 | let responses : Vec<String> = join_all(requests).await;
| ^^^^^^^^ `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>` is not a future
|
::: /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.5/src/future/join_all.rs:83:14
|
83 | I::Item: Future,
| ------ required by this bound in `futures::future::join_all`
|
= help: the trait `futures::Future` is not implemented for `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>`
= note: required because of the requirements on the impl of `futures::Future` for `std::boxed::Box<dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>>`
error[E0277]: `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>` cannot be unpinned
--> src/main.rs:15:36
|
15 | let responses : Vec<String> = join_all(requests).await;
| ^^^^^^^^^^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>`
|
::: /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.5/src/future/join_all.rs:28:8
|
28 | F: Future,
| ------ required by this bound in `futures::future::JoinAll`
|
= note: required because of the requirements on the impl of `futures::Future` for `std::boxed::Box<dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>>`
error[E0277]: `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>` is not a future
--> src/main.rs:15:36
|
15 | let responses : Vec<String> = join_all(requests).await;
| ^^^^^^^^^^^^^^^^^^ `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>` is not a future
|
::: /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.5/src/future/join_all.rs:28:8
|
28 | F: Future,
| ------ required by this bound in `futures::future::JoinAll`
|
= help: the trait `futures::Future` is not implemented for `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>`
= note: required because of the requirements on the impl of `futures::Future` for `std::boxed::Box<dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>>`
error[E0277]: `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>` cannot be unpinned
--> src/main.rs:15:36
|
15 | let responses : Vec<String> = join_all(requests).await;
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>`
|
= note: required because of the requirements on the impl of `futures::Future` for `std::boxed::Box<dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>>`
error[E0277]: `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>` is not a future
--> src/main.rs:15:36
|
15 | let responses : Vec<String> = join_all(requests).await;
| ^^^^^^^^^^^^^^^^^^^^^^^^ `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>` is not a future
|
= help: the trait `futures::Future` is not implemented for `dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>`
= note: required because of the requirements on the impl of `futures::Future` for `std::boxed::Box<dyn std::ops::Fn() -> std::boxed::Box<dyn futures::Future<Output = std::string::String>>>`
error[E0277]: `main` has invalid return type `impl futures::Future`
--> src/main.rs:9:17
|
9 | async fn main() {
| ^ `main` can only return types that implement `std::process::Termination`
|
= help: consider using `()`, or a `Result`
error[E0752]: `main` function is not allowed to be `async`
--> src/main.rs:9:1
|
9 | async fn main() {
| ^^^^^^^^^^^^^^^ `main` function is not allowed to be `async`
join_all requires an iterator of futures, not an iterator of functions returning futures:
pub fn join_all<I>(i: I) -> JoinAll<<I as IntoIterator>::Item>
where
I: IntoIterator,
<I as IntoIterator>::Item: Future,
Additionally, your futures can't be pinned and so join_all cannot use them.
The shortest fix is to:
Call the closure
Pin the future
use futures::future; // 0.3.5
use std::{future::Future, pin::Pin};
async fn hello(name: &str) -> String {
format!("Hello {}!", name)
}
pub async fn example() {
let urls = vec!["Peter", "Hans", "Jake"];
let mut requests: Vec<Box<dyn Fn() -> Pin<Box<dyn Future<Output = String>>>>> = vec![];
for url in urls {
requests.push(Box::new(move || Box::pin(hello(&url))));
}
let responses: Vec<String> = future::join_all(requests.into_iter().map(|r| r())).await;
println!("Response: {:?}", responses);
}
This can be written more succinctly as:
use futures::future::{self, FutureExt, LocalBoxFuture}; // 0.3.5
async fn hello(name: &str) -> String {
format!("Hello {}!", name)
}
pub async fn example() {
let urls = vec!["Peter", "Hans", "Jake"];
let mut requests: Vec<Box<dyn Fn() -> LocalBoxFuture<'static, String>>> = vec![];
for url in urls {
requests.push(Box::new(move || hello(&url).boxed_local()));
}
let responses: Vec<String> = future::join_all(requests.into_iter().map(|r| r())).await;
println!("Response: {:?}", responses);
}
However, none of that is needed for your specific example:
The closure doesn't provide any value
You have one type of future so there's no need for dynamic dispatch
You don't even need a Vec
use futures::future; // 0.3.5
async fn hello(name: &str) -> String {
format!("Hello {}!", name)
}
pub async fn example() {
let urls = vec!["Peter", "Hans", "Jake"];
let hellos = urls.iter().map(|u| hello(u));
let responses = future::join_all(hellos).await;
println!("Response: {:?}", responses);
}
See also:
How can I put an async function into a map in Rust?
Cannot use `impl Future` to store async function in a vector

Resources