From 3b45f6ba3cba4b7122791b9a90dceab2f0ca33b0 Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Tue, 6 May 2025 14:19:32 +1000 Subject: [PATCH] Simplify `bevy_utils` features --- crates/bevy_app/Cargo.toml | 5 +- crates/bevy_diagnostic/Cargo.toml | 7 +- crates/bevy_ecs/Cargo.toml | 13 +-- crates/bevy_image/Cargo.toml | 2 +- crates/bevy_input/Cargo.toml | 1 - crates/bevy_internal/Cargo.toml | 6 +- crates/bevy_reflect/Cargo.toml | 10 +- crates/bevy_state/Cargo.toml | 2 - crates/bevy_transform/Cargo.toml | 2 +- crates/bevy_utils/Cargo.toml | 22 +---- crates/bevy_utils/src/lib.rs | 126 ++++++------------------ crates/bevy_utils/src/map.rs | 83 ++++++++++++++++ crates/bevy_utils/src/parallel_queue.rs | 2 - 13 files changed, 124 insertions(+), 157 deletions(-) create mode 100644 crates/bevy_utils/src/map.rs diff --git a/crates/bevy_app/Cargo.toml b/crates/bevy_app/Cargo.toml index f46db94db36bc..c892860dcec0b 100644 --- a/crates/bevy_app/Cargo.toml +++ b/crates/bevy_app/Cargo.toml @@ -47,7 +47,6 @@ std = [ "bevy_ecs/std", "dep:ctrlc", "downcast-rs/std", - "bevy_utils/std", "bevy_tasks/std", "bevy_platform/std", ] @@ -77,9 +76,7 @@ web = [ bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" } bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev", default-features = false } bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-features = false, optional = true } -bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", default-features = false, features = [ - "alloc", -] } +bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", default-features = false } bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false } bevy_platform = { path = "../bevy_platform", version = "0.16.0-dev", default-features = false } diff --git a/crates/bevy_diagnostic/Cargo.toml b/crates/bevy_diagnostic/Cargo.toml index eff17104387df..2b89e5759e77b 100644 --- a/crates/bevy_diagnostic/Cargo.toml +++ b/crates/bevy_diagnostic/Cargo.toml @@ -18,7 +18,6 @@ serialize = [ "dep:serde", "bevy_ecs/serialize", "bevy_time/serialize", - "bevy_utils/serde", "bevy_platform/serialize", ] @@ -39,7 +38,6 @@ std = [ "bevy_app/std", "bevy_platform/std", "bevy_time/std", - "bevy_utils/std", "bevy_tasks/std", ] @@ -50,7 +48,6 @@ critical-section = [ "bevy_app/critical-section", "bevy_platform/critical-section", "bevy_time/critical-section", - "bevy_utils/critical-section", "bevy_tasks/critical-section", ] @@ -59,9 +56,7 @@ critical-section = [ bevy_app = { path = "../bevy_app", version = "0.16.0-dev", default-features = false } bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev", default-features = false } bevy_time = { path = "../bevy_time", version = "0.16.0-dev", default-features = false } -bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", default-features = false, features = [ - "alloc", -] } +bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", default-features = false } bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false } bevy_platform = { path = "../bevy_platform", version = "0.16.0-dev", default-features = false, features = [ "alloc", diff --git a/crates/bevy_ecs/Cargo.toml b/crates/bevy_ecs/Cargo.toml index 97cdcee0824b7..a16504335a059 100644 --- a/crates/bevy_ecs/Cargo.toml +++ b/crates/bevy_ecs/Cargo.toml @@ -20,12 +20,7 @@ default = ["std", "bevy_reflect", "async_executor", "backtrace"] multi_threaded = ["bevy_tasks/multi_threaded", "dep:arrayvec"] ## Adds serialization support through `serde`. -serialize = [ - "dep:serde", - "bevy_utils/serde", - "bevy_platform/serialize", - "indexmap/serde", -] +serialize = ["dep:serde", "bevy_platform/serialize", "indexmap/serde"] ## Adds runtime reflection support using `bevy_reflect`. bevy_reflect = ["dep:bevy_reflect"] @@ -74,7 +69,7 @@ async_executor = ["std", "bevy_tasks/async_executor"] std = [ "bevy_reflect?/std", "bevy_tasks/std", - "bevy_utils/std", + "bevy_utils/parallel", "bitflags/std", "concurrent-queue/std", "disqualified/alloc", @@ -101,9 +96,7 @@ bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [ "smallvec", ], default-features = false, optional = true } bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false } -bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", default-features = false, features = [ - "alloc", -] } +bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", default-features = false } bevy_ecs_macros = { path = "macros", version = "0.16.0-dev" } bevy_platform = { path = "../bevy_platform", version = "0.16.0-dev", default-features = false, features = [ "alloc", diff --git a/crates/bevy_image/Cargo.toml b/crates/bevy_image/Cargo.toml index 988325c7076b8..91dfd44bf473f 100644 --- a/crates/bevy_image/Cargo.toml +++ b/crates/bevy_image/Cargo.toml @@ -32,7 +32,7 @@ qoi = ["image/qoi"] tga = ["image/tga"] tiff = ["image/tiff"] webp = ["image/webp"] -serialize = ["bevy_reflect", "bevy_platform/serialize", "bevy_utils/serde"] +serialize = ["bevy_reflect", "bevy_platform/serialize"] # For ktx2 supercompression zlib = ["flate2"] diff --git a/crates/bevy_input/Cargo.toml b/crates/bevy_input/Cargo.toml index 570273a00ac59..f6752abb051c9 100644 --- a/crates/bevy_input/Cargo.toml +++ b/crates/bevy_input/Cargo.toml @@ -42,7 +42,6 @@ std = [ "bevy_app/std", "bevy_ecs/std", "bevy_math/std", - "bevy_utils/std", "bevy_reflect/std", "bevy_platform/std", ] diff --git a/crates/bevy_internal/Cargo.toml b/crates/bevy_internal/Cargo.toml index 28d234f2b4e3e..b86c880b6b998 100644 --- a/crates/bevy_internal/Cargo.toml +++ b/crates/bevy_internal/Cargo.toml @@ -299,7 +299,6 @@ std = [ "bevy_state?/std", "bevy_time/std", "bevy_transform/std", - "bevy_utils/std", "bevy_tasks/std", "bevy_window?/std", ] @@ -317,7 +316,6 @@ critical-section = [ "bevy_reflect/critical-section", "bevy_state?/critical-section", "bevy_time/critical-section", - "bevy_utils/critical-section", "bevy_tasks/critical-section", ] @@ -380,9 +378,7 @@ bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev", default-f "bevy-support", "bevy_reflect", ] } -bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", default-features = false, features = [ - "alloc", -] } +bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", default-features = false } bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false } # bevy (std required) diff --git a/crates/bevy_reflect/Cargo.toml b/crates/bevy_reflect/Cargo.toml index bb72226ab85a7..f73d00aa7dfdb 100644 --- a/crates/bevy_reflect/Cargo.toml +++ b/crates/bevy_reflect/Cargo.toml @@ -54,7 +54,6 @@ wgpu-types = ["dep:wgpu-types"] ## on `no_std` targets, but provides access to certain additional features on ## supported platforms. std = [ - "bevy_utils/std", "erased-serde/std", "downcast-rs/std", "serde/std", @@ -67,10 +66,7 @@ std = [ ## `critical-section` provides the building blocks for synchronization primitives ## on all platforms, including `no_std`. -critical-section = [ - "bevy_platform/critical-section", - "bevy_utils/critical-section", -] +critical-section = ["bevy_platform/critical-section"] ## Enables use of browser APIs. ## Note this is currently only applicable on `wasm32` architectures. @@ -79,9 +75,7 @@ web = ["bevy_platform/web", "uuid?/js"] [dependencies] # bevy bevy_reflect_derive = { path = "derive", version = "0.16.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", default-features = false, features = [ - "alloc", -] } +bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", default-features = false } bevy_ptr = { path = "../bevy_ptr", version = "0.16.0-dev" } bevy_platform = { path = "../bevy_platform", version = "0.16.0-dev", default-features = false, features = [ "alloc", diff --git a/crates/bevy_state/Cargo.toml b/crates/bevy_state/Cargo.toml index 1ae52fa571670..654218fb28d5d 100644 --- a/crates/bevy_state/Cargo.toml +++ b/crates/bevy_state/Cargo.toml @@ -30,7 +30,6 @@ bevy_app = ["dep:bevy_app"] ## supported platforms. std = [ "bevy_ecs/std", - "bevy_utils/std", "bevy_reflect?/std", "bevy_app?/std", "bevy_platform/std", @@ -40,7 +39,6 @@ std = [ ## on all platforms, including `no_std`. critical-section = [ "bevy_ecs/critical-section", - "bevy_utils/critical-section", "bevy_app?/critical-section", "bevy_reflect?/critical-section", "bevy_platform/critical-section", diff --git a/crates/bevy_transform/Cargo.toml b/crates/bevy_transform/Cargo.toml index 348db148ce66a..8d5ca38e30228 100644 --- a/crates/bevy_transform/Cargo.toml +++ b/crates/bevy_transform/Cargo.toml @@ -74,7 +74,7 @@ std = [ "bevy_math/std", "bevy_reflect?/std", "bevy_tasks/std", - "bevy_utils/std", + "bevy_utils/parallel", "serde?/std", ] diff --git a/crates/bevy_utils/Cargo.toml b/crates/bevy_utils/Cargo.toml index 39ba4629a5094..5995f58bc4505 100644 --- a/crates/bevy_utils/Cargo.toml +++ b/crates/bevy_utils/Cargo.toml @@ -9,26 +9,10 @@ license = "MIT OR Apache-2.0" keywords = ["bevy"] [features] -default = ["std", "serde"] +default = ["parallel"] -# Functionality - -## Adds serialization support through `serde`. -serde = ["bevy_platform/serialize"] - -# Platform Compatibility - -## Allows access to the `std` crate. Enabling this feature will prevent compilation -## on `no_std` targets, but provides access to certain additional features on -## supported platforms. -std = ["alloc", "bevy_platform/std", "dep:thread_local"] - -## Allows access to the `alloc` crate. -alloc = ["bevy_platform/alloc"] - -## `critical-section` provides the building blocks for synchronization primitives -## on all platforms, including `no_std`. -critical-section = ["bevy_platform/critical-section"] +# Provides access to the `Parallel` type. +parallel = ["bevy_platform/std", "dep:thread_local"] [dependencies] bevy_platform = { path = "../bevy_platform", version = "0.16.0-dev", default-features = false } diff --git a/crates/bevy_utils/src/lib.rs b/crates/bevy_utils/src/lib.rs index 9f564f14c2f63..ea50306391b97 100644 --- a/crates/bevy_utils/src/lib.rs +++ b/crates/bevy_utils/src/lib.rs @@ -9,11 +9,35 @@ //! //! [Bevy]: https://bevyengine.org/ -#[cfg(feature = "std")] -extern crate std; +/// Configuration information for this crate. +pub mod cfg { + pub(crate) use bevy_platform::cfg::*; -#[cfg(feature = "alloc")] -extern crate alloc; + pub use bevy_platform::cfg::{alloc, std}; + + define_alias! { + #[cfg(feature = "parallel")] => { + /// Indicates the `Parallel` type is available. + parallel + } + } +} + +cfg::std! { + extern crate std; +} + +cfg::alloc! { + extern crate alloc; + + mod map; + pub use map::*; +} + +cfg::parallel! { + mod parallel_queue; + pub use parallel_queue::*; +} /// The utilities prelude. /// @@ -27,65 +51,14 @@ pub mod syncunsafecell; mod default; mod once; -#[cfg(feature = "std")] -mod parallel_queue; #[doc(hidden)] pub use once::OnceFlag; pub use default::default; -#[cfg(feature = "std")] -pub use parallel_queue::*; - use core::mem::ManuallyDrop; -#[cfg(feature = "alloc")] -use { - bevy_platform::{ - collections::HashMap, - hash::{Hashed, NoOpHash, PassHash}, - }, - core::{any::TypeId, hash::Hash}, -}; - -/// A [`HashMap`] pre-configured to use [`Hashed`] keys and [`PassHash`] passthrough hashing. -/// Iteration order only depends on the order of insertions and deletions. -#[cfg(feature = "alloc")] -pub type PreHashMap = HashMap, V, PassHash>; - -/// Extension methods intended to add functionality to [`PreHashMap`]. -#[cfg(feature = "alloc")] -pub trait PreHashMapExt { - /// Tries to get or insert the value for the given `key` using the pre-computed hash first. - /// If the [`PreHashMap`] does not already contain the `key`, it will clone it and insert - /// the value returned by `func`. - fn get_or_insert_with V>(&mut self, key: &Hashed, func: F) -> &mut V; -} - -#[cfg(feature = "alloc")] -impl PreHashMapExt for PreHashMap { - #[inline] - fn get_or_insert_with V>(&mut self, key: &Hashed, func: F) -> &mut V { - use bevy_platform::collections::hash_map::RawEntryMut; - let entry = self - .raw_entry_mut() - .from_key_hashed_nocheck(key.hash(), key); - match entry { - RawEntryMut::Occupied(entry) => entry.into_mut(), - RawEntryMut::Vacant(entry) => { - let (_, value) = entry.insert_hashed_nocheck(key.hash(), key.clone(), func()); - value - } - } - } -} - -/// A specialized hashmap type with Key of [`TypeId`] -/// Iteration order only depends on the order of insertions and deletions. -#[cfg(feature = "alloc")] -pub type TypeIdMap = HashMap; - /// A type which calls a function when dropped. /// This can be used to ensure that cleanup code is run even in case of a panic. /// @@ -144,46 +117,3 @@ impl Drop for OnDrop { callback(); } } - -#[cfg(test)] -mod tests { - use super::*; - use static_assertions::assert_impl_all; - - // Check that the HashMaps are Clone if the key/values are Clone - assert_impl_all!(PreHashMap::: Clone); - - #[test] - fn fast_typeid_hash() { - struct Hasher; - - impl core::hash::Hasher for Hasher { - fn finish(&self) -> u64 { - 0 - } - fn write(&mut self, _: &[u8]) { - panic!("Hashing of core::any::TypeId changed"); - } - fn write_u64(&mut self, _: u64) {} - } - - Hash::hash(&TypeId::of::<()>(), &mut Hasher); - } - - #[cfg(feature = "alloc")] - #[test] - fn stable_hash_within_same_program_execution() { - use alloc::vec::Vec; - - let mut map_1 = >::default(); - let mut map_2 = >::default(); - for i in 1..10 { - map_1.insert(i, i); - map_2.insert(i, i); - } - assert_eq!( - map_1.iter().collect::>(), - map_2.iter().collect::>() - ); - } -} diff --git a/crates/bevy_utils/src/map.rs b/crates/bevy_utils/src/map.rs new file mode 100644 index 0000000000000..ca74e34dbbb4f --- /dev/null +++ b/crates/bevy_utils/src/map.rs @@ -0,0 +1,83 @@ +use core::{any::TypeId, hash::Hash}; + +use bevy_platform::{ + collections::HashMap, + hash::{Hashed, NoOpHash, PassHash}, +}; + +/// A [`HashMap`] pre-configured to use [`Hashed`] keys and [`PassHash`] passthrough hashing. +/// Iteration order only depends on the order of insertions and deletions. +pub type PreHashMap = HashMap, V, PassHash>; + +/// Extension methods intended to add functionality to [`PreHashMap`]. +pub trait PreHashMapExt { + /// Tries to get or insert the value for the given `key` using the pre-computed hash first. + /// If the [`PreHashMap`] does not already contain the `key`, it will clone it and insert + /// the value returned by `func`. + fn get_or_insert_with V>(&mut self, key: &Hashed, func: F) -> &mut V; +} + +impl PreHashMapExt for PreHashMap { + #[inline] + fn get_or_insert_with V>(&mut self, key: &Hashed, func: F) -> &mut V { + use bevy_platform::collections::hash_map::RawEntryMut; + let entry = self + .raw_entry_mut() + .from_key_hashed_nocheck(key.hash(), key); + match entry { + RawEntryMut::Occupied(entry) => entry.into_mut(), + RawEntryMut::Vacant(entry) => { + let (_, value) = entry.insert_hashed_nocheck(key.hash(), key.clone(), func()); + value + } + } + } +} + +/// A specialized hashmap type with Key of [`TypeId`] +/// Iteration order only depends on the order of insertions and deletions. +pub type TypeIdMap = HashMap; + +#[cfg(test)] +mod tests { + use super::*; + use static_assertions::assert_impl_all; + + // Check that the HashMaps are Clone if the key/values are Clone + assert_impl_all!(PreHashMap::: Clone); + + #[test] + fn fast_typeid_hash() { + struct Hasher; + + impl core::hash::Hasher for Hasher { + fn finish(&self) -> u64 { + 0 + } + fn write(&mut self, _: &[u8]) { + panic!("Hashing of core::any::TypeId changed"); + } + fn write_u64(&mut self, _: u64) {} + } + + Hash::hash(&TypeId::of::<()>(), &mut Hasher); + } + + crate::cfg::alloc! { + #[test] + fn stable_hash_within_same_program_execution() { + use alloc::vec::Vec; + + let mut map_1 = >::default(); + let mut map_2 = >::default(); + for i in 1..10 { + map_1.insert(i, i); + map_2.insert(i, i); + } + assert_eq!( + map_1.iter().collect::>(), + map_2.iter().collect::>() + ); + } + } +} \ No newline at end of file diff --git a/crates/bevy_utils/src/parallel_queue.rs b/crates/bevy_utils/src/parallel_queue.rs index 861d17bcf2d2b..bd6e359a2574f 100644 --- a/crates/bevy_utils/src/parallel_queue.rs +++ b/crates/bevy_utils/src/parallel_queue.rs @@ -10,7 +10,6 @@ pub struct Parallel { locals: ThreadLocal>, } -/// A scope guard of a `Parallel`, when this struct is dropped ,the value will writeback to its `Parallel` impl Parallel { /// Gets a mutable iterator over all of the per-thread queues. pub fn iter_mut(&mut self) -> impl Iterator { @@ -56,7 +55,6 @@ where } } -#[cfg(feature = "alloc")] impl Parallel> { /// Collect all enqueued items from all threads and appends them to the end of a /// single Vec.