bevyengine / bevyengine/bevy

Allow to mutably query for immutable components

Open
#17,141 0 comments 0 reactions 0 assignees View on GitHub
A-ECS C-Feature D-Modest S-Needs-Design
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 22h
Merged PRs (30d)
161

Description

## What problem does this solve or what need does it fill?

Related https://github.com/bevyengine/bevy/pull/17140

Often you want to lock end users from mutating component, while still having the ability to mutate it in the library internals. For example there is a Child and Parent relationship in the bevy_hierarchy https://github.com/bevyengine/bevy/pull/16662

Currently, this access only limited to the exclusive world access. Querying also can be an option

## What solution would you like?

There are two ways of implementing it:
Add new smart pointer analogue to `Mut` that implements `QueryData` and only allows getting mutable access via unsafe methods
```rust
impl<'a, T> AssumeMut<'a, T> {
/// - One of the following should be true:
/// - Either `T` is mutable, or
/// - `OnReplace` hooks and observers for that component on that entity should trigger immediately before the mutation
/// and `OnInsert` should trigger immediately after the mutation, or
/// - The user should uphold documented invariants of `T`. If no such documentation provided, it is impossible for the end user to uphold this.
unsafe fn assume_mut(self) -> Mut<'a, T> {
// ....
}
}
```

Or

Change `Mut` smart pointer in a way to add `assume_mut` function if the type it points to is immutable.
```rust
impl Mut<'_, T> {
/// - One of the following should be true:
/// - Either `T` is mutable, or
/// - `OnReplace` hooks and observers for that component on that entity should trigger immediately before the mutation
/// and `OnInsert` should trigger immediately after the mutation, or
/// - The user should uphold documented invariants of `T`. If no such documentation provided, it is impossible for the end user to uphold this.
unsafe fn assume_mut(&mut self) -> &mut T {
// ....
}
}
```
For that current implementation of immutable components does not work, since `Mut` is generic over any type, but `DerefMut` only should be implemented for mutable components. For that we can either
```rust
trait Mutable {}

impl DerefMut for Mut<'_, T> { /*..*/ }
```
Or
```rust
trait Mutability {
type Mutability: ComponentMutability; // Rename would be desired
}

trait Component: Mutability {
// No associated `Mutability` type
//...
}

impl> DerefMut for Mut<'_, T> { /*...*/ }
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.