How can one await a result of a boxed future? - rust

use futures::{future, Future};
fn test() -> Box<dyn Future<Output = bool>> {
Box::new(future::ok::<bool>(true))
}
async fn async_fn() -> bool {
let result: bool = test().await;
return result;
}
fn main(){
async_fn();
println!("Hello!");
}
Playground
Error:
error[E0277]: the trait bound `dyn core::future::future::Future<Output = bool>: std::marker::Unpin` is not satisfied
--> src/main.rs:8:24
|
8 | let result: bool = test().await;
| ^^^^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `dyn core::future::future::Future<Output = bool>`
|
= note: required because of the requirements on the impl of `core::future::future::Future` for `std::boxed::Box<dyn core::future::future::Future<Output = bool>>`

According to the implementation:
impl<F> Future for Box<F>
where
F: Unpin + Future + ?Sized,
Boxed futures only implement the Future trait when the future inside the Box implements Unpin.
Since your function doesn't guarantee that the returned future implements Unpin, your return value will be considered to not implement Future. You'll not able to await it because your type is basically not a Future.
The solution from #Stargateur, adding an explicit type boundary to the signature, works (Playground):
fn test() -> Box<dyn Future<Output = Result<bool, ()>> + Unpin>
If you are using futures-rs, there is a helper type BoxFuture. You can use BoxedFuture without explicitly stating Unpin:
use futures::future::BoxFuture;
fn test() -> BoxFuture<'static, Result<bool, ()>> {
Box::pin(async { Ok(true) })
}
Playground

When it comes to Box and future, it almost always make sense to use Box::pin instead of Box::new:
use std::pin::Pin;
use futures::{future, Future};
fn test() -> Pin<Box<dyn Future<Output = Result<bool, ()>>>> {
Box::pin(future::ok(true))
}
async fn async_fn() -> bool {
test().await.unwrap()
}
The reason is quite interesting. Pin has a blanket implementation for Unpin:
impl<P> Unpin for Pin<P> where
P: Unpin,
And the Box<T> inside it is unconditionally Unpin:
impl<T> Unpin for Box<T> where
T: ?Sized,
So a Pin<Box<dyn Future>> is a unpinned Future. Everything works out, but why Box itself doesn't? This is one place where Deref gets in the way:
impl<T: ?Sized> Deref for Box<T> {
type Target = T;
}
await expects an unpinned Future, and the Box<dyn Future> you created with Box::new does contain a Future. So it is auto-dereferenced and the Unpin is lost unless you explicitly state it that way with Box<dyn Future + Unpin>.
Edit: #ÖmerErden is right about why Box<dyn Future> wouldn't work.

Related

Writing an async function that calls another async function

I am trying to create a async function which takes a function pointer as a parameter. It does some stuff, calls the function, awaits on the result, then does some more stuff:
use std::future::Future;
async fn run_another_async_fn<F, Fut>(f: F)
where
Fut: Future<Output = ()>,
F: FnOnce(&mut i32) -> Fut,
{
let mut i = 42;
println!("running function");
f(&mut i).await;
println!("ran function");
}
async fn foo(i: &mut i32) {}
async fn bar() {
run_another_async_fn(foo);
}
[view on Rust Playground]
Unfortunately this fails to compile:
error[E0308]: mismatched types
--> src/lib.rs:17:5
|
17 | run_another_async_fn(foo);
| ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected associated type `<for<'_> fn(&mut i32) -> impl Future {foo} as FnOnce<(&mut i32,)>>::Output`
found associated type `<for<'_> fn(&mut i32) -> impl Future {foo} as FnOnce<(&mut i32,)>>::Output`
= note: the required lifetime does not necessarily outlive the empty lifetime
note: the lifetime requirement is introduced here
--> src/lib.rs:6:28
|
6 | F: FnOnce(&mut i32) -> Fut,
| ^^^
Firstly, it seems the compiler found exactly what it expected but it's complaining anyway?
Secondly, what's "the empty lifetime"? I guess it must mean the '_, does that have some special significance?
Finally, what's the way to get this to compile?
The issue is that there is no way to specify the same lifetime for F and Fut in the where clause.
Luckily (if you don't mind heap allocating the future) there is an easy workaround. You can use the already existing futures::future::BoxFuture; which looks like:
pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
With its help you can specify the same lifetime parameter for both the borrow and as a trait bound for the future:
where for<'a> F: FnOnce(&'a mut i32) -> BoxFuture<'a, ()>,
You also have to add an adapter function which will have the correct return type - i.e. BoxFuture<'_, T> instead of impl Future:
fn asd(i: &mut i32) -> BoxFuture<'_, ()> {
foo(i).boxed()
}
or use a closure:
run_another_async_fn(|i| foo(i).boxed());
As a result your code would look like:
use futures::future::BoxFuture;
use futures::FutureExt;
use std::future::Future;
async fn run_another_async_fn<F>(f: F)
where
for<'a> F: FnOnce(&'a mut i32) -> BoxFuture<'a, ()>,
{
let mut i = 42;
println!("running function");
f(&mut i).await;
println!("ran function");
}
fn asd(i: &mut i32) -> BoxFuture<'_, ()> {
foo(i).boxed()
}
async fn foo<'a>(i: &'a mut i32) {
// no-op
}
async fn bar() {
run_another_async_fn(asd);
run_another_async_fn(|i| foo(i).boxed());
}

