-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace all labels with interned labels #7762
Conversation
Neat! I've added Controversial to all three of these PRs, to make sure the ECS SMEs consciously choose between them. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've scanned over this quickly, and it definitely seems like a promising approach. Very similar to #7760 but potentially preferable.
Just for clarity, what are the differences between SystemSet::dyn_intern
, Intern::intern
, and IntoInterned::into_interned
? Is it possible to simplify or combine any of these methods some way?
9d7efbf
to
3b3b4e3
Compare
@JoJoJet I've replaced The functions that took I've also introduced a new trait and method |
3b3b4e3
to
35d535a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you also switch AppLabel
to use interned labels? It still uses pseudo-stringly typed labels, and I'd rather not leave that relic around.
@JoJoJet Regarding |
I guess that's fine, but is there a reason not to do it now? As far as I know, you'd just have to change a |
OK, after giving it a second thought, I've decided to do the I also changed |
Thank you for implementing my suggestions. I'll try to review this more closely today. |
I finally got around to this. I have a couple more ideas for how the API can be refined. Rather than going back-and-forth, I opened a PR to your branch: geieredgar#1. As always, feel free to voice any concerns you have with my suggestions. |
b9fb74f
to
b91bee9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this PR is in a good state now! I just have a minor documentation suggestion.
It looks like your PR is a breaking change, but you didn't provide a migration guide. Could you add some context on what users should update when this change get released in a new version of Bevy? |
This can be removed from the cons list, and added to the pros. |
@nicopap After finding rust-lang/rust#106447 I think you are correct that this approach was unsound, because two equal labels could yield two different pointers. Therefore I removed the I also believe that two different labels cannot yield the same fat pointer when leaking, because then |
I've replaced the use of |
@geieredgar this is in the milestone for 0.12, slated for this Saturday. I'm going to do a full review now, but I'm hopeful we can get this in and ship it. Can you resolve merge conflicts? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really cool stuff! The changes in schedule.rs
and intern.rs
are the only non-trivial changes: focus your review efforts there.
The breaking changes are acceptable and well-documented, the motivation is sound, I basically understand how this works, and this is incredibly well-tested. I'm comfortable approving this!
Conflicts are resolved. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy with this approach!
crates/bevy_utils/src/intern.rs
Outdated
} | ||
|
||
fn ref_eq(&self, other: &Self) -> bool { | ||
self.len() == other.len() && self.as_ptr() == other.as_ptr() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As an optimization, seems worth it to flip the order here to short-circuit on the ptr comparison? I think two interned strs are more likely to have different pointers than different lengths.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just pushed as I doubt this will be controversial (and in the interest of moving forward).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll leave this open in case anyone wants to discuss.
# Objective First of all, this PR took heavy inspiration from bevyengine#7760 and bevyengine#5715. It intends to also fix bevyengine#5569, but with a slightly different approach. This also fixes bevyengine#9335 by reexporting `DynEq`. ## Solution The advantage of this API is that we can intern a value without allocating for zero-sized-types and for enum variants that have no fields. This PR does this automatically in the `SystemSet` and `ScheduleLabel` derive macros for unit structs and fieldless enum variants. So this should cover many internal and external use cases of `SystemSet` and `ScheduleLabel`. In these optimal use cases, no memory will be allocated. - The interning returns a `Interned<dyn SystemSet>`, which is just a wrapper around a `&'static dyn SystemSet`. - `Hash` and `Eq` are implemented in terms of the pointer value of the reference, similar to my first approach of anonymous system sets in bevyengine#7676. - Therefore, `Interned<T>` does not implement `Borrow<T>`, only `Deref`. - The debug output of `Interned<T>` is the same as the interned value. Edit: - `AppLabel` is now also interned and the old `derive_label`/`define_label` macros were replaced with the new interning implementation. - Anonymous set ids are reused for different `Schedule`s, reducing the amount of leaked memory. ### Pros - `InternedSystemSet` and `InternedScheduleLabel` behave very similar to the current `BoxedSystemSet` and `BoxedScheduleLabel`, but can be copied without an allocation. - Many use cases don't allocate at all. - Very fast lookups and comparisons when using `InternedSystemSet` and `InternedScheduleLabel`. - The `intern` module might be usable in other areas. - `Interned{ScheduleLabel, SystemSet, AppLabel}` does implement `{ScheduleLabel, SystemSet, AppLabel}`, increasing ergonomics. ### Cons - Implementors of `SystemSet` and `ScheduleLabel` still need to implement `Hash` and `Eq` (and `Clone`) for it to work. ## Changelog ### Added - Added `intern` module to `bevy_utils`. - Added reexports of `DynEq` to `bevy_ecs` and `bevy_app`. ### Changed - Replaced `BoxedSystemSet` and `BoxedScheduleLabel` with `InternedSystemSet` and `InternedScheduleLabel`. - Replaced `impl AsRef<dyn ScheduleLabel>` with `impl ScheduleLabel`. - Replaced `AppLabelId` with `InternedAppLabel`. - Changed `AppLabel` to use `Debug` for error messages. - Changed `AppLabel` to use interning. - Changed `define_label`/`derive_label` to use interning. - Replaced `define_boxed_label`/`derive_boxed_label` with `define_label`/`derive_label`. - Changed anonymous set ids to be only unique inside a schedule, not globally. - Made interned label types implement their label trait. ### Removed - Removed `define_boxed_label` and `derive_boxed_label`. ## Migration guide - Replace `BoxedScheduleLabel` and `Box<dyn ScheduleLabel>` with `InternedScheduleLabel` or `Interned<dyn ScheduleLabel>`. - Replace `BoxedSystemSet` and `Box<dyn SystemSet>` with `InternedSystemSet` or `Interned<dyn SystemSet>`. - Replace `AppLabelId` with `InternedAppLabel` or `Interned<dyn AppLabel>`. - Types manually implementing `ScheduleLabel`, `AppLabel` or `SystemSet` need to implement: - `dyn_hash` directly instead of implementing `DynHash` - `as_dyn_eq` - Pass labels to `World::try_schedule_scope`, `World::schedule_scope`, `World::try_run_schedule`. `World::run_schedule`, `Schedules::remove`, `Schedules::remove_entry`, `Schedules::contains`, `Schedules::get` and `Schedules::get_mut` by value instead of by reference. --------- Co-authored-by: Joseph <[email protected]> Co-authored-by: Carter Anderson <[email protected]>
# Objective First of all, this PR took heavy inspiration from bevyengine#7760 and bevyengine#5715. It intends to also fix bevyengine#5569, but with a slightly different approach. This also fixes bevyengine#9335 by reexporting `DynEq`. ## Solution The advantage of this API is that we can intern a value without allocating for zero-sized-types and for enum variants that have no fields. This PR does this automatically in the `SystemSet` and `ScheduleLabel` derive macros for unit structs and fieldless enum variants. So this should cover many internal and external use cases of `SystemSet` and `ScheduleLabel`. In these optimal use cases, no memory will be allocated. - The interning returns a `Interned<dyn SystemSet>`, which is just a wrapper around a `&'static dyn SystemSet`. - `Hash` and `Eq` are implemented in terms of the pointer value of the reference, similar to my first approach of anonymous system sets in bevyengine#7676. - Therefore, `Interned<T>` does not implement `Borrow<T>`, only `Deref`. - The debug output of `Interned<T>` is the same as the interned value. Edit: - `AppLabel` is now also interned and the old `derive_label`/`define_label` macros were replaced with the new interning implementation. - Anonymous set ids are reused for different `Schedule`s, reducing the amount of leaked memory. ### Pros - `InternedSystemSet` and `InternedScheduleLabel` behave very similar to the current `BoxedSystemSet` and `BoxedScheduleLabel`, but can be copied without an allocation. - Many use cases don't allocate at all. - Very fast lookups and comparisons when using `InternedSystemSet` and `InternedScheduleLabel`. - The `intern` module might be usable in other areas. - `Interned{ScheduleLabel, SystemSet, AppLabel}` does implement `{ScheduleLabel, SystemSet, AppLabel}`, increasing ergonomics. ### Cons - Implementors of `SystemSet` and `ScheduleLabel` still need to implement `Hash` and `Eq` (and `Clone`) for it to work. ## Changelog ### Added - Added `intern` module to `bevy_utils`. - Added reexports of `DynEq` to `bevy_ecs` and `bevy_app`. ### Changed - Replaced `BoxedSystemSet` and `BoxedScheduleLabel` with `InternedSystemSet` and `InternedScheduleLabel`. - Replaced `impl AsRef<dyn ScheduleLabel>` with `impl ScheduleLabel`. - Replaced `AppLabelId` with `InternedAppLabel`. - Changed `AppLabel` to use `Debug` for error messages. - Changed `AppLabel` to use interning. - Changed `define_label`/`derive_label` to use interning. - Replaced `define_boxed_label`/`derive_boxed_label` with `define_label`/`derive_label`. - Changed anonymous set ids to be only unique inside a schedule, not globally. - Made interned label types implement their label trait. ### Removed - Removed `define_boxed_label` and `derive_boxed_label`. ## Migration guide - Replace `BoxedScheduleLabel` and `Box<dyn ScheduleLabel>` with `InternedScheduleLabel` or `Interned<dyn ScheduleLabel>`. - Replace `BoxedSystemSet` and `Box<dyn SystemSet>` with `InternedSystemSet` or `Interned<dyn SystemSet>`. - Replace `AppLabelId` with `InternedAppLabel` or `Interned<dyn AppLabel>`. - Types manually implementing `ScheduleLabel`, `AppLabel` or `SystemSet` need to implement: - `dyn_hash` directly instead of implementing `DynHash` - `as_dyn_eq` - Pass labels to `World::try_schedule_scope`, `World::schedule_scope`, `World::try_run_schedule`. `World::run_schedule`, `Schedules::remove`, `Schedules::remove_entry`, `Schedules::contains`, `Schedules::get` and `Schedules::get_mut` by value instead of by reference. --------- Co-authored-by: Joseph <[email protected]> Co-authored-by: Carter Anderson <[email protected]>
Objective
First of all, this PR took heavy inspiration from #7760 and #5715. It intends to also fix #5569, but with a slightly different approach.
This also fixes #9335 by reexporting
DynEq
.Solution
The advantage of this API is that we can intern a value without allocating for zero-sized-types and for enum variants that have no fields. This PR does this automatically in the
SystemSet
andScheduleLabel
derive macros for unit structs and fieldless enum variants. So this should cover many internal and external use cases ofSystemSet
andScheduleLabel
. In these optimal use cases, no memory will be allocated.Interned<dyn SystemSet>
, which is just a wrapper around a&'static dyn SystemSet
.Hash
andEq
are implemented in terms of the pointer value of the reference, similar to my first approach of anonymous system sets inrun_if
forSystemConfigs
via anonymous system sets #7676.Interned<T>
does not implementBorrow<T>
, onlyDeref
.Interned<T>
is the same as the interned value.Edit:
AppLabel
is now also interned and the oldderive_label
/define_label
macros were replaced with the new interning implementation.Schedule
s, reducing the amount of leaked memory.Pros
InternedSystemSet
andInternedScheduleLabel
behave very similar to the currentBoxedSystemSet
andBoxedScheduleLabel
, but can be copied without an allocation.InternedSystemSet
andInternedScheduleLabel
.intern
module might be usable in other areas.Interned{ScheduleLabel, SystemSet, AppLabel}
does implement{ScheduleLabel, SystemSet, AppLabel}
, increasing ergonomics.Cons
SystemSet
andScheduleLabel
still need to implementHash
andEq
(andClone
) for it to work.Changelog
Added
intern
module tobevy_utils
.DynEq
tobevy_ecs
andbevy_app
.Changed
BoxedSystemSet
andBoxedScheduleLabel
withInternedSystemSet
andInternedScheduleLabel
.impl AsRef<dyn ScheduleLabel>
withimpl ScheduleLabel
.AppLabelId
withInternedAppLabel
.AppLabel
to useDebug
for error messages.AppLabel
to use interning.define_label
/derive_label
to use interning.define_boxed_label
/derive_boxed_label
withdefine_label
/derive_label
.Removed
define_boxed_label
andderive_boxed_label
.Migration guide
BoxedScheduleLabel
andBox<dyn ScheduleLabel>
withInternedScheduleLabel
orInterned<dyn ScheduleLabel>
.BoxedSystemSet
andBox<dyn SystemSet>
withInternedSystemSet
orInterned<dyn SystemSet>
.AppLabelId
withInternedAppLabel
orInterned<dyn AppLabel>
.ScheduleLabel
,AppLabel
orSystemSet
need to implement:dyn_hash
directly instead of implementingDynHash
as_dyn_eq
World::try_schedule_scope
,World::schedule_scope
,World::try_run_schedule
.World::run_schedule
,Schedules::remove
,Schedules::remove_entry
,Schedules::contains
,Schedules::get
andSchedules::get_mut
by value instead of by reference.