# Objective
There's a lot of code duplication in `access.rs`. The same logic is
duplicated between components and resources. This also takes up
unnecessary memory in `Access`, as it relies on bitsets spanning the
entire `ComponentId` range.
## Solution
Since resources are now a special kind of component, this can be
removed.
## Limitations
Since `!Send` data queries used `Access` resources, `!Send` data queries
now conflict with broad queries.
```rust
// 0.18
fn system(q1_: Query<EntityMut>, q2_: NonSend<R>) {} // valid, does not conflict
// 0.19
fn system(q1_: Query<EntityMut>, q2_: NonSend<R>) {} // invalid, does conflict
```
Given how rarely non-send data is used, I recommend using
```
// 0.19
fn system(q1_: Query<EntityMut, Without<R>>, q2_: NonSend<R>) {} // works again
```
If this is also unacceptable, this PR is blocked on the `!Send` data
removal from the ECS (or some hacky workaround).
## Extra Attention
@chescock brought `AssetChanged` to my attention. It has a weird access
pattern. See the following example:
```rust
fn system(c: Query<&mut AssetChanges<Mesh>>, r: Query<(), AssetChanged<Mesh>>) {}
```
System `c` registers access with `add_write` for `AssetChanges<Mesh>`,
while `r` registers access with `add_read` for both `Mesh` and
`AssetChanges<Mesh>`. This system is invalid, and I've added a test to
reflect that. However, since this stuff is tricky, I would like some
extra eyes on it. Currently, it looks *fine*.
2.8 KiB
B0002
To keep Rust rules on references (either one mutable reference or any number of immutable references) on a resource, it is not possible to have more than one resource of a kind if one is mutable in the same system. This can happen between Res<T> and ResMut<T> for the same T, or between NonSend<T> and NonSendMut<T> for the same T.
Erroneous code example:
use bevy::prelude::*;
fn update_materials(
mut material_updater: ResMut<Assets<StandardMaterial>>,
current_materials: Res<Assets<StandardMaterial>>,
) {
// ...
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Update, update_materials)
.run();
}
This will panic, as it's not possible to have both a mutable and an immutable resource on Assets<StandardMaterial> at the same time.
As a mutable resource already provides access to the current resource value, so you can remove the immutable resource.
use bevy::prelude::*;
fn update_materials(
mut material_updater: ResMut<Assets<StandardMaterial>>,
) {
// ...
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Update, update_materials)
.run();
}
Resources as Components
Under the hood, resources are components. The consequences of this are usually nothing more than an implementation detail, however, you may run into an issue where the following system throws an error:
# use bevy::prelude::*;
# #[derive(Resource)]
# struct MyResource;
fn system(all_entities: Query<EntityMut>, res: Res<MyResource>) {}
It's not possible to both query all entities and a resource when resources are stored on an entity.
To fix this, you should either constrain the all_entities query (you usually don't need to query every single entity), or exclude MyResource with Without<MyResource> or Without<IsResource>.
Here, IsResource, is a marker component on every single entity that holds a resource, so it's very convenient if you want to exclude resources.
Queries that might conflict with Res or ResMut include:
Query<()>Query<Entity>Query<EntityMut>Query<EntityRef>Query<EntityMutExcept>Query<EntityRefExcept>Query<Option<&T>>
You can run into the same problem with non-send data:
# use bevy::prelude::*;
# #[derive(Resource)]
# struct MyNonSend;
fn system(all_entities: Query<EntityMut>, some_non_send: NonSend<MyNonSend>) {}
This can be fixed by adding a Without<MyNonSend> filter to the query.