I've yet to fully understand the new async/.await patterns, framwork and concepts. In doing so I've seen that it is possible to have a Future with a specific Output type not being (). However, when looking at how Futures are spawned and run from the Executor I've seen that the Traitbounds in the respective methods always deal with Future<Output = ()> only. So I'm wondering how to ever run a Future to completion that actually gives a return type like u32. I've understood that an async fn will be magically converted into a Future with the return type that the function signature provides. But as this could not just being scheduled/spawned to the Executor I'd like to know what additional "magic" is going on there and allows to .await such a Future while retrieving the correct return type. Or is the return type of an .await not the actual value?
Assuming:
async fn add(current: u32) -> u32 {
current + 1
}
Will:
let value = add(100).await;
actually return 101 in value ? Or is it a wrapped complex type behind the scenes ? As far as I understood the .await can only be placed inside an async function/block which would lead to the assumption that the compiler makes some clever Future chains that at the very top level creates an Future<Output = ()> that is ultimately spawnable ?
Thanks for those great answers... This unties the knot in my head
Just to add:
so using several .await statements after one another would de-sugar to .then chains of the generated Futures, right? So there is an "outer" Future with type () that wraps the chained Futures with their specific result type ? If this is the case, the compiler has a tough job to do
Yeah something like that. Every call to await is called an await-point, and there's also an implicit one at the start of the function. The anonymous future type it generates for the async fn is then an enum with a case for every await point, and the fields in each case, are the variables that exist at that point in the code. Then calling poll just has it move around between different states.