I'm using futures 0.3 and I would like to use a single trait that is implemented for both async scenarios and synchronous ones:
trait Testy {
type FutType: Future<Output = i32>;
fn stuff(&self) -> Self::FutType;
}
pub struct TestyImp;
impl Testy for TestyImp {
type FutType = Ready<i32>;
fn stuff(&self) -> Self::FutType {
ready(3)
}
}
How do I get from the Rust compiler's evaluation of .await
on this Ready
future back into the runtime (i.e. Tokio)? Was I able to get straight to a poll
call with an immediate result from a stack-based future state machine, or did it cost me something along the way? Did the use of Ready
introduce:
- heap allocations?
- a path through a chain of non-inlined function calls in the runtime?
- a run through an event loop?
- a thread context switch? (not synchronously scheduled is how I would think of this from a C# perspective)
Let's assume an intelligently designed runtime, or just assume Tokio if the answer is particularly dependent on it.
I've spent a lot of time in C# where we have ValueTask
and Task
. ValueTask
provides two major advantages: an already completed value that can be on the stack, and no entry into task runtime overhead when awaited with a preexisting value. Hopefully that helps explain the motivation of my question.