Skip to content

Commit bd48906

Browse files
Allow bevy_utils in no_std Contexts (bevyengine#15279)
# Objective - Adjust `bevy_utils` to make it `no_std` compatible - Partially replaces bevyengine#6581 - Contributes to bevyengine#8161 - Contributes to bevyengine#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.
1 parent b1273d4 commit bd48906

File tree

6 files changed

+50
-35
lines changed

6 files changed

+50
-35
lines changed

crates/bevy_utils/Cargo.toml

+7-2
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,16 @@ license = "MIT OR Apache-2.0"
99
keywords = ["bevy"]
1010

1111
[features]
12+
default = ["std"]
13+
std = ["alloc", "tracing/std", "ahash/std"]
14+
alloc = []
1215
detailed_trace = []
1316

1417
[dependencies]
15-
ahash = "0.8.7"
16-
tracing = { version = "0.1", default-features = false, features = ["std"] }
18+
ahash = { version = "0.8.7", default-features = false, features = [
19+
"runtime-rng",
20+
] }
21+
tracing = { version = "0.1", default-features = false }
1722
web-time = { version = "1.1" }
1823
hashbrown = { version = "0.14.2", features = ["serde"] }
1924
bevy_utils_proc_macros = { version = "0.15.0-dev", path = "macros" }

crates/bevy_utils/src/futures.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//! Utilities for working with [`Future`]s.
2-
use std::{
2+
use core::{
33
future::Future,
44
pin::Pin,
55
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
@@ -44,7 +44,7 @@ fn noop(_data: *const ()) {}
4444
const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop);
4545

4646
fn noop_raw_waker() -> RawWaker {
47-
RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE)
47+
RawWaker::new(core::ptr::null(), &NOOP_WAKER_VTABLE)
4848
}
4949

5050
fn noop_waker() -> Waker {

crates/bevy_utils/src/lib.rs

+20-7
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@
44
html_logo_url = "https://bevyengine.org/assets/icon.png",
55
html_favicon_url = "https://bevyengine.org/assets/icon.png"
66
)]
7+
#![cfg_attr(not(feature = "std"), no_std)]
78

89
//! General utilities for first-party [Bevy] engine crates.
910
//!
1011
//! [Bevy]: https://bevyengine.org/
1112
//!
1213
14+
#[cfg(feature = "alloc")]
15+
extern crate alloc;
16+
1317
/// The utilities prelude.
1418
///
1519
/// This includes the most common types in this crate, re-exported for your convenience.
@@ -18,7 +22,9 @@ pub mod prelude {
1822
}
1923

2024
pub mod futures;
25+
#[cfg(feature = "alloc")]
2126
mod short_names;
27+
#[cfg(feature = "alloc")]
2228
pub use short_names::get_short_name;
2329
pub mod synccell;
2430
pub mod syncunsafecell;
@@ -37,15 +43,18 @@ pub use parallel_queue::*;
3743
pub use tracing;
3844
pub use web_time::{Duration, Instant, SystemTime, SystemTimeError, TryFromFloatSecsError};
3945

