Encapsulate cfg(feature = "track_location") in a type.#17602
Encapsulate cfg(feature = "track_location") in a type.#17602alice-i-cecile merged 10 commits intobevyengine:mainfrom
cfg(feature = "track_location") in a type.#17602Conversation
This allows code that depends on the feature to be checked by the compiler even when the feature is disabled, while still being removed during compilation.
|
Nice, we do want something like this. I'll take a proper look later, but from a quick glance I can't see why we need
I was surprised that this didn't happen in the PR that introduced it (didn't get a chance to look at it before it got merged). |
That would be simpler! I was trying to make sure that there was never any cost when the feature was disabled, though, and |
c1a64ac to
1bee714
Compare
|
This would help avoid this pitfall I've seen a couple times cBournhonesque/lightyear#745 joseph-gio/bevy-trait-query#77 |
eckz
left a comment
There was a problem hiding this comment.
Just to avoid repetition in names like TrackLocationOption<Option<T>>, what about renaming TrackLocationOption to
pub struct MaybeLocation<T: ?Sized = &'static Location<'static>> { ... }and removing the type alias
Remove `into_inner()` in favor of `into_option().unwrap()`.
Hmm, that's tempting. I'm concerned that the default type there is a little complex, though; usually default types are simple things like I think I'll leave it alone for now, but if someone else chimes in with a preference to change it to that then I'm happy to do so! |
JaySpruce
left a comment
There was a problem hiding this comment.
LGTM, but I do like eckz's suggestion. More complex than most default types maybe, but I think it'd be fine
…ion<Option<T>>` with `?`.
Use a defaulted type parameter to make plain `MaybeLocation` work.
Oh, I should add a note about I also see that |
Alright, two votes in favor sounds good to me! I'll make the change! |
Link to `Option`. Remove extra spaces.
# Conflicts: # crates/bevy_ecs/src/bundle.rs # crates/bevy_ecs/src/event/base.rs # crates/bevy_ecs/src/system/commands/command.rs # crates/bevy_ecs/src/system/commands/mod.rs # crates/bevy_ecs/src/world/entity_ref.rs # crates/bevy_ecs/src/world/mod.rs # crates/bevy_ecs/src/world/spawn_batch.rs
|
@cart has previously expressed a desire for this. Also, no one seems to think this is a bad idea :p Marking as Blessed and merging :) |
Objective
Eliminate the need to write
cfg(feature = "track_location")every time one uses an API that may use location tracking. It's verbose, and a little intimidating. And it requires code outside ofbevy_ecsthat wants to use location tracking needs to either unconditionally enable the feature, or include conditional compilation of its own. It would be good for users to be able to log locations when they are available without needing to add feature flags to their own crates.Reduce the number of cases where code compiles with the
track_locationfeature enabled, but not with it disabled, or vice versa. It can be hard to remember to test it both ways!Remove the need to store a
NoneinHookContextwhen thetrack_locationfeature is disabled.Solution
Create an
MaybeLocation<T>type that contains aTif thetrack_locationfeature is enabled, and is a ZST if it is not. The overall API is similar toOption, but whether the value isSomeorNoneis set at compile time and is the same for all values.Default
Tto&'static Location<'static>, since that is the most common case.Remove all
cfg(feature = "track_location")blocks outside of the implementation of that type, and instead call methods on it.When
track_locationis disabled,MaybeLocationis a ZST and all methods are#[inline]and empty, so they should be entirely removed by the compiler. But the code will still be visible to the compiler and checked, so if it compiles with the feature disabled then it should also compile with it enabled, and vice versa.Open Questions
Where should these types live? I put them in
change_detectionbecause that's where the existingMaybeLocationtypes were, but we now use these outside of change detection.While I believe that the compiler should be able to remove all of these calls, I have not actually tested anything. If we want to take this approach, what testing is required to ensure it doesn't impact performance?
Migration Guide
Methods like
Ref::changed_by()that return a&'static Location<'static>will now be available even when thetrack_locationfeature is disabled, but they will return a newMaybeLocationtype.MaybeLocationwraps a&'static Location<'static>when the feature is enabled, and is a ZST when the feature is disabled.Existing code that needs a
&Locationcan callinto_option().unwrap()to recover it. Many trait impls are forwarded, so if you only needDisplaythen no changes will be necessary.If that code was conditionally compiled, you may instead want to use the methods on
MaybeLocationto remove the need for conditional compilation.Code that constructs a
Ref,Mut,Res, orResMutwill now need to provide location information unconditionally. If you are creating them from existing Bevy types, you can obtain aMaybeLocationfrom methods likeTable::get_changed_by_slice_for()orComponentSparseSet::get_with_ticks. Otherwise, you will need to store aMaybeLocationnext to your data and use methods likeas_ref()oras_mut()to obtain wrapped references.