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
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<...>)
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.
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
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()
}
}
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 ?
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.
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.