Simplify bevy_utils
Features (#19090)
# Objective Now that `bevy_platform::cfg` is merged, we can start tidying up features. This PR starts with `bevy_utils`. ## Solution - Removed `serde` and `critical-section` features (they were just re-exports of `bevy_platform` anyway) - Removed `std`, `alloc` features, relying on `bevy_platform::cfg` to check for availability. - Added `parallel` feature to provide access to the `Parallel` type. - Moved the `HashMap` type aliases into `map.rs` for better organisation. ## Testing - CI
This commit is contained in:
parent
d7cab93495
commit
3d3746e5d0
@ -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 }
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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"]
|
||||
@ -67,7 +62,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",
|
||||
@ -94,9 +89,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",
|
||||
|
@ -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"]
|
||||
|
@ -42,7 +42,6 @@ std = [
|
||||
"bevy_app/std",
|
||||
"bevy_ecs/std",
|
||||
"bevy_math/std",
|
||||
"bevy_utils/std",
|
||||
"bevy_reflect/std",
|
||||
"bevy_platform/std",
|
||||
]
|
||||
|
@ -296,7 +296,6 @@ std = [
|
||||
"bevy_state?/std",
|
||||
"bevy_time/std",
|
||||
"bevy_transform/std",
|
||||
"bevy_utils/std",
|
||||
"bevy_tasks/std",
|
||||
"bevy_window?/std",
|
||||
]
|
||||
@ -314,7 +313,6 @@ critical-section = [
|
||||
"bevy_reflect/critical-section",
|
||||
"bevy_state?/critical-section",
|
||||
"bevy_time/critical-section",
|
||||
"bevy_utils/critical-section",
|
||||
"bevy_tasks/critical-section",
|
||||
]
|
||||
|
||||
@ -377,9 +375,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)
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -74,7 +74,7 @@ std = [
|
||||
"bevy_math/std",
|
||||
"bevy_reflect?/std",
|
||||
"bevy_tasks/std",
|
||||
"bevy_utils/std",
|
||||
"bevy_utils/parallel",
|
||||
"serde?/std",
|
||||
]
|
||||
|
||||
|
@ -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 }
|
||||
|
@ -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<K, V> = HashMap<Hashed<K>, V, PassHash>;
|
||||
|
||||
/// Extension methods intended to add functionality to [`PreHashMap`].
|
||||
#[cfg(feature = "alloc")]
|
||||
pub trait PreHashMapExt<K, V> {
|
||||
/// 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<F: FnOnce() -> V>(&mut self, key: &Hashed<K>, func: F) -> &mut V;
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<K: Hash + Eq + PartialEq + Clone, V> PreHashMapExt<K, V> for PreHashMap<K, V> {
|
||||
#[inline]
|
||||
fn get_or_insert_with<F: FnOnce() -> V>(&mut self, key: &Hashed<K>, 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<V> = HashMap<TypeId, V, NoOpHash>;
|
||||
|
||||
/// 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<F: FnOnce()> Drop for OnDrop<F> {
|
||||
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::<u64, usize>: 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 = <HashMap<_, _>>::default();
|
||||
let mut map_2 = <HashMap<_, _>>::default();
|
||||
for i in 1..10 {
|
||||
map_1.insert(i, i);
|
||||
map_2.insert(i, i);
|
||||
}
|
||||
assert_eq!(
|
||||
map_1.iter().collect::<Vec<_>>(),
|
||||
map_2.iter().collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
83
crates/bevy_utils/src/map.rs
Normal file
83
crates/bevy_utils/src/map.rs
Normal file
@ -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<K, V> = HashMap<Hashed<K>, V, PassHash>;
|
||||
|
||||
/// Extension methods intended to add functionality to [`PreHashMap`].
|
||||
pub trait PreHashMapExt<K, V> {
|
||||
/// 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<F: FnOnce() -> V>(&mut self, key: &Hashed<K>, func: F) -> &mut V;
|
||||
}
|
||||
|
||||
impl<K: Hash + Eq + PartialEq + Clone, V> PreHashMapExt<K, V> for PreHashMap<K, V> {
|
||||
#[inline]
|
||||
fn get_or_insert_with<F: FnOnce() -> V>(&mut self, key: &Hashed<K>, 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<V> = HashMap<TypeId, V, NoOpHash>;
|
||||
|
||||
#[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::<u64, usize>: 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 = <HashMap<_, _>>::default();
|
||||
let mut map_2 = <HashMap<_, _>>::default();
|
||||
for i in 1..10 {
|
||||
map_1.insert(i, i);
|
||||
map_2.insert(i, i);
|
||||
}
|
||||
assert_eq!(
|
||||
map_1.iter().collect::<Vec<_>>(),
|
||||
map_2.iter().collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -10,7 +10,6 @@ pub struct Parallel<T: Send> {
|
||||
locals: ThreadLocal<RefCell<T>>,
|
||||
}
|
||||
|
||||
/// A scope guard of a `Parallel`, when this struct is dropped ,the value will writeback to its `Parallel`
|
||||
impl<T: Send> Parallel<T> {
|
||||
/// Gets a mutable iterator over all of the per-thread queues.
|
||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = &'_ mut T> {
|
||||
@ -56,7 +55,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<T: Send> Parallel<Vec<T>> {
|
||||
/// Collect all enqueued items from all threads and appends them to the end of a
|
||||
/// single Vec.
|
||||
|
Loading…
Reference in New Issue
Block a user