40-
use hashbrown::hash_map::RawEntryMut;
41-
use std::{
46+
#[cfg(feature = "alloc")]
47+
use alloc::boxed::Box;
48+
49+
use core::{
4250
any::TypeId,
4351
fmt::Debug,
4452
hash::{BuildHasher, BuildHasherDefault, Hash, Hasher},
4553
marker::PhantomData,
4654
mem::ManuallyDrop,
4755
ops::Deref,
4856
};
57+
use hashbrown::hash_map::RawEntryMut;
4958

5059
#[cfg(not(target_arch = "wasm32"))]
5160
mod conditional_send {
@@ -66,11 +75,12 @@ pub use conditional_send::*;
6675

6776
/// Use [`ConditionalSendFuture`] for a future with an optional Send trait bound, as on certain platforms (eg. Wasm),
6877
/// futures aren't Send.
69-
pub trait ConditionalSendFuture: std::future::Future + ConditionalSend {}
70-
impl<T: std::future::Future + ConditionalSend> ConditionalSendFuture for T {}
78+
pub trait ConditionalSendFuture: core::future::Future + ConditionalSend {}
79+
impl<T: core::future::Future + ConditionalSend> ConditionalSendFuture for T {}
7180

7281
/// An owned and dynamically typed Future used when you can't statically type your result or need to add some indirection.
73-
pub type BoxedFuture<'a, T> = std::pin::Pin<Box<dyn ConditionalSendFuture<Output = T> + 'a>>;
82+
#[cfg(feature = "alloc")]
83+
pub type BoxedFuture<'a, T> = core::pin::Pin<Box<dyn ConditionalSendFuture<Output = T> + 'a>>;
7484

7585
/// A shortcut alias for [`hashbrown::hash_map::Entry`].
7686
pub type Entry<'a, K, V, S = BuildHasherDefault<AHasher>> = hashbrown::hash_map::Entry<'a, K, V, S>;
@@ -192,7 +202,7 @@ impl<V: PartialEq, H> PartialEq for Hashed<V, H> {
192202
}
193203

194204
impl<V: Debug, H> Debug for Hashed<V, H> {
195-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
205+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
196206
f.debug_struct("Hashed")
197207
.field("hash", &self.hash)
198208
.field("value", &self.value)
@@ -417,7 +427,7 @@ mod tests {
417427
fn fast_typeid_hash() {
418428
struct Hasher;
419429

420-
impl std::hash::Hasher for Hasher {
430+
impl core::hash::Hasher for Hasher {
421431
fn finish(&self) -> u64 {
422432
0
423433
}
@@ -430,8 +440,11 @@ mod tests {
430440
Hash::hash(&TypeId::of::<()>(), &mut Hasher);
431441
}
432442

443+
#[cfg(feature = "alloc")]
433444
#[test]
434445
fn stable_hash_within_same_program_execution() {
446+
use alloc::vec::Vec;
447+
435448
let mut map_1 = HashMap::new();
436449
let mut map_2 = HashMap::new();
437450
for i in 1..10 {

crates/bevy_utils/src/parallel_queue.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use std::{cell::RefCell, ops::DerefMut};
1+
#[cfg(all(feature = "alloc", not(feature = "std")))]
2+
use alloc::vec::Vec;
3+
4+
use core::{cell::RefCell, ops::DerefMut};
25
use thread_local::ThreadLocal;
36

47
/// A cohesive set of thread-local values of a given type.
@@ -56,6 +59,7 @@ where
5659
}
5760
}
5861

62+
#[cfg(feature = "alloc")]
5963
impl<T: Send> Parallel<Vec<T>> {
6064
/// Collect all enqueued items from all threads and appends them to the end of a
6165
/// single Vec.

crates/bevy_utils/src/short_names.rs

+15-22
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use alloc::string::String;
2+
13
/// Shortens a type name to remove all module paths.
24
///
35
/// The short name of a type is its full name as returned by
@@ -88,75 +90,66 @@ mod name_formatting_tests {
8890
fn path_separated() {
8991
assert_eq!(
9092
get_short_name("bevy_prelude::make_fun_game"),
91-
"make_fun_game".to_string()
93+
"make_fun_game"
9294
);
9395
}
9496

9597
#[test]
9698
fn tuple_type() {
97-
assert_eq!(
98-
get_short_name("(String, String)"),
99-
"(String, String)".to_string()
100-
);
99+
assert_eq!(get_short_name("(String, String)"), "(String, String)");
101100
}
102101

103102
#[test]
104103
fn array_type() {
105-
assert_eq!(get_short_name("[i32; 3]"), "[i32; 3]".to_string());
104+
assert_eq!(get_short_name("[i32; 3]"), "[i32; 3]");
106105
}
107106

108107
#[test]
109108
fn trivial_generics() {
110-
assert_eq!(get_short_name("a<B>"), "a<B>".to_string());
109+
assert_eq!(get_short_name("a<B>"), "a<B>");
111110
}
112111

113112
#[test]
114113
fn multiple_type_parameters() {
115-
assert_eq!(get_short_name("a<B, C>"), "a<B, C>".to_string());
114+
assert_eq!(get_short_name("a<B, C>"), "a<B, C>");
116115
}
117116

118117
#[test]
119118
fn enums() {
120-
assert_eq!(get_short_name("Option::None"), "Option::None".to_string());
121-
assert_eq!(
122-
get_short_name("Option::Some(2)"),
123-
"Option::Some(2)".to_string()
124-
);
119+
assert_eq!(get_short_name("Option::None"), "Option::None");
120+
assert_eq!(get_short_name("Option::Some(2)"), "Option::Some(2)");
125121
assert_eq!(
126122
get_short_name("bevy_render::RenderSet::Prepare"),
127-
"RenderSet::Prepare".to_string()
123+
"RenderSet::Prepare"
128124
);
129125
}
130126

131127
#[test]
132128
fn generics() {
133129
assert_eq!(
134130
get_short_name("bevy_render::camera::camera::extract_cameras<bevy_render::camera::bundle::Camera3d>"),
135-
"extract_cameras<Camera3d>".to_string()
131+
"extract_cameras<Camera3d>"
136132
);
137133
}
138134

139135
#[test]
140136
fn nested_generics() {
141137
assert_eq!(
142138
get_short_name("bevy::mad_science::do_mad_science<mad_science::Test<mad_science::Tube>, bavy::TypeSystemAbuse>"),
143-
"do_mad_science<Test<Tube>, TypeSystemAbuse>".to_string()
139+
"do_mad_science<Test<Tube>, TypeSystemAbuse>"
144140
);
145141
}
146142

147143
#[test]
148144
fn sub_path_after_closing_bracket() {
149145
assert_eq!(
150146
get_short_name("bevy_asset::assets::Assets<bevy_scene::dynamic_scene::DynamicScene>::asset_event_system"),
151-
"Assets<DynamicScene>::asset_event_system".to_string()
147+
"Assets<DynamicScene>::asset_event_system"
152148
);
153149
assert_eq!(
154150
get_short_name("(String, String)::default"),
155-
"(String, String)::default".to_string()
156-
);
157-
assert_eq!(
158-
get_short_name("[i32; 16]::default"),
159-
"[i32; 16]::default".to_string()
151+
"(String, String)::default"
160152
);
153+
assert_eq!(get_short_name("[i32; 16]::default"), "[i32; 16]::default");
161154
}
162155
}

crates/bevy_utils/src/synccell.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//!
33
//! [`std::sync::Exclusive`]: https://doc.rust-lang.org/nightly/std/sync/struct.Exclusive.html
44
5-
use std::ptr;
5+
use core::ptr;
66

77
/// See [`Exclusive`](https://github.com/rust-lang/rust/issues/98407) for stdlib's upcoming implementation,
88
/// which should replace this one entirely.

0 commit comments

Comments
 (0)