Simple future example

I'm trying to do a simple future example. I followed https://blog.logrocket.com/a-practical-guide-to-async-in-rust/
So I did:
use futures::Future;
type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
pub async fn receive_fut(
f: &mut dyn FnMut(&[u8])
) -> impl Future<Output = Result<Vec<u8>>> {
futures::future::ok(Ok(Vec::new())).await
}
but I get
error[E0277]: `std::result::Result<std::result::Result<Vec<_>, _>, _>` is not a future
--> src/lib.rs:6:10
|
6 | ) -> impl Future<Output = Result<Vec<u8>>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::result::Result<std::result::Result<Vec<_>, _>, _>` is not a future
|
= help: the trait `futures::Future` is not implemented for `std::result::Result<std::result::Result<Vec<_>, _>, _>`
error: aborting due to previous error
Why std::result::Result should implement future, if I used futures::future::ok to turn it into a future result?
This is answered in the article:
Async functions differ in one important way: all your return types are “wrapped” into a Future.
You might read the documentation about Futures in Rust and think your async function needs to look like this:
async fn our_async_program() -> impl Future<Output = Result<String>> {
future::ok("Hello world".to_string()).await
}
This is wrong! If you’re doing this, you’re overthinking it. An async function already wraps the return type, so you can write functions the way you’re used to.
This is what you actually want:
async fn our_async_program() -> Result<String> {
future::ok("Hello world".to_string()).await
}
So you'd want to drop the impl Future<... part of the return type:
pub async fn receive_fut(
f: &mut dyn FnMut(&[u8])
) -> Result<Vec<u8>> {
futures::future::ok(Ok(Vec::new())).await
}
And then realize that future::ok already yields a Result::Ok, so you don't need to wrap it in Ok() again.
pub async fn receive_fut(
f: &mut dyn FnMut(&[u8])
) -> Result<Vec<u8>> {
futures::future::ok(Vec::new()).await
}

Storing FnMut in struct gives lifetime problems

I'm trying to store a FnMut in a struct:
struct OpenVPNSocket {
socket_send_callback: Option<Box<dyn FnMut(Vec<u8>) -> Result<(), ()>>>,
}
impl OpenVPNSocket {
fn set_socket_send<F: FnMut(Vec<u8>) -> Result<(), ()>>(&mut self, callback: Box<F>) {
self.socket_send_callback = Some(callback);
}
}
I get this error:
error[E0310]: the parameter type `F` may not live long enough
--> src/lib.rs:8:42
|
7 | fn set_socket_send<F: FnMut(Vec<u8>) -> Result<(), ()>>(&mut self, callback: Box<F>) {
| -- help: consider adding an explicit lifetime bound...: `F: 'static +`
8 | self.socket_send_callback = Some(callback);
| ^^^^^^^^ ...so that the type `F` will meet its required lifetime bounds
I understand lifetime as something to do with references. However I don't use references. I don't see why my struct cannot store a Box. A Box lives as long as it's used.
UPDATE:
I have this example:
use std::sync::Arc;
pub type OnConsume = Arc<dyn Fn() -> Option<u8> + Send + Sync>;
struct Test {
callback: OnConsume
}
impl Test {
fn set_on_consume(&mut self, f: OnConsume) {
self.callback = f;
}
}
which works. What is the difference from the previous one?
In Rust, values also have lifetimes. Take, for example, this struct:
struct RefWrapper<'a> {
some_ref: &'a u32
}
An instance of RefWrapper is not a reference, but contains a lifetime. Since you're moving the box into the struct, which could live for the duration of the program (the method makes no guarantees as to when the struct instance could be dropped), the function must live for the maximum lifetime, the static lifetime.
All trait objects have lifetimes, the default implicit lifetime for boxed trait objects is 'static so your struct's socket_send_callback actually has an implicit + 'static bound. Shown in context:
struct OpenVPNSocket {
socket_send_callback: Option<Box<dyn FnMut(Vec<u8>) -> Result<(), ()> + 'static>>,
}
Since the boxed trait object has to be bounded by a 'static lifetime when you write a function to set this field the value itself must have a 'static lifetime which is why the compiler suggests adding that explicit bound. Fixed example with added bound:
impl OpenVPNSocket {
// notice the added 'static bound for F
fn set_socket_send<F: FnMut(Vec<u8>) -> Result<(), ()> + 'static>(&mut self, callback: Box<F>) {
self.socket_send_callback = Some(callback);
}
}
With this change your code will compile. If you want to accept trait objects that aren't bounded by 'static lifetimes then you can do that by making your OpenVPNSocket generic over lifetimes. This alternative solution also compiles:
struct OpenVPNSocket<'a> {
socket_send_callback: Option<Box<dyn FnMut(Vec<u8>) -> Result<(), ()> + 'a>>,
}
impl<'a> OpenVPNSocket<'a> {
fn set_socket_send<F: FnMut(Vec<u8>) -> Result<(), ()> + 'a>(&mut self, callback: Box<F>) {
self.socket_send_callback = Some(callback);
}
}
The reason why this code works is because you define the type once and use it in multiple places, and in all places it has the implicit 'static bound. Desugared:
use std::sync::Arc;
pub type OnConsume = Arc<dyn Fn() -> Option<u8> + Send + Sync + 'static>;
struct Test {
callback: OnConsume
}
impl Test {
fn set_on_consume(&mut self, f: OnConsume) {
self.callback = f;
}
}
However you can do the exact same thing in your prior code as well:
type Callback = Box<dyn FnMut(Vec<u8>) -> Result<(), ()>>;
struct OpenVPNSocket {
socket_send_callback: Option<Callback>,
}
impl OpenVPNSocket {
fn set_socket_send(&mut self, callback: Callback) {
self.socket_send_callback = Some(callback);
}
}
The above also compiles, and the implicit 'static bound is still there.

