-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Perfect privacy for mutable component access #5799
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
Conversation
#[test] | ||
#[should_panic] | ||
fn panic_when_hierarchy_cycle() { |
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 removed this test because it should not be possible to trigger a hierarchy cycle outside of bevy_hierarchy
anymore.
For future searchability: this is an implementation of "permissions" as discussed by @BoxyUwU and @TheRawMeatball :) |
While i don't have a full opinion on this yet, we should also consider the other two options we have for implementing perfect privacy:
Personally, given that I'd consider the second a bug that needs to be fixed eventually, I'm partial to that solution. |
I don't think this is as valuable, as it would make it really awkward to get read access to protected components. I think that anyone who doesn't need write access shouldn't even have to worry about this feature at all. |
This comment was marked as resolved.
This comment was marked as resolved.
It'd probably be nice to have that noted down somewhere, for the sake of future reference. |
There is a few different problems with this, that I am aware of. Cannot implement traitsIn order to return // Entirely strawman syntax, only pay attention to the generics
pub fn iter_mut<Marker>(&mut self) -> Self::Item<Marker> where Self::Item: WriteAccesss<Marker>
{ ... } This is fine: it's how // This fails to compile, since `Marker` is not bounded by either the trait or the type.
impl<T: WorldQuery, Marker> IntoIterator for Query<T> where T: WriteAccess<Marker>
{ ... } In order to implement traits for pub struct Query<Q: WorldQuery, F: WorldQuery = (), Marker = ()> where Q: WriteAccess<Marker>
{ ... }
// `Protected1` and `Protected2` are components, protected by the types `Marker1` and `Marker2`.
fn my_system(
query: Query<(Entity, &mut Protected1, &mut Protected2), (), ((), Marker1, Marker2)>,
) { ... } But, this is the same solution as with Unnecessary complexityEven if we figure out a way of implementing this approach, it would add a significant amount of complexity for little to no benefit. We'd have to expand the concept of privacy to With the solution described in this PR, privacy is only a property of components -- if you don't have write access, then you can't even declare a mutable |
Hm, this isn't exactly what I meant by gating it on impl<T: Component> DerefMut for Mut<'_, T>
where
T: Component<MutPerm = ()>,
{} and then, add an explicit method to impl<'a, T: Component> Mut<'a, T> {
fn get_with_perm(&mut self, _perm: T::MutPerm -> &mut T {}
} |
Well then yeah, that should work as an alternative to |
This comment was marked as resolved.
This comment was marked as resolved.
nile's idea was to not have a generic on |
Ah, right. My bad |
Objective
Preventing mutation is very difficult in bevy. Even if you encapsulate an entire type, you can still acquire a
&mut T
andstd::mem::swap
it out.The most obvious example of this is the hierarchy. We would like to keep it consistent at all times, but that is not currently possible since anyone can swap out components at any time.
Related to / evolution of #5356
Solution
Example
Defining protected components.
Trying to modify protected components incorrectly.
Modifying the components properly.
Modifying through direct world access.
Changelog
bevy_hierarchy::{Parent, Children}
externally immutable.Migration Guide
When writing systems with generic components, you now must specify the trait bound
bevy_ecs::component::WriteComponent
in order to mutate/insert/remove them.Before:
After: