bevy_utils/
futures.rs

1//! Utilities for working with [`Future`]s.
2use core::{
3    future::Future,
4    pin::Pin,
5    task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
6};
7
8/// Consumes a future, polls it once, and immediately returns the output
9/// or returns `None` if it wasn't ready yet.
10///
11/// This will cancel the future if it's not ready.
12pub fn now_or_never<F: Future>(mut future: F) -> Option<F::Output> {
13    let noop_waker = noop_waker();
14    let mut cx = Context::from_waker(&noop_waker);
15
16    // SAFETY: `future` is not moved and the original value is shadowed
17    let future = unsafe { Pin::new_unchecked(&mut future) };
18
19    match future.poll(&mut cx) {
20        Poll::Ready(x) => Some(x),
21        _ => None,
22    }
23}
24
25/// Polls a future once, and returns the output if ready
26/// or returns `None` if it wasn't ready yet.
27pub fn check_ready<F: Future + Unpin>(future: &mut F) -> Option<F::Output> {
28    let noop_waker = noop_waker();
29    let mut cx = Context::from_waker(&noop_waker);
30
31    let future = Pin::new(future);
32
33    match future.poll(&mut cx) {
34        Poll::Ready(x) => Some(x),
35        _ => None,
36    }
37}
38
39fn noop_clone(_data: *const ()) -> RawWaker {
40    noop_raw_waker()
41}
42fn noop(_data: *const ()) {}
43
44const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop);
45
46fn noop_raw_waker() -> RawWaker {
47    RawWaker::new(core::ptr::null(), &NOOP_WAKER_VTABLE)
48}
49
50fn noop_waker() -> Waker {
51    // SAFETY: the `RawWakerVTable` is just a big noop and doesn't violate any of the rules in `RawWakerVTable`s documentation
52    // (which talks about retaining and releasing any "resources", of which there are none in this case)
53    unsafe { Waker::from_raw(noop_raw_waker()) }
54}