Reputation: 1894
pub async fn send_and_expect(&mut self, request: rtsp_types::Request<Body>, retrying: bool) -> std::result::Result<rtsp_types::Response<Body>, ClientActionError> {
I get:
recursion in an `async fn` requires boxing
recursive `async fn`
note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`rustc(E0733)
I found https://rust-lang.github.io/async-book/07_workarounds/04_recursion.html but it is for a function that does not use async
.
What should be the way here?
I found Why recursive async functions require 'static parameters in Rust? and I changed my function to
pub fn send_and_expect(&mut self, request: rtsp_types::Request<Body>, retrying: bool)
-> Pin<Box<dyn Future <Output = std::result::Result<rtsp_types::Response<Body>, ClientActionError>>>> {
but now I cannot use await
inside my funtion. Also, how do I return things?
For example:
return Box::pin(Err(ClientActionError::CSeqMissing))
won't work
UPDATE:
Based on the answer, below, I get this on the recursion call:
194 | }.boxed()
| ^^^^^ future created by async block is not `Send`
|
= help: the trait `std::marker::Send` is not implemented for `dyn futures::Future<Output = std::result::Result<rtsp_types::Response<Body>, ClientActionError>>`
note: future is not `Send` as it awaits another future which is not `Send`
--> src/client.rs:170:36
|
170 | ... return self.send_and_expect(request.clone(), true).await;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ await occurs here on type `Pin<Box<dyn futures::Future<Output = std::result::Result<rtsp_types::Response<Body>, ClientActionError>>>>`, which is not `Send`
UPDATE 2:
error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> src/client.rs:156:20
|
154 | pub fn send_and_expect(&mut self, request: rtsp_types::Request<Body>, retrying: bool)
| --------- this data with an anonymous lifetime `'_`...
155 | -> Pin<Box<dyn Future<Output = std::result::Result<rtsp_types::Response<Body>, ClientActionError>>+ Send>> {
156 | async move {
| ____________________^
157 | | let expected_cseq_header_value = rtsp_types::HeaderName::from_static_str("cseq").unwrap();
158 | | let expected_cseq = request.header(&expected_cseq_header_value);
159 | | let expected_cseq = match expected_cseq {
... |
193 | | Err(ClientActionError::Teardown)
194 | | }.boxed()
| |_________^ ...is captured here, requiring it to live as long as `'static`
|
help: to declare that the trait object captures data from argument `self`, you can add an explicit `'_` lifetime bound
|
155 | -> Pin<Box<dyn Future<Output = std::result::Result<rtsp_types::Response<Body>, ClientActionError>>+ Send + '_>> {
| ^^^^
Upvotes: 14
Views: 6843
Reputation: 375
Since Rust 1.77, this code now works:
async fn recursive_pinned() {
Box::pin(recursive_pinned()).await;
Box::pin(recursive_pinned()).await;
}
Reference: https://rust-lang.github.io/async-book/07_workarounds/04_recursion.html
Upvotes: 2
Reputation: 151
Also, in hopes that it'll help somebody else, there's a crate providing a macro to do the whole complicated function rewrite automatically: https://docs.rs/async-recursion/latest/async_recursion.
Upvotes: 0
Reputation: 60607
I found [...] but it is for a function that does not use
async
.
Yes it does. You should take a closer look at code. The original function is definitely async
:
async fn recursive() {
recursive().await;
recursive().await;
}
... but now I cannot use
await
inside my function.
You can if you make an async {}
block as the fix suggests:
use futures::future::{BoxFuture, FutureExt};
fn recursive() -> BoxFuture<'static, ()> {
async move {
recursive().await; // you can use await here
recursive().await;
}.boxed()
}
The idea is simply async return type needs to be boxed instead of an impl Future
. So the fix is to create an async {}
block, wherein you run your function as normal, and then box it in order to return it. This avoids the issue caused by nested async
/await
functions being monomorphised together.
So you should be able to:
pub fn send_and_expect(&mut self, request: rtsp_types::Request<Body>, retrying: bool)
-> Pin<Box<dyn Future<Output = std::result::Result<rtsp_types::Response<Body>, ClientActionError>> + Send>> {
// ^^^^^^
async move {
// put your original code here
}.boxed()
}
Also, how do I return things?
You can return things as normal, either via the last expression in the async
block, or you can use return
. You should simply the same as you would for a proper async
function, don't worry about the Box::pin(...)
.
If you need the Future
to satisfy any other trait bounds (Send
, Sync
, Unpin
, etc.) then you can specify it along with the dyn Future<...>
The return type requires dyn Future<Output = ...> + Send
to use .boxed()
.
If the contents of the async
block cannot be made Send
, you can do it manually like so (although most runtimes expect Future
s to be Send
so you'd have a hard time using it):
fn recursive() -> Pin<Box<dyn Future<Output = ()>>> {
Box::pin(async move {
recursive().await;
recursive().await;
})
}
Upvotes: 7