Description
I tried this code:
#![feature(async_fn_in_trait)]
#![feature(return_type_notation)]
trait Service<Request> {
type Output;
type Error;
async fn call(&mut self, req: Request) -> Result<Self::Output, Self::Error>;
}
struct EchoService;
impl<Request> Service<Request> for EchoService {
type Output = Request;
type Error = std::convert::Infallible;
async fn call(&mut self, req: Request) -> Result<Self::Output, Self::Error> {
Ok(req)
}
}
async fn higher_order_async_fn<S, Request>(mut svc: S, req: Request)
where
S: Service<Request, call(): Send> + Send + 'static,
S::Output: std::fmt::Debug + Send + 'static,
S::Error: std::fmt::Debug + Send + 'static,
Request: Send + 'static,
{
tokio::spawn(async move {
let output = svc.call(req).await.unwrap();
println!("{:?}", output);
})
.await
.unwrap();
}
#[tokio::main]
async fn main() {
higher_order_async_fn(EchoService, "Hello, World!").await;
}
Playground: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=b8b7d938b1f7ab5cfe4284e0cc6ab09c
I expected to see this happen: it should work and print "Hello, World!"
to the stdout.
Instead, this happened: I get a compile error:
error[[E0277]](https://doc.rust-lang.org/nightly/error_codes/E0277.html): `impl Future<Output = Result<<_ as Service<_>>::Output, <_ as Service<_>>::Error>>` cannot be sent between threads safely
--> src/main.rs:39:27
|
39 | higher_order_async_fn(EchoService, "Hello, World!").await;
| --------------------- ^^^^^^^^^^^ `impl Future<Output = Result<<_ as Service<_>>::Output, <_ as Service<_>>::Error>>` cannot be sent between threads safely
| |
| required by a bound introduced by this call
|
= help: the trait `for<'a> Send` is not implemented for `impl Future<Output = Result<<_ as Service<_>>::Output, <_ as Service<_>>::Error>>`
note: required by a bound in `higher_order_async_fn`
--> src/main.rs:24:33
|
22 | async fn higher_order_async_fn<S, Request>(mut svc: S, req: Request)
| --------------------- required by a bound in this function
23 | where
24 | S: Service<Request, call(): Send> + Send + 'static,
| ^^^^ required by this bound in `higher_order_async_fn`
For more information about this error, try `rustc --explain E0277`.
and E0277
refers to:
rustc --explain E0277
You tried to use a type which doesn't implement some trait in a place which expected that trait.
which is not really more helpful then the error msg itself.
Meta
Playground:
Nightly channel
Build using the Nightly version: 1.73.0-nightly
(2023-07-26 0d95f9132909ae7c5f24)
Local version:
rustc --version --verbose
:
rustc --version --verbose
rustc 1.72.0-nightly (cb80ff132 2023-07-07)
binary: rustc
commit-hash: cb80ff132a0e9aa71529b701427e4e6c243b58df
commit-date: 2023-07-07
host: aarch64-apple-darwin
release: 1.72.0-nightly
LLVM version: 16.0.5
Background
I also track this issue in plabayo/tower-async#9, an issue in the tower-async
repo, which is a monorepo of a fork of the https://github.com/tower-rs/tower and https://github.com/tower-rs/tower-http libraries that I made and maintain, making use of the new upcoming async support as advertised in https://blog.rust-lang.org/inside-rust/2023/05/03/stabilizing-async-fn-in-trait.html, which got me very excited and very invested in starting to prepare for that future.
tower-async
is then used by me in another project of mine, https://github.com/plabayo/rama, which is a going to be a general proxy framework with data extraction in mind.
Problem is however that it seems that the futures produced by the tower-async
Service
does not implement Send. And without my higher order functions requiring themethod(): Send
trait bound it won't compile either.
So:
- in worst case this is a bug in the current incomplete async-fn trait support
- or in best case it is me missing something obvious, or in other words not knowing how to use this properly. In which case I guess the error message could never the less still use some work as a solution is not immediately clear to me.
Similar to the other
F-async_fn_in_trait
rustc
:)
Thanks upfront!
Metadata
Metadata
Assignees
Labels
Type
Projects
Status