Skip to content

Conversation

@Victoronz
Copy link
Contributor

@Victoronz Victoronz commented Dec 20, 2024

Objective

EntityHashMap and EntityHashSet iterators do not implement EntitySetIterator.

Solution

Make them newtypes instead of aliases. The methods that create the iterators can then produce their own newtypes that carry the Hasher generic and implement EntitySetIterator. Functionality remains the same otherwise.
There are some other small benefits, f.e. the removal of with_hasher associated functions, and the ability to implement more traits ourselves.

MainEntityHashMap and MainEntityHashSet are currently left as the previous type aliases, because supporting general TrustedEntityBorrow hashing is more complex. However, it can also be done.

Testing

Pre-existing EntityHashMap tests.

Migration Guide

Users of with_hasher and with_capacity_and_hasher on EntityHashMap/Set must now use new and with_capacity respectively.
If the non-newtyped versions are required, they can be obtained via Deref, DerefMut or into_inner calls.

@Victoronz Victoronz added A-ECS Entities, components, systems, and events C-Usability A targeted quality-of-life change that makes Bevy easier to use D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Dec 20, 2024
/// /// This struct is created by the [`keys`] method on [`EntityHashMap`]. See its documentation for more.
///
/// [`keys`]: EntityHashMap::keys
pub struct Keys<'a, V, S = EntityHash>(hash_map::Keys<'a, Entity, V>, PhantomData<S>);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need the S type parameter and PhantomData? It looks like this is only ever instantiated with S = EntityHash.

(And the same question for the other types with a PhantomData.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is! This S generic parameter is currently only here to express the purpose of these newtypes to the readers:
Technically a newtype alone is enough, but then the type will not communicate why it exists.
This is especially the case for the EntitySetIterator impls.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future we might also want to support more hashers, as we currently have multiple "trusted" Hashers in the engine. However I think I'll leave that for when we support hashing more TrustedEntityBorrow types.
(That allows for switching MainEntityHashMap/Set as well)

/// Clears the set, returning all elements in an iterator.
///
/// Equivalent to [`HashSet::drain`].
pub fn drain(&mut self) -> Drain<'_> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you also want a wrapper for ExtractIf?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes!

@alice-i-cecile alice-i-cecile added the M-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide label Dec 20, 2024
Copy link
Member

@alice-i-cecile alice-i-cecile left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Annoying to need more code for this, but this is well-executed and I agree with the justification.

@alice-i-cecile alice-i-cecile added this pull request to the merge queue Dec 20, 2024
@Victoronz
Copy link
Contributor Author

Victoronz commented Dec 20, 2024

Yeah, all this code and the upcoming EntityIndexMap/Set versions could be removed if the hashbrown iterators carried the Hasher generic, which for them would probably be a small non-breaking change to a few dozen lines at most.

Merged via the queue into bevyengine:main with commit 8ac90ac Dec 20, 2024
29 checks passed
ecoskey pushed a commit to ecoskey/bevy that referenced this pull request Jan 6, 2025
# Objective

`EntityHashMap` and `EntityHashSet` iterators do not implement
`EntitySetIterator`.

## Solution

Make them newtypes instead of aliases. The methods that create the
iterators can then produce their own newtypes that carry the `Hasher`
generic and implement `EntitySetIterator`. Functionality remains the
same otherwise.
There are some other small benefits, f.e. the removal of `with_hasher`
associated functions, and the ability to implement more traits
ourselves.

`MainEntityHashMap` and `MainEntityHashSet` are currently left as the
previous type aliases, because supporting general `TrustedEntityBorrow`
hashing is more complex. However, it can also be done.

## Testing

Pre-existing `EntityHashMap` tests.

## Migration Guide

Users of `with_hasher` and `with_capacity_and_hasher` on
`EntityHashMap`/`Set` must now use `new` and `with_capacity`
respectively.
If the non-newtyped versions are required, they can be obtained via
`Deref`, `DerefMut` or `into_inner` calls.
github-merge-queue bot pushed a commit that referenced this pull request Jan 24, 2025
# Objective

We do not have `EntityIndexMap`/`EntityIndexSet`.

Usual `HashMap`s/`HashSet`s do not guarantee any order, which can be
awkward for some use cases.
The `indexmap` versions remember insertion order, which then also
becomes their iteration order.
They can be thought of as a `HashTable` + `Vec`, which means fast
iteration and removal, indexing by index (not just key), and slicing!
Performance should otherwise be comparable.

## Solution

Because `indexmap` is structured to mirror `hashbrown`, it suffers the
same issue of not having the `Hasher` generic on their iterators. #16912
solved this issue for `EntityHashMap`/`EntityHashSet` with a wrapper
around the hashbrown version, so this PR does the same.

Hopefully these wrappers can be removed again in the future by having
`hashbrown`/`indexmap` adopt that generic in their iterators themselves!
github-merge-queue bot pushed a commit that referenced this pull request Jan 30, 2025
# Objective

#16912 turned `EntityHashMap` and `EntityHashSet` into proper newtypes
instead of type aliases. However, this removed the ability to create
these collections in const contexts; previously, you could use
`EntityHashSet::with_hasher(EntityHash)`, but it doesn't exist anymore.

## Solution

Make `EntityHashMap::new` and `EntityHashSet::new` const methods.
github-merge-queue bot pushed a commit that referenced this pull request Feb 2, 2025
# Objective

Follow-up to #17615.

Bevy's entity collection types like `EntityHashSet` no longer implement
serde's `Serialize` and `Deserialize` after becoming newtypes instead of
type aliases in #16912. This broke some types that support serde for me
in Avian.

I also missed creating const constructors for `EntityIndexMap` and
`EntityIndexSet` in #17615. Oops!

## Solution

Implement `Serialize` and `Deserialize` for Bevy's entity collection
types, and add const constructors for `EntityIndexMap` and
`EntityIndexSet`.

I didn't implement `ReflectSerialize` or `ReflectDeserialize` here,
because I had some trouble fixing the resulting errors, and they were
not implemented previously either.
mrchantey pushed a commit to mrchantey/bevy that referenced this pull request Feb 4, 2025
# Objective

`EntityHashMap` and `EntityHashSet` iterators do not implement
`EntitySetIterator`.

## Solution

Make them newtypes instead of aliases. The methods that create the
iterators can then produce their own newtypes that carry the `Hasher`
generic and implement `EntitySetIterator`. Functionality remains the
same otherwise.
There are some other small benefits, f.e. the removal of `with_hasher`
associated functions, and the ability to implement more traits
ourselves.

`MainEntityHashMap` and `MainEntityHashSet` are currently left as the
previous type aliases, because supporting general `TrustedEntityBorrow`
hashing is more complex. However, it can also be done.

## Testing

Pre-existing `EntityHashMap` tests.

## Migration Guide

Users of `with_hasher` and `with_capacity_and_hasher` on
`EntityHashMap`/`Set` must now use `new` and `with_capacity`
respectively.
If the non-newtyped versions are required, they can be obtained via
`Deref`, `DerefMut` or `into_inner` calls.
mrchantey pushed a commit to mrchantey/bevy that referenced this pull request Feb 4, 2025
# Objective

We do not have `EntityIndexMap`/`EntityIndexSet`.

Usual `HashMap`s/`HashSet`s do not guarantee any order, which can be
awkward for some use cases.
The `indexmap` versions remember insertion order, which then also
becomes their iteration order.
They can be thought of as a `HashTable` + `Vec`, which means fast
iteration and removal, indexing by index (not just key), and slicing!
Performance should otherwise be comparable.

## Solution

Because `indexmap` is structured to mirror `hashbrown`, it suffers the
same issue of not having the `Hasher` generic on their iterators. bevyengine#16912
solved this issue for `EntityHashMap`/`EntityHashSet` with a wrapper
around the hashbrown version, so this PR does the same.

Hopefully these wrappers can be removed again in the future by having
`hashbrown`/`indexmap` adopt that generic in their iterators themselves!
mrchantey pushed a commit to mrchantey/bevy that referenced this pull request Feb 4, 2025
…17615)