Why can't Box<dyn T> be used as an associated type which needs to implement T? [duplicate]

I’ve the following simplified code.
use async_trait::async_trait; // 0.1.36
use std::error::Error;
#[async_trait]
trait Metric: Send {
type Output;
type Error: Error;
async fn refresh_metric(&mut self) -> Result<Self::Output, Self::Error>;
}
#[derive(Default)]
struct StaticMetric;
#[async_trait]
impl Metric for StaticMetric {
type Output = ();
type Error = Box<dyn Error>;
async fn refresh_metric(&mut self) -> Result<Self::Output, Self::Error> {
Ok(())
}
}
struct LocalSystemData<T> {
inner: T,
}
impl<T> LocalSystemData<T>
where
T: Metric,
<T as Metric>::Error: 'static,
{
fn new(inner: T) -> LocalSystemData<T> {
LocalSystemData { inner }
}
async fn refresh_all(&mut self) -> Result<(), Box<dyn Error>> {
self.inner.refresh_metric().await?;
Ok(())
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let mut sys_data = LocalSystemData::new(StaticMetric::default());
sys_data.refresh_all().await?;
Ok(())
}
Playground
The compiler throws the following error
error[E0277]: the size for values of type `(dyn std::error::Error + 'static)` cannot be known at compilation time
--> src/main.rs:18:18
|
5 | trait Metric: Send {
| ------ required by a bound in this
6 | type Output;
7 | type Error: Error;
| ----- required by this bound in `Metric`
...
18 | type Error = Box<dyn Error>;
| ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `(dyn std::error::Error + 'static)`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required because of the requirements on the impl of `std::error::Error` for `std::boxed::Box<(dyn std::error::Error + 'static)>`
I'm not really sure if I understand the problem correct.
I’m using Box<dyn Error> because I don’t have a concrete type and boxing an error can handle all errors. In my implementation of LocaSystemData, I added <T as Metric>::Error: 'static (the compiler gave me that hint, not my idea). After I added the 'static requirement the compiler complains about that the size is unknown. This happens because the size of a 'static type should always known at compile time because the implication of static.
I changed the Metric trait so that I get rid of the type Error; Now I've the following async trait function and my code compiles
Playground
async fn refresh_metric(&mut self) -> Result<Self::Output, Box<dyn Error>>;
Why does my second version compile and the first one does not? For me as a human the code does exactly the same. I feel I tricked the compiler :-).
The error message is a bit misleading, as it represents an intermediate issue that emerged during type constraint resolution. The same problem can be reproduced without async.
use std::error::Error;
trait Metric {
type Error: Error;
}
struct StaticMetric;
impl Metric for StaticMetric {
type Error = Box<dyn Error>;
}
The root of the problem is that Box<dyn Error> does not implement std::error::Error. And as specified by the implementation of From<Box<E>> for Box<dyn Error>, the inner type E must also be Sized.
impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a>
Therefore, Box<dyn Error> should not be assigned to the associated type Metric::Error.
Other than getting rid of the associated type altogether, this can be fixed by introducing your own new error type which can flow into the main function.
#[derive(Debug, Default)]
struct MyErr;
impl std::fmt::Display for MyErr {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_str("I AM ERROR")
}
}
impl Error for MyErr {}
#[async_trait]
impl Metric for StaticMetric {
type Output = ();
type Error = MyErr;
async fn refresh_metric(&mut self) -> Result<Self::Output, Self::Error> {
Ok(())
}
}
Playground
See also:
How do you define custom `Error` types in Rust?
How can I implement From for both concrete Error types and Box<Error> in Rust?

