Newtype hashbrown
(#18694)
# Objective - Fixes #18690 - Closes [#2065](https://github.com/bevyengine/bevy-website/pull/2065) - Alternative to #18691 The changes to the Hash made in #15801 to the [BuildHasher](https://doc.rust-lang.org/std/hash/trait.BuildHasher.html) resulted in serious migration problems and downgraded UX for users of Bevy's re-exported hashmaps. Once merged, we need to go in and remove the migration guide added as part of #15801. ## Solution - Newtype `HashMap` and `HashSet` instead of type aliases - Added `Deref/Mut` to allow accessing future `hashbrown` methods without maintenance from Bevy - Added bidirectional `From` implementations to provide escape hatch for API incompatibility - Added inlinable re-exports of all methods directly to Bevy's types. This ensures `HashMap::new()` works (since the `Deref` implementation wont cover these kinds of invocations). ## Testing - CI --- ## Migration Guide - If you relied on Bevy's `HashMap` and/or `HashSet` types to be identical to `hashbrown`, consider using `From` and `Into` to convert between the `hashbrown` and Bevy types as required. - If you relied on `hashbrown/serde` or `hashbrown/rayon` features, you may need to enable `bevy_platform_support/serialize` and/or `bevy_platform_support/rayon` respectively. --- ## Notes - Did not replicate the Rayon traits, users will need to rely on the `Deref/Mut` or `From` implementations for those methods. - Did not re-expose the `unsafe` methods from `hashbrown`. In most cases users will still have access via `Deref/Mut` anyway. - I have added `inline` to all methods as they are trivial wrappings of existing methods. - I chose to make `HashMap::new` and `HashSet::new` const, which is different to `hashbrown`. We can do this because we default to a fixed-state build-hasher. Mild ergonomic win over using `HashMap::with_hasher(FixedHasher)`.
This commit is contained in:
parent
3d17865c2e
commit
f3f4e80d87
@ -131,9 +131,7 @@ fn build_over_map(
|
||||
.filter(|e| !cancelled_pointers.contains(&e.pointer))
|
||||
{
|
||||
let pointer = entities_under_pointer.pointer;
|
||||
let layer_map = pointer_over_map
|
||||
.entry(pointer)
|
||||
.or_insert_with(BTreeMap::new);
|
||||
let layer_map = pointer_over_map.entry(pointer).or_default();
|
||||
for (entity, pick_data) in entities_under_pointer.picks.iter() {
|
||||
let layer = entities_under_pointer.order;
|
||||
let hits = layer_map.entry(FloatOrd(layer)).or_default();
|
||||
|
@ -14,7 +14,10 @@ default = ["std"]
|
||||
# Functionality
|
||||
|
||||
## Adds serialization support through `serde`.
|
||||
serialize = ["hashbrown/serde"]
|
||||
serialize = ["dep:serde", "hashbrown/serde"]
|
||||
|
||||
## Adds integration with Rayon.
|
||||
rayon = ["dep:rayon", "hashbrown/rayon"]
|
||||
|
||||
# Platform Compatibility
|
||||
|
||||
@ -28,10 +31,11 @@ std = [
|
||||
"portable-atomic-util/std",
|
||||
"spin/std",
|
||||
"foldhash/std",
|
||||
"serde?/std",
|
||||
]
|
||||
|
||||
## Allows access to the `alloc` crate.
|
||||
alloc = ["portable-atomic-util/alloc", "dep:hashbrown"]
|
||||
alloc = ["portable-atomic-util/alloc", "dep:hashbrown", "serde?/alloc"]
|
||||
|
||||
## `critical-section` provides the building blocks for synchronization primitives
|
||||
## on all platforms, including `no_std`.
|
||||
@ -57,6 +61,8 @@ hashbrown = { version = "0.15.1", features = [
|
||||
"equivalent",
|
||||
"raw-entry",
|
||||
], optional = true, default-features = false }
|
||||
serde = { version = "1", default-features = false, optional = true }
|
||||
rayon = { version = "1", default-features = false, optional = true }
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
web-time = { version = "1.1", default-features = false, optional = true }
|
||||
|
@ -1,68 +0,0 @@
|
||||
//! Provides [`HashMap`] and [`HashSet`] from [`hashbrown`] with some customized defaults.
|
||||
//!
|
||||
//! Also provides the [`HashTable`] type, which is specific to [`hashbrown`].
|
||||
//!
|
||||
//! Note that due to the implementation details of [`hashbrown`], [`HashMap::new`] is only implemented for `HashMap<K, V, RandomState>`.
|
||||
//! Whereas, Bevy exports `HashMap<K, V, FixedHasher>` as its default [`HashMap`] type, meaning [`HashMap::new`] will typically fail.
|
||||
//! To bypass this issue, use [`HashMap::default`] instead.
|
||||
|
||||
pub use hash_map::HashMap;
|
||||
pub use hash_set::HashSet;
|
||||
pub use hash_table::HashTable;
|
||||
pub use hashbrown::Equivalent;
|
||||
|
||||
pub mod hash_map {
|
||||
//! Provides [`HashMap`]
|
||||
|
||||
use crate::hash::FixedHasher;
|
||||
use hashbrown::hash_map as hb;
|
||||
|
||||
// Re-exports to match `std::collections::hash_map`
|
||||
pub use {
|
||||
crate::hash::{DefaultHasher, RandomState},
|
||||
hb::{
|
||||
Drain, IntoIter, IntoKeys, IntoValues, Iter, IterMut, Keys, OccupiedEntry, VacantEntry,
|
||||
Values, ValuesMut,
|
||||
},
|
||||
};
|
||||
|
||||
// Additional items from `hashbrown`
|
||||
pub use hb::{
|
||||
EntryRef, ExtractIf, OccupiedError, RawEntryBuilder, RawEntryBuilderMut, RawEntryMut,
|
||||
RawOccupiedEntryMut,
|
||||
};
|
||||
|
||||
/// Shortcut for [`HashMap`](hb::HashMap) with [`FixedHasher`] as the default hashing provider.
|
||||
pub type HashMap<K, V, S = FixedHasher> = hb::HashMap<K, V, S>;
|
||||
|
||||
/// Shortcut for [`Entry`](hb::Entry) with [`FixedHasher`] as the default hashing provider.
|
||||
pub type Entry<'a, K, V, S = FixedHasher> = hb::Entry<'a, K, V, S>;
|
||||
}
|
||||
|
||||
pub mod hash_set {
|
||||
//! Provides [`HashSet`]
|
||||
|
||||
use crate::hash::FixedHasher;
|
||||
use hashbrown::hash_set as hb;
|
||||
|
||||
// Re-exports to match `std::collections::hash_set`
|
||||
pub use hb::{Difference, Drain, Intersection, IntoIter, Iter, SymmetricDifference, Union};
|
||||
|
||||
// Additional items from `hashbrown`
|
||||
pub use hb::{ExtractIf, OccupiedEntry, VacantEntry};
|
||||
|
||||
/// Shortcut for [`HashSet`](hb::HashSet) with [`FixedHasher`] as the default hashing provider.
|
||||
pub type HashSet<T, S = FixedHasher> = hb::HashSet<T, S>;
|
||||
|
||||
/// Shortcut for [`Entry`](hb::Entry) with [`FixedHasher`] as the default hashing provider.
|
||||
pub type Entry<'a, T, S = FixedHasher> = hb::Entry<'a, T, S>;
|
||||
}
|
||||
|
||||
pub mod hash_table {
|
||||
//! Provides [`HashTable`]
|
||||
|
||||
pub use hashbrown::hash_table::{
|
||||
AbsentEntry, Drain, Entry, ExtractIf, HashTable, IntoIter, Iter, IterHash, IterHashMut,
|
||||
IterMut, OccupiedEntry, VacantEntry,
|
||||
};
|
||||
}
|
1287
crates/bevy_platform_support/src/collections/hash_map.rs
Normal file
1287
crates/bevy_platform_support/src/collections/hash_map.rs
Normal file
File diff suppressed because it is too large
Load Diff
1078
crates/bevy_platform_support/src/collections/hash_set.rs
Normal file
1078
crates/bevy_platform_support/src/collections/hash_set.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,6 @@
|
||||
//! Provides [`HashTable`]
|
||||
|
||||
pub use hashbrown::hash_table::{
|
||||
AbsentEntry, Drain, Entry, ExtractIf, HashTable, IntoIter, Iter, IterHash, IterHashMut,
|
||||
IterMut, OccupiedEntry, VacantEntry,
|
||||
};
|
12
crates/bevy_platform_support/src/collections/mod.rs
Normal file
12
crates/bevy_platform_support/src/collections/mod.rs
Normal file
@ -0,0 +1,12 @@
|
||||
//! Provides [`HashMap`] and [`HashSet`] from [`hashbrown`] with some customized defaults.
|
||||
//!
|
||||
//! Also provides the [`HashTable`] type, which is specific to [`hashbrown`].
|
||||
|
||||
pub use hash_map::HashMap;
|
||||
pub use hash_set::HashSet;
|
||||
pub use hash_table::HashTable;
|
||||
pub use hashbrown::Equivalent;
|
||||
|
||||
pub mod hash_map;
|
||||
pub mod hash_set;
|
||||
pub mod hash_table;
|
@ -331,10 +331,7 @@ impl SceneSpawner {
|
||||
Ok(_) => {
|
||||
self.spawned_instances
|
||||
.insert(instance_id, InstanceInfo { entity_map });
|
||||
let spawned = self
|
||||
.spawned_dynamic_scenes
|
||||
.entry(handle.id())
|
||||
.or_insert_with(HashSet::default);
|
||||
let spawned = self.spawned_dynamic_scenes.entry(handle.id()).or_default();
|
||||
spawned.insert(instance_id);
|
||||
|
||||
// Scenes with parents need more setup before they are ready.
|
||||
|
Loading…
Reference in New Issue
Block a user