# Objective

bevyengine#16912 turned `EntityHashMap` and `EntityHashSet` into proper newtypes
instead of type aliases. However, this removed the ability to create
these collections in const contexts; previously, you could use
`EntityHashSet::with_hasher(EntityHash)`, but it doesn't exist anymore.

## Solution

Make `EntityHashMap::new` and `EntityHashSet::new` const methods.
mrchantey pushed a commit to mrchantey/bevy that referenced this pull request Feb 4, 2025
…e#17620)

# Objective

Follow-up to bevyengine#17615.

Bevy's entity collection types like `EntityHashSet` no longer implement
serde's `Serialize` and `Deserialize` after becoming newtypes instead of
type aliases in bevyengine#16912. This broke some types that support serde for me
in Avian.

I also missed creating const constructors for `EntityIndexMap` and
`EntityIndexSet` in bevyengine#17615. Oops!

## Solution

Implement `Serialize` and `Deserialize` for Bevy's entity collection
types, and add const constructors for `EntityIndexMap` and
`EntityIndexSet`.

I didn't implement `ReflectSerialize` or `ReflectDeserialize` here,
because I had some trouble fixing the resulting errors, and they were
not implemented previously either.
joshua-holmes pushed a commit to joshua-holmes/bevy that referenced this pull request Feb 5, 2025
…17615)

# Objective

bevyengine#16912 turned `EntityHashMap` and `EntityHashSet` into proper newtypes
instead of type aliases. However, this removed the ability to create
these collections in const contexts; previously, you could use
`EntityHashSet::with_hasher(EntityHash)`, but it doesn't exist anymore.

## Solution

Make `EntityHashMap::new` and `EntityHashSet::new` const methods.
joshua-holmes pushed a commit to joshua-holmes/bevy that referenced this pull request Feb 5, 2025
…e#17620)

# Objective

Follow-up to bevyengine#17615.

Bevy's entity collection types like `EntityHashSet` no longer implement
serde's `Serialize` and `Deserialize` after becoming newtypes instead of
type aliases in bevyengine#16912. This broke some types that support serde for me
in Avian.

I also missed creating const constructors for `EntityIndexMap` and
`EntityIndexSet` in bevyengine#17615. Oops!

## Solution

Implement `Serialize` and `Deserialize` for Bevy's entity collection
types, and add const constructors for `EntityIndexMap` and
`EntityIndexSet`.

I didn't implement `ReflectSerialize` or `ReflectDeserialize` here,
because I had some trouble fixing the resulting errors, and they were
not implemented previously either.
@Victoronz Victoronz mentioned this pull request Apr 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-ECS Entities, components, systems, and events C-Usability A targeted quality-of-life change that makes Bevy easier to use D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes M-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide S-Needs-Review Needs reviewer attention (from anyone!) to move forward

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants