In a rust async function is there any way to get access to the current Context without writing an explicit implementation of a Future
?
Before actually answering the question, it is useful to remember what a Context
is; whenever you are writing an implementation of a Future
that depends on outside resources (say, I/O), you do not want to busy-wait anything. As a result, you'll most likely have implementations of Future
where you'll return Pending
and then wake it up. Context
(and Waker
) exist for that purpose.
However, this is what they are: low-level, implementation details. If you are using a Future
already as opposed to writing a low-level implementation of one, the Waker
will most likely be contained somewhere, but not directly accessible to you.
As a result of this, a Waker
directly leaking is an implementation detail leak 99.9% of the time and not actually recommended. A Waker
being used as part of a bigger struct
is perfectly fine, however, but this is where you'll need to implement your own Future
from scratch. There is no other valid use case for this, and in normal terms, you should never need direct access to a Waker
.
Due to the limitations of the playground, I sadly cannot show you a live example of when it is useful to get this Waker
; however, such a future setup may be used in such a situation: let's assume we're building the front door of a house. We have a doorbell and a door, and we want to be notified when somebody rings the doorbell. However, we don't want to have to wait at the door for visitors.
We therefore make two objects: a FrontDoor
and a Doorbell
, and we give the option to wire()
the Doorbell
to connect the two.
pub struct FrontDoor {
doorbell: Arc<RwLock<Doorbell>>
}
impl FrontDoor {
pub fn new() -> FrontDoor {
FrontDoor {
doorbell: Arc::new(RwLock::new(Doorbell {
waker: None,
visitor: false
}))
}
}
pub fn wire(&self) -> Arc<RwLock<Doorbell>> {
self.doorbell.clone() // We retrieve the bell
}
}
impl Future for FrontDoor {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
self.doorbell.read().map(|guard| {
match guard.visitor {
true => Poll::Ready(()),
false => Poll::Pending
}
}).unwrap_or(Poll::Pending)
}
}
pub struct Doorbell {
waker: Option<Waker>,
pub visitor: bool
}
impl Doorbell {
pub fn ring(&mut self) {
self.visitor = true;
self.waker.as_ref().map(|waker| waker.wake_by_ref());
}
}
Our FrontDoor
implements Future
, which means we can just throw it on an executor of your choice; waker
is contained in the Doorbell
object and allows us to "ring" and wake up our future.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With