bevy_tasks/
futures.rs

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