I'm using the async_trait crate to define an async method on a trait. I intend to transform the Future it returns into a Stream, wrap the Stream in an Arc and send the Arc over to multiple threads. Minimal reproducible code is as follows:
use async_trait::async_trait;
use futures::stream::{unfold, Stream};
use std::sync::Arc;
use tokio::runtime::Runtime;
#[async_trait]
trait Trait: Send + Sync {
async fn do_something(&self) -> i32;
}
async fn use_trait<T: Trait>(x: &T) {
let boxed: Arc<Box<dyn Stream<Item = i32> + Send + Sync>>;
let lazy_poller = unfold(None, move |state| async move {
if let Some(value) = state {
Some((value, Some(value)))
} else {
let value = x.do_something().await;
Some((value, Some(value)))
}
});
boxed = Arc::new(Box::new(lazy_poller));
let boxed_clone = boxed.clone();
let rt = Runtime::new().unwrap();
rt.block_on(async {
let _moved = boxed_clone;
// Do something with `_moved.next()`
});
}
However it compiled with the following error:
error: future cannot be shared between threads safely
--> src/main.rs:21:22
|
21 | boxed = Arc::new(Box::new(lazy_poller));
| ^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Sync`
|
= help: the trait `Sync` is not implemented for `dyn futures::Future<Output = i32> + std::marker::Send`
note: future is not `Sync` as it awaits another future which is not `Sync`
--> src/main.rs:17:25
|
17 | let value = x.do_something().await;
| ^^^^^^^^^^^^^^^^ await occurs here on type `Pin<Box<dyn futures::Future<Output = i32> + std::marker::Send>>`, which is not `Sync`
= note: required for the cast to the object type `dyn Stream<Item = i32> + Sync + std::marker::Send`
It seems that async_trait desugars the async methods' return types as Pin<Box<dyn Future<...> + Send>>, without specifying Sync. However I thought it would also be fairly common to require Futures to be Sync, in addition to Send.
My questions are:
How should I specify the async method's return type to be Sync, and
Why does async_traitnot specify Sync for the return types automatically?
After some searching I found that Futures do not need to be Sync for most of the use cases; and when it may be polled from different tasks, FutureExt::shared is the way to go. Closing
I'm using the
async_trait
crate to define anasync
method on a trait. I intend to transform theFuture
it returns into aStream
, wrap theStream
in anArc
and send theArc
over to multiple threads. Minimal reproducible code is as follows:However it compiled with the following error:
It seems that
async_trait
desugars the async methods' return types asPin<Box<dyn Future<...> + Send>>
, without specifyingSync
. However I thought it would also be fairly common to requireFuture
s to beSync
, in addition toSend
.My questions are:
Sync
, andasync_trait
not specifySync
for the return types automatically?