How do poll an async function in a function that returns a Future but itself is not async?

I am trying to implement FromRequest trait from actix-web
from_request method returns a future and I would like to call an async function in this method however apparently I cant use await in there since it is not an async function
I also cannot use futuresExt.map .and_then etc on a standard library feature returned by async functions.
What are my options then?
should I abandon using async functions and have my functions return futures::Future instead?

PS: I tried to use poll method but apparently poll requires a context to which I dont have access to

You could use an async block inside the function, as those will produce a future.

The fact that it's a trait method means you need to name the exact future you're returning, which makes this slightly more complicated, but not much. I recommend returning a BoxFuture, and creating that with something like

(async {
    ...
}).boxed()
1 Like

so lets say I have an async function a inside a function that returns a futures::future I should do

a().boxed().and_then ... 

is that correct ?

I tried but this does not work boxed returns a Pin what I need is a futures:future::Ready

That's one way to do it?

Usually you would box the future last, though. There isn't really much advantage to using .boxed() except for the ability to name the exact type of the future. In fact, it will introduce dynamic dispatch, and make things slightly less efficient. The big advantage is that all different types of futures can be unified as a single dynamically-dispatch type, BoxFuture, which you can name (in, say, your trait as type Future = BoxFuture<...>)

You should return a Future that internally calls the async function you wish to await.

Why do you need this? Ready is a particular future, doing exactly one thing - implementing the ready function. Unless you use that function, you cannot produce a Ready. It's not a general-purpose future.

If I box it last I cant to anything with it since there's no and_then map etc on std futures

The FutureExt trait provides a then method that is similar to and_then and usable on std futures.

I am trying to implement FromRequest trait on my type isnt this sooo stupid then all the handlers are async functions in actix-web but extractors have to be blocking what is the point of using async in the first place then

You aren't supposed to block in actix. You need to return a future that does the work you want to happen.

1 Like

If I am understanding correctly, you're forcing yourself to be blocking by declaring your future type as Ready. This is not in general required. Does the followng not work?

impl FromRequest for Thing {
    type Error = Error;
    type Future = BoxFuture<Result<Self, Self::Error>>;
    type Config = ();

    fn from_request(req: &HttpRequest, payload: &mut dev::Payload) -> Self::Future {
        (async {
            (...).await;
        }).boxed()
    }
}
1 Like


this is an example from the official docs

Yes, that example is not using async - because for that example, it wasn't required. In general, the interface does allow for writing async code inside handlers.

The type Future = ... here is declaring what your function returns. You can return any kind of future, such as a BoxFuture if you want to use an async block and async/await code, but you need to declare it. Let me know if that seems reasonable?

Ah so I can use anything as Future type which would mean I also can use std futures right without having to go through all the trouble of converting things back and forth ?

Yes. To be clear, stuff like Ready is also a certain kind of std future. It's just not a very powerful one.

1 Like

Yep - as long as it is a declarable type!

The reason I suggest BoxFuture is because every combinator adds another type. Like x.then(...).map(...).or_else(...) is OrElse<Map<Then<X, fn(...) -> ...>, fn(...) -> ...>, fn(...) -> ...> and that just because unwieldy (or outright impossible) to type.

apparently I cant use std futures because their size is unknown at compile time but I also cannot use boxed std futures because it is not unpin.

The std future type is a trait and not a struct, so you can't use it directly. To talk about "any type that implements the Future trait", you're going to need a special kind of thing called a trait object. And you can indeed get around the Unpin requirement by using Box::pin like this:

type Future = Pin<Box<dyn Future<Output = Foo>>>
// later
Box::pin(async move { ... })

The BoxFuture that @daboross suggested is a type alias for the Pin<Box<...>> combination above.

If you simply use Box::new without Pin, then you do indeed need the future to be Unpin, which async blocks are not.

3 Likes

this works without using anything specific from futures thanks

1 Like