Ralith / hecs

A handy ECS
Apache License 2.0
924 stars 81 forks source link

Using Or mutably - query violates a unique borrow #289

Closed junglie85 closed 1 year ago

junglie85 commented 1 year ago

I want to mutable query for entities which have 2 possible sets of components, like so:

for (_id, r) in world.query_mut::<Or<
        (&mut Transform, &Physics, &Drawable, &Input),
        (&mut Transform, &Physics, &Drawable),
    >>() {

The only difference is that one has an Input component.

However, when I run this, I get the following error:

thread 'main' panicked at 'query violates a unique borrow', C:\Users\junglie85\.cargo\registry\src\github.com-1ecc6299db9ec823\hecs-0.9.0\src\query.rs:848:21
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: process didn't exit successfully: `target\debug\examples\sandbox.exe` (exit code: 101)

Is what I'm trying to do possible and I'm just misunderstanding the API, or is it not possible and I need to do 2 separate queries?

Ralith commented 1 year ago

This should work, but it looks like there's a bug here; thanks for the report! In the mean time, what you probably want to do is use the query (&mut Transform, &Physics, &Drawable, Option<&Input>) anyway, which will definitely work.

Ralith commented 1 year ago

On closer review, this is working as intended. Or is documented as:

Holds an L, or an R, or both

When an entity satisfies both, you get both. Two &mut Transforms to the same value would be illegal aliasing. If both clasues of an Or contain the same &mut T, you need to ensure that no entity will ever match both. In your case you should use an Option instead, so that the common references aren't needlessly duplicated.

junglie85 commented 1 year ago

Ah, you're very right re Or. I understand now why the error is being raised - my query satisfies both L and R so we have two mutable borrows of the same data, which cannot happen.

I originally tried the &Option<Input> and it didn't work, which is why I reached for Or. Thanks for your example - I had the borrow in the wrong place!