Why can't Result be treated as a Future even though it implements IntoFuture?

std::result::Result implements IntoFuture, but the following code doesn't compile:
extern crate futures; // 0.1.25
use futures::{future::Either, prelude::*, sync::mpsc};
fn example() -> impl Future<Item = (), Error = ()> {
let (tx, rx) = mpsc::channel(0);
let data = Some(1);
match data {
Some(d) => Either::A(tx.send(d).and_then(|x| Ok(())).map_err(|e| ())),
None => Either::B(Ok(()) as Result<(), ()>),
}
}
Full error message:
error[E0277]: the trait bound `std::result::Result<(), ()>: futures::Future` is not satisfied
--> src/lib.rs:5:17
|
5 | fn example() -> impl Future<Item = (), Error = ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `futures::Future` is not implemented for `std::result::Result<(), ()>`
|
= note: required because of the requirements on the impl of `futures::Future` for `futures::future::Either<futures::MapErr<futures::AndThen<futures::sink::Send<futures::sync::mpsc::Sender<{integer}>>, std::result::Result<(), futures::sync::mpsc::SendError<{integer}>>, [closure#src/lib.rs:9:50: 9:60]>, [closure#src/lib.rs:9:70: 9:76]>, std::result::Result<(), ()>>`
= note: the return type of a function must have a statically known size
Moreover, IntoFuture doesn't require Sized. Why can't Result<(), ()> be treated as a Future here?
Either only implements Future when both of its children implement Future and their types line up:
impl<A, B> Future for Either<A, B>
where
A: Future,
B: Future<Item = A::Item, Error = A::Error>,
Result does not implement Future, so placing a Result directly inside of an Either will not implement Future either.
The IntoFuture trait is orthogonal to Future. As its documentation states:
This trait is very similar to the IntoIterator trait and is intended to be used in a very similar fashion.
You can't call Iterator::map on a Vec (vec![1, 2, 3].map(...)), even though Vec implements IntoIterator, and the same logic applies to Result / Future / IntoFuture.
Most of the time, you will want to use futures::ok:
extern crate futures; // 0.1.25
use futures::{
future::{self, Either},
prelude::*,
sync::mpsc,
};
fn example() -> impl Future<Item = (), Error = ()> {
let (tx, _) = mpsc::channel(0);
let data = Some(1);
match data {
Some(d) => Either::A(tx.send(d).map(|_| ()).map_err(|_| ())),
None => Either::B(future::ok(())),
}
}
You could also choose to call into_future directly:
Either::B(Ok(()).into_future())

Resources