bevy/crates/bevy_utils/src/futures.rs
Zachary Harrold bd489068c6
Allow bevy_utils in no_std Contexts (#15279)
# Objective

- Adjust `bevy_utils` to make it `no_std` compatible
- Partially replaces #6581
- Contributes to #8161
- Contributes to #6370

## Solution

Added `alloc` and `std` features to `bevy_utils` (`std` is enabled by
default), allowing the crate's use in `no_std` contexts.

## Testing

- CI passed locally.
- Used `bevy_utils` in a `no_std` crate as an experiment and compiled
successfully.

## Migration Guide

If you were importing `bevy_utils` and setting `default_features` to
`false`, but relying on elements which are now gated behind the `std` or
`alloc` features, include the relevant feature in your `Cargo.toml`.

## Notes

- Bevy already includes a single `no_std` crate, `bevy_ptr`, so there is
precedent for this change.
- As `bevy_utils` is widely used across the rest of Bevy, further work
to make Bevy `no_std` compatible would be blocked on this crate, if such
work was to be undertaken.
- Most of the changes in this PR are just the removal of an unnecessary
call to `to_string()` within unit tests.
2024-09-18 16:00:03 +00:00

55 lines
1.7 KiB
Rust

//! Utilities for working with [`Future`]s.
use core::{
future::Future,
pin::Pin,
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
};
/// Consumes a future, polls it once, and immediately returns the output
/// or returns `None` if it wasn't ready yet.
///
/// This will cancel the future if it's not ready.
pub fn now_or_never<F: Future>(mut future: F) -> Option<F::Output> {
let noop_waker = noop_waker();
let mut cx = Context::from_waker(&noop_waker);
// SAFETY: `future` is not moved and the original value is shadowed
let future = unsafe { Pin::new_unchecked(&mut future) };
match future.poll(&mut cx) {
Poll::Ready(x) => Some(x),
_ => None,
}
}
/// Polls a future once, and returns the output if ready
/// or returns `None` if it wasn't ready yet.
pub fn check_ready<F: Future + Unpin>(future: &mut F) -> Option<F::Output> {
let noop_waker = noop_waker();
let mut cx = Context::from_waker(&noop_waker);
let future = Pin::new(future);
match future.poll(&mut cx) {
Poll::Ready(x) => Some(x),
_ => None,
}
}
fn noop_clone(_data: *const ()) -> RawWaker {
noop_raw_waker()
}
fn noop(_data: *const ()) {}
const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop);
fn noop_raw_waker() -> RawWaker {
RawWaker::new(core::ptr::null(), &NOOP_WAKER_VTABLE)
}
fn noop_waker() -> Waker {
// SAFETY: the `RawWakerVTable` is just a big noop and doesn't violate any of the rules in `RawWakerVTable`s documentation
// (which talks about retaining and releasing any "resources", of which there are none in this case)
unsafe { Waker::from_raw(noop_raw_waker()) }
}