Commit Graph

156 Commits

Author SHA1 Message Date
Vic
b7d5254762
implement get_many_unique (#18315)
# Objective

Continuation to #16547 and #17954.

The `get_many` family are the last methods on `Query`/`QueryState` for
which we're still missing a `unique` version.

## Solution

Offer `get_many_unique`/`get_many_unique_mut` and
`get_many_unique_inner`!

Their implementation is the same as `get_many`, the difference lies in
their guaranteed-to-be unique inputs, meaning we never do any aliasing
checks.

To reduce confusion, we also rename `get_many_readonly` into
`get_many_inner` and the current `get_many_inner` into
`get_many_mut_inner` to clarify their purposes.

## Testing

Doc examples.

## Migration Guide

`get_many_inner` is now called `get_many_mut_inner`.
`get_many_readonly` is now called `get_many_inner`.
2025-03-16 21:12:26 +00:00
Vic
32d53e7bd3
make various entity wrapper type modules public (#18248)
# Objective

Part of the #16547 series.

The entity wrapper types often have some associated types an aliases
with them that cannot be re-exported into an outer module together.
Some helper types are best used with part of their path:
`bevy::ecs::entity::index_set::Slice` as `index_set::Slice`.
This has already been done for `entity::hash_set` and
`entity::hash_map`.

## Solution

Publicize the `index_set`, `index_map`, `unique_vec`, `unique_slice`,
and `unique_array` modules.

## Migration Guide

Any mention or import of types in the affected modules have to add the
respective module name to the import path.
F.e.:
`bevy::ecs::entity::EntityIndexSet` ->
`bevy::ecs::entity::index_set::EntityIndexSet`
2025-03-11 05:48:31 +00:00
Zachary Harrold
cbc931723e
Remove lifetime from QueryEntityError (#18157)
# Objective

- Allow `Query` methods such as `Query::get` to have their error
short-circuited using `?` in systems using Bevy's `Error` type

## Solution

- Removed `UnsafeWorldCell<'w>` from `QueryEntityError` and instead
store `ArchetypeId` (the information the error formatter was extracting
anyway).
- Replaced trait implementations with derives now that the type is
plain-old-data.

## Testing

- CI

---

## Migration Guide

- `QueryEntityError::QueryDoesNotMatch.1` is of type `ArchetypeId`
instead of `UnsafeWorldCell`. It is up to the caller to obtain an
`UnsafeWorldCell` now.
- `QueryEntityError` no longer has a lifetime parameter, remove it from
type signatures where required.

## Notes

This was discussed on Discord and accepted by Cart as the desirable path
forward in [this
message](https://discord.com/channels/691052431525675048/749335865876021248/1346611950527713310).
Scroll up from this point for context.

---------

Co-authored-by: SpecificProtagonist <30270112+SpecificProtagonist@users.noreply.github.com>
2025-03-09 20:05:22 +00:00
Carter Anderson
cca5813472
BevyError: Bevy's new catch-all error type (#18144)
## Objective

Fixes #18092

Bevy's current error type is a simple type alias for `Box<dyn Error +
Send + Sync + 'static>`. This largely works as a catch-all error, but it
is missing a critical feature: the ability to capture a backtrace at the
point that the error occurs. The best way to do this is `anyhow`-style
error handling: a new error type that takes advantage of the fact that
the `?` `From` conversion happens "inline" to capture the backtrace at
the point of the error.

## Solution

This PR adds a new `BevyError` type (replacing our old
`std::error::Error` type alias), which uses the "from conversion
backtrace capture" approach:

```rust
fn oh_no() -> Result<(), BevyError> {
    // this fails with Rust's built in ParseIntError, which
    // is converted into the catch-all BevyError type
    let number: usize = "hi".parse()?;
    println!("parsed {number}");
    Ok(())
}
```

This also updates our exported `Result` type alias to default to
`BevyError`, meaning you can write this instead:

```rust
fn oh_no() -> Result {
    let number: usize = "hi".parse()?;
    println!("parsed {number}");
    Ok(())
}
```

When a BevyError is encountered in a system, it will use Bevy's default
system error handler (which panics by default). BevyError does custom
"backtrace filtering" by default, meaning we can cut out the _massive_
amount of "rust internals", "async executor internals", and "bevy system
scheduler internals" that show up in backtraces. It also trims out the
first generally-unnecssary `From` conversion backtrace lines that make
it harder to locate the real error location. The result is a blissfully
simple backtrace by default:


![image](https://github.com/user-attachments/assets/7a5f5c9b-ea70-4176-af3b-d231da31c967)

The full backtrace can be shown by setting the `BEVY_BACKTRACE=full`
environment variable. Non-BevyError panics still use the default Rust
backtrace behavior.

One issue that prevented the truly noise-free backtrace during panics
that you see above is that Rust's default panic handler will print the
unfiltered (and largely unhelpful real-panic-point) backtrace by
default, in _addition_ to our filtered BevyError backtrace (with the
helpful backtrace origin) that we capture and print. To resolve this, I
have extended Bevy's existing PanicHandlerPlugin to wrap the default
panic handler. If we panic from the result of a BevyError, we will skip
the default "print full backtrace" panic handler. This behavior can be
enabled and disabled using the new `error_panic_hook` cargo feature in
`bevy_app` (which is enabled by default).

One downside to _not_ using `Box<dyn Error>` directly is that we can no
longer take advantage of the built-in `Into` impl for strings to errors.
To resolve this, I have added the following:

```rust
// Before
Err("some error")?

// After
Err(BevyError::message("some error"))?
```

We can discuss adding shorthand methods or macros for this (similar to
anyhow's `anyhow!("some error")` macro), but I'd prefer to discuss that
later.

I have also added the following extension method:

```rust
// Before
some_option.ok_or("some error")?;

// After
some_option.ok_or_message("some error")?;
```

I've also moved all of our existing error infrastructure from
`bevy_ecs::result` to `bevy_ecs::error`, as I think that is the better
home for it

## Why not anyhow (or eyre)?

The biggest reason is that `anyhow` needs to be a "generically useful
error type", whereas Bevy is a much narrower scope. By using our own
error, we can be significantly more opinionated. For example, anyhow
doesn't do the extensive (and invasive) backtrace filtering that
BevyError does because it can't operate on Bevy-specific context, and
needs to be generically useful.

Bevy also has a lot of operational context (ex: system info) that could
be useful to attach to errors. If we have control over the error type,
we can add whatever context we want to in a structured way. This could
be increasingly useful as we add more visual / interactive error
handling tools and editor integrations.

Additionally, the core approach used is simple and requires almost no
code. anyhow clocks in at ~2500 lines of code, but the impl here uses
160. We are able to boil this down to exactly what we need, and by doing
so we improve our compile times and the understandability of our code.
2025-03-07 01:50:07 +00:00
Chris Russell
1f6642df4c
Fix unsound query transmutes on queries obtained from Query::as_readonly() (#17973)
# Objective

Fix unsound query transmutes on queries obtained from
`Query::as_readonly()`.

The following compiles, and the call to `transmute_lens()` should panic,
but does not:
```rust
fn bad_system(query: Query<&mut A>) {
    let mut readonly = query.as_readonly();
    let mut lens: QueryLens<&mut A> = readonly.transmute_lens();
    let other_readonly: Query<&A> = query.as_readonly();
    // `lens` and `other_readonly` alias, and are both alive here!
}
```

To make `Query::as_readonly()` zero-cost, we pointer-cast
`&QueryState<D, F>` to `&QueryState<D::ReadOnly, F>`. This means that
the `component_access` for a read-only query's state may include
accesses for the original mutable version, but the `Query` does not have
exclusive access to those components! `transmute` and `join` use that
access to ensure that a join is valid, and will incorrectly allow a
transmute that includes mutable access.

As a bonus, allow `Query::join`s that output `FilteredEntityRef` or
`FilteredEntityMut` to receive access from the `other` query. Currently
they only receive access from `self`.

## Solution

When transmuting or joining from a read-only query, remove any writes
before performing checking that the transmute is valid. For joins, be
sure to handle the case where one input query was the result of
`as_readonly()` but the other has valid mutable access.

This requires identifying read-only queries, so add a
`QueryData::IS_READ_ONLY` associated constant. Note that we only call
`QueryState::as_transmuted_state()` with `NewD: ReadOnlyQueryData`, so
checking for read-only queries is sufficient to check for
`as_transmuted_state()`.

Removing writes requires allocating a new `FilteredAccess`, so only do
so if the query is read-only and the state has writes. Otherwise, the
existing access is correct and we can continue using a reference to it.

Use the new read-only state to call `NewD::set_access`, so that
transmuting to a `FilteredAccessMut` results in a read-only
`FilteredAccessMut`. Otherwise, it would take the original write access,
and then the transmute would panic because it had too much access.

Note that `join` was previously passing `self.component_access` to
`NewD::set_access`. Switching it to `joined_component_access` also
allows a join that outputs `FilteredEntity(Ref|Mut)` to receive access
from `other`. The fact that it didn't do that before seems like an
oversight, so I didn't try to prevent that change.

## Testing

Added unit tests with the unsound transmute and join.
2025-03-04 19:26:31 +00:00
Zachary Harrold
ff1143ec87
Remove deprecated component_reads_and_writes (#16348)
# Objective

- Fixes #16339

## Solution

- Replaced `component_reads_and_writes` and `component_writes` with
`try_iter_component_access`.

## Testing

- Ran `dynamic` example to confirm behaviour is unchanged.
- CI

---

## Migration Guide

The following methods (some removed in previous PRs) are now replaced by
`Access::try_iter_component_access`:

* `Access::component_reads_and_writes`
* `Access::component_reads`
* `Access::component_writes`

As `try_iter_component_access` returns a `Result`, you'll now need to
handle the failing case (e.g., `unwrap()`). There is currently a single
failure mode, `UnboundedAccess`, which occurs when the `Access` is for
all `Components` _except_ certain exclusions. Since this list is
infinite, there is no meaningful way for `Access` to provide an
iterator. Instead, get a list of components (e.g., from the `Components`
structure) and iterate over that instead, filtering using
`Access::has_component_read`, `Access::has_component_write`, etc.

Additionally, you'll need to `filter_map` the accesses based on which
method you're attempting to replace:

* `Access::component_reads_and_writes` -> `Exclusive(_) | Shared(_)`
* `Access::component_reads` -> `Shared(_)`
* `Access::component_writes` -> `Exclusive(_)`

To ease migration, please consider the below extension trait which you
can include in your project:

```rust
pub trait AccessCompatibilityExt {
    /// Returns the indices of the components this has access to.
    fn component_reads_and_writes(&self) -> impl Iterator<Item = T> + '_;

    /// Returns the indices of the components this has non-exclusive access to.
    fn component_reads(&self) -> impl Iterator<Item = T> + '_;

    /// Returns the indices of the components this has exclusive access to.
    fn component_writes(&self) -> impl Iterator<Item = T> + '_;
}

impl<T: SparseSetIndex> AccessCompatibilityExt for Access<T> {
    fn component_reads_and_writes(&self) -> impl Iterator<Item = T> + '_ {
        self
            .try_iter_component_access()
            .expect("Access is unbounded. Please refactor the usage of this method to directly use try_iter_component_access")
            .filter_map(|component_access| {
                let index = component_access.index().sparse_set_index();

                match component_access {
                    ComponentAccessKind::Archetypal(_) => None,
                    ComponentAccessKind::Shared(_) => Some(index),
                    ComponentAccessKind::Exclusive(_) => Some(index),
                }
            })
    }

    fn component_reads(&self) -> impl Iterator<Item = T> + '_ {
        self
            .try_iter_component_access()
            .expect("Access is unbounded. Please refactor the usage of this method to directly use try_iter_component_access")
            .filter_map(|component_access| {
                let index = component_access.index().sparse_set_index();

                match component_access {
                    ComponentAccessKind::Archetypal(_) => None,
                    ComponentAccessKind::Shared(_) => Some(index),
                    ComponentAccessKind::Exclusive(_) => None,
                }
            })
    }

    fn component_writes(&self) -> impl Iterator<Item = T> + '_ {
        self
            .try_iter_component_access()
            .expect("Access is unbounded. Please refactor the usage of this method to directly use try_iter_component_access")
            .filter_map(|component_access| {
                let index = component_access.index().sparse_set_index();

                match component_access {
                    ComponentAccessKind::Archetypal(_) => None,
                    ComponentAccessKind::Shared(_) => None,
                    ComponentAccessKind::Exclusive(_) => Some(index),
                }
            })
    }
}
```

Please take note of the use of `expect(...)` in these methods. You
should consider using these as a starting point for a more appropriate
migration based on your specific needs.

## Notes

- This new method is fallible based on whether the `Access` is bounded
or unbounded (unbounded occurring with inverted component sets). If
bounded, will return an iterator of every item and its access level. I
believe this makes sense without exposing implementation details around
`Access`.
- The access level is defined by an `enum` `ComponentAccessKind<T>`,
either `Archetypical`, `Shared`, or `Exclusive`. As a convenience, this
`enum` has a method `index` to get the inner `T` value without a match
statement. It does add more code, but the API is clearer.
- Within `QueryBuilder` this new method simplifies several pieces of
logic without changing behaviour.
- Within `QueryState` the logic is simplified and the amount of
iteration is reduced, potentially improving performance.
- Within the `dynamic` example it has identical behaviour, with the
inversion footgun explicitly highlighted by an `unwrap`.

---------

Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
Co-authored-by: Mike <2180432+hymm@users.noreply.github.com>
2025-03-04 08:22:29 +00:00
Alice Cecile
2ad5908e58
Make Query::single (and friends) return a Result (#18082)
# Objective

As discussed in #14275, Bevy is currently too prone to panic, and makes
the easy / beginner-friendly way to do a large number of operations just
to panic on failure.

This is seriously frustrating in library code, but also slows down
development, as many of the `Query::single` panics can actually safely
be an early return (these panics are often due to a small ordering issue
or a change in game state.

More critically, in most "finished" products, panics are unacceptable:
any unexpected failures should be handled elsewhere. That's where the
new

With the advent of good system error handling, we can now remove this.

Note: I was instrumental in a) introducing this idea in the first place
and b) pushing to make the panicking variant the default. The
introduction of both `let else` statements in Rust and the fancy system
error handling work in 0.16 have changed my mind on the right balance
here.

## Solution

1. Make `Query::single` and `Query::single_mut` (and other random
related methods) return a `Result`.
2. Handle all of Bevy's internal usage of these APIs.
3. Deprecate `Query::get_single` and friends, since we've moved their
functionality to the nice names.
4. Add detailed advice on how to best handle these errors.

Generally I like the diff here, although `get_single().unwrap()` in
tests is a bit of a downgrade.

## Testing

I've done a global search for `.single` to track down any missed
deprecated usages.

As to whether or not all the migrations were successful, that's what CI
is for :)

## Future work

~~Rename `Query::get_single` and friends to `Query::single`!~~

~~I've opted not to do this in this PR, and smear it across two releases
in order to ease the migration. Successive deprecations are much easier
to manage than the semantics and types shifting under your feet.~~

Cart has convinced me to change my mind on this; see
https://github.com/bevyengine/bevy/pull/18082#discussion_r1974536085.

## Migration guide

`Query::single`, `Query::single_mut` and their `QueryState` equivalents
now return a `Result`. Generally, you'll want to:

1. Use Bevy 0.16's system error handling to return a `Result` using the
`?` operator.
2. Use a `let else Ok(data)` block to early return if it's an expected
failure.
3. Use `unwrap()` or `Ok` destructuring inside of tests.

The old `Query::get_single` (etc) methods which did this have been
deprecated.
2025-03-02 19:51:56 +00:00
Zachary Harrold
5241e09671
Upgrade to Rust Edition 2024 (#17967)
# Objective

- Fixes #17960

## Solution

- Followed the [edition upgrade
guide](https://doc.rust-lang.org/edition-guide/editions/transitioning-an-existing-project-to-a-new-edition.html)

## Testing

- CI

---

## Summary of Changes

### Documentation Indentation

When using lists in documentation, proper indentation is now linted for.
This means subsequent lines within the same list item must start at the
same indentation level as the item.

```rust
/* Valid */
/// - Item 1
///   Run-on sentence.
/// - Item 2
struct Foo;

/* Invalid */
/// - Item 1
///     Run-on sentence.
/// - Item 2
struct Foo;
```

### Implicit `!` to `()` Conversion

`!` (the never return type, returned by `panic!`, etc.) no longer
implicitly converts to `()`. This is particularly painful for systems
with `todo!` or `panic!` statements, as they will no longer be functions
returning `()` (or `Result<()>`), making them invalid systems for
functions like `add_systems`. The ideal fix would be to accept functions
returning `!` (or rather, _not_ returning), but this is blocked on the
[stabilisation of the `!` type
itself](https://doc.rust-lang.org/std/primitive.never.html), which is
not done.

The "simple" fix would be to add an explicit `-> ()` to system
signatures (e.g., `|| { todo!() }` becomes `|| -> () { todo!() }`).
However, this is _also_ banned, as there is an existing lint which (IMO,
incorrectly) marks this as an unnecessary annotation.

So, the "fix" (read: workaround) is to put these kinds of `|| -> ! { ...
}` closuers into variables and give the variable an explicit type (e.g.,
`fn()`).

```rust
// Valid
let system: fn() = || todo!("Not implemented yet!");
app.add_systems(..., system);

// Invalid
app.add_systems(..., || todo!("Not implemented yet!"));
```

### Temporary Variable Lifetimes

The order in which temporary variables are dropped has changed. The
simple fix here is _usually_ to just assign temporaries to a named
variable before use.

### `gen` is a keyword

We can no longer use the name `gen` as it is reserved for a future
generator syntax. This involved replacing uses of the name `gen` with
`r#gen` (the raw-identifier syntax).

### Formatting has changed

Use statements have had the order of imports changed, causing a
substantial +/-3,000 diff when applied. For now, I have opted-out of
this change by amending `rustfmt.toml`

```toml
style_edition = "2021"
```

This preserves the original formatting for now, reducing the size of
this PR. It would be a simple followup to update this to 2024 and run
`cargo fmt`.

### New `use<>` Opt-Out Syntax

Lifetimes are now implicitly included in RPIT types. There was a handful
of instances where it needed to be added to satisfy the borrow checker,
but there may be more cases where it _should_ be added to avoid
breakages in user code.

### `MyUnitStruct { .. }` is an invalid pattern

Previously, you could match against unit structs (and unit enum
variants) with a `{ .. }` destructuring. This is no longer valid.

### Pretty much every use of `ref` and `mut` are gone

Pattern binding has changed to the point where these terms are largely
unused now. They still serve a purpose, but it is far more niche now.

### `iter::repeat(...).take(...)` is bad

New lint recommends using the more explicit `iter::repeat_n(..., ...)`
instead.

## Migration Guide

The lifetimes of functions using return-position impl-trait (RPIT) are
likely _more_ conservative than they had been previously. If you
encounter lifetime issues with such a function, please create an issue
to investigate the addition of `+ use<...>`.

## Notes

- Check the individual commits for a clearer breakdown for what
_actually_ changed.

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
2025-02-24 03:54:47 +00:00
JaySpruce
ee44560523
Add EntityDoesNotExistError, replace cases of Entity as an error, do some easy Resultification (#17855)
## Objective
There's no general error for when an entity doesn't exist, and some
methods are going to need one when they get Resultified. The closest
thing is `EntityFetchError`, but that error has a slightly more specific
purpose.

## Solution
- Added `EntityDoesNotExistError`.
  - Contains `Entity` and `EntityDoesNotExistDetails`.
- Changed `EntityFetchError` and `QueryEntityError`:
- Changed `NoSuchEntity` variant to wrap `EntityDoesNotExistError` and
renamed the variant to `EntityDoesNotExist`.
- Renamed `EntityFetchError` to `EntityMutableFetchError` to make its
purpose clearer.
- Renamed `TryDespawnError` to `EntityDespawnError` to make it more
general.
- Changed `World::inspect_entity` to return `Result<[ok],
EntityDoesNotExistError>` instead of panicking.
- Changed `World::get_entity` and `WorldEntityFetch::fetch_ref` to
return `Result<[ok], EntityDoesNotExistError>` instead of `Result<[ok],
Entity>`.
- Changed `UnsafeWorldCell::get_entity` to return
`Result<UnsafeEntityCell, EntityDoesNotExistError>` instead of
`Option<UnsafeEntityCell>`.

## Migration Guide
- `World::inspect_entity` now returns `Result<impl Iterator<Item =
&ComponentInfo>, EntityDoesNotExistError>` instead of `impl
Iterator<Item = &ComponentInfo>`.
- `World::get_entity` now returns `EntityDoesNotExistError` as an error
instead of `Entity`. You can still access the entity's ID through the
error's `entity` field.
- `UnsafeWorldCell::get_entity` now returns `Result<UnsafeEntityCell,
EntityDoesNotExistError>` instead of `Option<UnsafeEntityCell>`.
2025-02-16 21:59:46 +00:00
Chris Russell
794bf6a332
Move implementations of Query methods from QueryState to Query. (#17822)
# Objective

Simplify the API surface by removing duplicated functionality between
`Query` and `QueryState`.

Reduce the amount of `unsafe` code required in `QueryState`.  

This is a follow-up to #15858.

## Solution

Move implementations of `Query` methods from `QueryState` to `Query`.
Instead of the original methods being on `QueryState`, with `Query`
methods calling them by passing the individual parameters, the original
methods are now on `Query`, with `QueryState` methods calling them by
constructing a `Query`.

This also adds two `_inner` methods that were missed in #15858:
`iter_many_unique_inner` and `single_inner`.

One goal here is to be able to deprecate and eventually remove many of
the methods on `QueryState`, reducing the overall API surface. (I
expected to do that in this PR, but this change was large enough on its
own!) Now that the `QueryState` methods each consist of a simple
expression like `self.query(world).get_inner(entity)`, a future PR can
deprecate some or all of them with simple migration instructions.

The other goal is to reduce the amount of `unsafe` code. The current
implementation of a read-only method like `QueryState::get` directly
calls the `unsafe fn get_unchecked_manual` and needs to repeat the proof
that `&World` has enough access. With this change, `QueryState::get` is
entirely safe code, with the proof that `&World` has enough access done
by the `query()` method and shared across all read-only operations.

## Future Work

The next step will be to mark the `QueryState` methods as
`#[deprecated]` and migrate callers to the methods on `Query`.
2025-02-16 19:57:43 +00:00
Vic
05e61d64f5
implement par_iter_many and par_iter_many_unique (#17815)
# Objective

Continuation of #16547.

We do not yet have parallel versions of `par_iter_many` and
`par_iter_many_unique`. It is currently very painful to try and use
parallel iteration over entity lists. Even if a list is not long, each
operation might still be very expensive, and worth parallelizing.
Plus, it has been requested several times!

## Solution

Once again, we implement what we lack!

These parallel iterators collect their input entity list into a
`Vec`/`UniqueEntityVec`, then chunk that over the available threads,
inspired by the original `par_iter`.

Since no order guarantee is given to the caller, we could sort the input
list according to `EntityLocation`, but that would likely only be worth
it for very large entity lists.

There is some duplication which could likely be improved, but I'd like
to leave that for a follow-up.

## Testing

The doc tests on `for_each_init` of `QueryParManyIter` and
`QueryParManyUniqueIter`.
2025-02-13 19:49:41 +00:00
Alice Cecile
fcc77fe3d6
Allow users to register their own disabling components / default query filters (#17768)
# Objective

Currently, default query filters, as added in #13120 / #17514 are
hardcoded to only use a single query filter.

This is limiting, as multiple distinct disabling components can serve
important distinct roles. I ran into this limitation when experimenting
with a workflow for prefabs, which don't represent the same state as "an
entity which is temporarily nonfunctional".

## Solution

1. Change `DefaultQueryFilters` to store a SmallVec of ComponentId,
rather than an Option.
2. Expose methods on `DefaultQueryFilters`, `World` and `App` to
actually configure this.
3. While we're here, improve the docs, write some tests, make use of
FromWorld and make some method names more descriptive.

## Follow-up

I'm not convinced that supporting sparse set disabling components is
useful, given the hit to iteration performance and runtime checks
incurred. That's disjoint from this PR though, so I'm not doing it here.
The existing warnings are fine for now.

## Testing

I've added both a doc test and an mid-level unit test to verify that
this works!
2025-02-11 18:25:32 +00:00
raldone01
1b7db895b7
Harden proc macro path resolution and add integration tests. (#17330)
This pr uses the `extern crate self as` trick to make proc macros behave
the same way inside and outside bevy.

# Objective

- Removes noise introduced by `crate as` in the whole bevy repo.
- Fixes #17004.
- Hardens proc macro path resolution.

## TODO

- [x] `BevyManifest` needs cleanup.
- [x] Cleanup remaining `crate as`.
- [x] Add proper integration tests to the ci.

## Notes

- `cargo-manifest-proc-macros` is written by me and based/inspired by
the old `BevyManifest` implementation and
[`bkchr/proc-macro-crate`](https://github.com/bkchr/proc-macro-crate).
- What do you think about the new integration test machinery I added to
the `ci`?
  More and better integration tests can be added at a later stage.
The goal of these integration tests is to simulate an actual separate
crate that uses bevy. Ideally they would lightly touch all bevy crates.

## Testing

- Needs RA test
- Needs testing from other users
- Others need to run at least `cargo run -p ci integration-test` and
verify that they work.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-02-09 19:45:45 +00:00
Chris Russell
6f39e44c48
Introduce methods on QueryState to obtain a Query (#15858)
# Objective

Simplify and expand the API for `QueryState`.  

`QueryState` has a lot of methods that mirror those on `Query`. These
are then multiplied by variants that take `&World`, `&mut World`, and
`UnsafeWorldCell`. In addition, many of them have `_manual` variants
that take `&QueryState` and avoid calling `update_archetypes()`. Not all
of the combinations exist, however, so some operations are not possible.

## Solution

Introduce methods to get a `Query` from a `QueryState`. That will reduce
duplication between the types, and ensure that the full `Query` API is
always available for `QueryState`.

Introduce methods on `Query` that consume the query to return types with
the full `'w` lifetime. This avoids issues with borrowing where things
like `query_state.query(&world).get(entity)` don't work because they
borrow from the temporary `Query`.

Finally, implement `Copy` for read-only `Query`s. `get_inner` and
`iter_inner` currently take `&self`, so changing them to consume `self`
would be a breaking change. By making `Query: Copy`, they can consume a
copy of `self` and continue to work.

The consuming methods also let us simplify the implementation of methods
on `Query`, by doing `fn foo(&self) { self.as_readonly().foo_inner() }`
and `fn foo_mut(&mut self) { self.reborrow().foo_inner() }`. That
structure makes it more difficult to accidentally extend lifetimes,
since the safe `as_readonly()` and `reborrow()` methods shrink them
appropriately. The optimizer is able to see that they are both identity
functions and inline them, so there should be no performance cost.

Note that this change would conflict with #15848. If `QueryState` is
stored as a `Cow`, then the consuming methods cannot be implemented, and
`Copy` cannot be implemented.

## Future Work

The next step is to mark the methods on `QueryState` as `#[deprecated]`,
and move the implementations into `Query`.

## Migration Guide

`Query::to_readonly` has been renamed to `Query::as_readonly`.
2025-02-05 18:33:15 +00:00
NiseVoid
de5486725d
Add DefaultQueryFilters (#13120)
# Objective

Some usecases in the ecosystems are blocked by the inability to stop
bevy internals and third party plugins from touching their entities.
However the specifics of a general purpose entity disabling system are
controversial and further complicated by hierarchies. We can partially
unblock these usecases with an opt-in approach: default query filters.

## Solution

- Introduce DefaultQueryFilters, these filters are automatically applied
to queries that don't otherwise mention the filtered component.
- End users and third party plugins can register default filters and are
responsible for handling entities they have hidden this way.
- Extra features can be left for after user feedback
- The default value could later include official ways to hide entities

---

## Changelog

- Add DefaultQueryFilters
2025-01-20 21:57:39 +00:00
SpecificProtagonist
f5d38f30cc
Fix entity does not exist message on index reuse (#17264)
# Objective

With the `track_location` feature, the error message of trying to
acquire an entity that was despawned pointed to the wrong line if the
entity index has been reused.

## Showcase

```rust
use bevy_ecs::prelude::*;

fn main() {
    let mut world = World::new();
    let e = world.spawn_empty().id();
    world.despawn(e);
    world.flush();
    let _ = world.spawn_empty();
    world.entity(e);
}
```
Old message:
```
Entity 0v1 was despawned by src/main.rs:8:19
```
New message:
```
Entity 0v1 does not exist (its index has been reused)
```
2025-01-12 05:39:54 +00:00
vil'mo
b30ee2d051
Disallow requesting write resource access in Queries (#17116)
Related to https://github.com/bevyengine/bevy/pull/16843

Since `WorldQuery::Fetch` is `Clone`, it can't store mutable references
to resources, so it doesn't make sense to mutably access resources. In
that sense, it is hard to find usecases of mutably accessing resources
and to clearly define, what mutably accessing resources would mean, so
it's been decided to disallow write resource access.
Also changed documentation of safety requirements of
`WorldQuery::init_fetch` and `WorldQuery::fetch` to clearly state to the
caller, what safety invariants they need to uphold.
2025-01-06 19:04:26 +00:00
Zachary Harrold
a371ee3019
Remove tracing re-export from bevy_utils (#17161)
# Objective

- Contributes to #11478

## Solution

- Made `bevy_utils::tracing` `doc(hidden)`
- Re-exported `tracing` from `bevy_log` for end-users
- Added `tracing` directly to crates that need it.

## Testing

- CI

---

## Migration Guide

If you were importing `tracing` via `bevy::utils::tracing`, instead use
`bevy::log::tracing`. Note that many items within `tracing` are also
directly re-exported from `bevy::log` as well, so you may only need
`bevy::log` for the most common items (e.g., `warn!`, `trace!`, etc.).
This also applies to the `log_once!` family of macros.

## Notes

- While this doesn't reduce the line-count in `bevy_utils`, it further
decouples the internal crates from `bevy_utils`, making its eventual
removal more feasible in the future.
- I have just imported `tracing` as we do for all dependencies. However,
a workspace dependency may be more appropriate for version management.
2025-01-05 23:06:34 +00:00
Benjamin Brienen
7112d5594e
Remove all deprecated code (#16338)
# Objective

Release cycle things

## Solution

Delete items deprecated in 0.15 and migrate bevy itself.

## Testing

CI
2025-01-05 20:33:39 +00:00
JaySpruce
4fde223831
Optimize Entities::entity_does_not_exist_error_details_message, remove UnsafeWorldCell from error (#17115)
## Objective

The error `EntityFetchError::NoSuchEntity` has an `UnsafeWorldCell`
inside it, which it uses to call
`Entities::entity_does_not_exist_error_details_message` when being
printed. That method returns a `String` that, if the `track_location`
feature is enabled, contains the location of whoever despawned the
relevant entity.

I initially had to modify this error while working on #17043. The
`UnsafeWorldCell` was causing borrow problems when being returned from a
command, so I tried replacing it with the `String` that the method
returns, since that was the world cell's only purpose.

Unfortunately, `String`s are slow, and it significantly impacted
performance (on top of that PR's performance hit):
<details>
<summary>17043 benchmarks</summary>

### With `String`

![error_handling_insert_slow](https://github.com/user-attachments/assets/5629ba6d-69fc-4c16-84c9-8be7e449232d)

### No `String`

![error_handling_insert_fixed](https://github.com/user-attachments/assets/6393e2d6-e61a-4558-8ff1-471ff8356c1c)

</details>

For that PR, I just removed the error details entirely, but I figured
I'd try to find a way to keep them around.

## Solution

- Replace the `String` with a helper struct that holds the location, and
only turn it into a string when someone actually wants to print it.
- Replace the `UnsafeWorldCell` with the aforementioned struct.
- Do the same for `QueryEntityError::NoSuchEntity`.

## Benchmarking

This had some interesting performance impact:

<details>
<summary>This PR vs main</summary>


![dne_rework_1](https://github.com/user-attachments/assets/05bf91b4-dddc-4d76-b2c4-41c9d25c7a57)

![dne_rework_2](https://github.com/user-attachments/assets/34aa76b2-d8a7-41e0-9670-c213207e457d)

![dne_rework_3](https://github.com/user-attachments/assets/8b9bd4e4-77c8-45a7-b058-dc0dfd3dd323)

</details>

## Other work

`QueryEntityError::QueryDoesNotMatch` also has an `UnsafeWorldCell`
inside it. This one would be more complicated to rework while keeping
the same functionality.

## Migration Guide

The errors `EntityFetchError::NoSuchEntity` and
`QueryEntityError::NoSuchEntity` now contain an
`EntityDoesNotExistDetails` struct instead of an `UnsafeWorldCell`. If
you were just printing these, they should work identically.

---------

Co-authored-by: Benjamin Brienen <benjamin.brienen@outlook.com>
2025-01-05 02:01:01 +00:00
Zachary Harrold
0403948aa2
Remove Implicit std Prelude from no_std Crates (#17086)
# Background

In `no_std` compatible crates, there is often an `std` feature which
will allow access to the standard library. Currently, with the `std`
feature _enabled_, the
[`std::prelude`](https://doc.rust-lang.org/std/prelude/index.html) is
implicitly imported in all modules. With the feature _disabled_, instead
the [`core::prelude`](https://doc.rust-lang.org/core/prelude/index.html)
is implicitly imported. This creates a subtle and pervasive issue where
`alloc` items _may_ be implicitly included (if `std` is enabled), or
must be explicitly included (if `std` is not enabled).

# Objective

- Make the implicit imports for `no_std` crates consistent regardless of
what features are/not enabled.

## Solution

- Replace the `cfg_attr` "double negative" `no_std` attribute with
conditional compilation to _include_ `std` as an external crate.
```rust
// Before
#![cfg_attr(not(feature = "std"), no_std)]

// After
#![no_std]

#[cfg(feature = "std")]
extern crate std;
```
- Fix imports that are currently broken but are only now visible with
the above fix.

## Testing

- CI

## Notes

I had previously used the "double negative" version of `no_std` based on
general consensus that it was "cleaner" within the Rust embedded
community. However, this implicit prelude issue likely was considered
when forming this consensus. I believe the reason why is the items most
affected by this issue are provided by the `alloc` crate, which is
rarely used within embedded but extensively used within Bevy.
2025-01-03 01:58:43 +00:00
Vic
a4b89d0d5e
implement EntitySet and iter_many_unique methods (#16547)
# Objective

In current Bevy, it is very inconvenient to mutably retrieve a
user-provided list of entities more than one element at a time.
If the list contains any duplicate entities, we risk mutable aliasing.
Users of `Query::iter_many_mut` do not have access to `Iterator` trait,
and thus miss out on common functionality, for instance collecting their
`QueryManyIter`.
We can circumvent this issue with validation, however that entails
checking every entity against all others for inequality, or utilizing an
`EntityHashSet`. Even if an entity list remains unchanged, this
validation is/would have to be redone every time we wish to fetch with
the list.
This presents a lot of wasted work, as we often trivially know an entity
list to be unique f.e.: `QueryIter` will fetch every `Entity` once and
only once.
As more things become entities – assets, components, queries – this
issue will become more pronounced.
`get_many`/`many`/`iter_many`/`par_iter_many`-like functionality is all
affected.

## Solution

The solution this PR proposes is to introduce functionality built around
a new trait: `EntitySet`.

The goal is to preserve the property of "uniqueness" in a list wherever
possible, and then rely on it as a bound within new `*_many_unique`
methods to avoid the need for validation.

This is achieved using `Iterator`:
`EntitySet` is blanket implemented for any `T` that implements
`IntoIterator<IntoIter: EntitySetIterator>`.
`EntitySetIterator` is the unsafe trait that actually guarantees an
iterator to be "unique" via its safety contract.

We define an "Iterator over unique entities" as: "No two entities
returned by the iterator may compare equal."
For iterators that cannot return more than 1 element, this is trivially
true.
Whether an iterator can satisfy this is up to the `EntitySetIterator`
implementor to ensure, hence the unsafe.

However, this is not yet a complete solution. Looking at the signature
of `iter_many`, we find that `IntoIterator::Item` is not `Entity`, but
is instead bounded by the `Borrow<Entity>` trait. That is because
iteration without consuming the collection will often yield us
references, not owned items.

`Borrow<Entity>` presents an issue: The `Borrow` docs state that `x = y`
should equal `x.borrow() = y.borrow()`, but unsafe cannot rely on this
for soundness. We run into similar problems with other trait
implementations of any `Borrow<Entity>` type: `PartialEq`, `Eq`,
`PartialOrd`, `Ord`, `Hash`, `Clone`, `Borrow`, and `BorrowMut`.
This PR solves this with the unsafe `TrustedEntityBorrow` trait: 
Any implementor promises that the behavior of the aforementioned traits
matches that of the underlying entity.

While `Borrow<Entity>` was the inspiration, we use our own counterpart
trait `EntityBorrow` as the supertrait to `TrustedEntityBorrow`, so we
can circumvent the limitations of the existing `Borrow<T>` blanket
impls.

All together, these traits allow us to implement `*_many_unique`
functionality with a lone `EntitySet` bound.
`EntitySetIterator` is implemented for all the std iterators and
iterator adapters that guarantee or preserve uniqueness, so we can
filter, skip, take, step, reverse, ... our unique entity iterators
without worry!

Sadly, current `HashSet` iterators do not carry the necessary type
information with them to determine whether the source `HashSet` produces
logic errors; A malicious `Hasher` could compromise a `HashSet`.
`HashSet` iteration is generally discouraged in the first place, so we
also exclude the set operation iterators, even though they do carry the
`Hasher` type parameter.

`BTreeSet` implements `EntitySet` without any problems.

If an iterator type cannot guarantee uniqueness at compile time, then a
user can still attach `EntitySetIterator` to an individual instance of
that type via `UniqueEntityIter::from_iterator_unchecked`.
With this, custom types can use `UniqueEntityIter<I>` as their
`IntoIterator::IntoIter` type, if necessary.

This PR is focused on the base concept, and expansions on it are left
for follow-up PRs. See "Potential Future Work" below.

## Testing

Doctests on `iter_many_unique`/`iter_many_unique_mut` + 2 tests in
entity_set.rs.

## Showcase

```rust
// Before:
fn system(player_list: Res<SomeUniquePlayerList>, players: Query<&mut Player>) {
    let value = 0;
    while let Some(player) = players.iter_many_mut(player_list).fetch_next() {
         value += mem::take(player.value_mut())
    }
}

// After:
fn system(player_list: Res<SomeUniquePlayerList>, players: Query<&mut Player>) {
    let value = players
        .iter_many_unique_mut(player_list)
        .map(|player| mem::take(player.value_mut()))
        .sum();
}

```

## Changelog

- added `EntityBorrow`, `TrustedEntityBorrow`, `EntitySet` and
`EntitySetIterator` traits
- added `iter_many_unique`, `iter_many_unique_mut`,
`iter_many_unique_unsafe` methods on `Query`
- added `iter_many_unique`, `iter_many_unique_mut`,
`iter_many_unique_manual` and `iter_many_unique_unchecked_manual`
methods on `QueryState`
- added corresponding `QueryManyUniqueIter`
- added `UniqueEntityIter`

## Migration Guide

Any custom type used as a `Borrow<Entity>` entity list item for an
`iter_many` method now has to implement `EntityBorrow` instead. Any type
that implements `Borrow<Entity>` can trivially implement `EntityBorrow`.

## Potential Future Work

- `ToEntitySet` trait for converting any entity iterator into an
`EntitySetIterator`
- `EntityIndexSet/Map` to tie in hashing with `EntitySet`
- add `EntityIndexSetSlice/MapSlice`
    - requires: `EntityIndexSet/Map`
- Implementing `par_iter_many_unique_mut` for parallel mutable iteration
    - requires: `par_iter_many`
- allow collecting into `UniqueEntityVec` to store entity sets
- add `UniqueEntitySlice`s
    - Doesn't require, but should be done after: `UniqueEntityVec`
- add `UniqueEntityArray`s 
    - Doesn't require, but should be done after: `UniqueEntitySlice`
- `get_many_unique`/`many_unique` methods
    - requires: `UniqueEntityArray`
- `World::entity_unique` to match `World::entity` methods
- Doesn't require, but makes sense after:
`get_many_unique`/`many_unique`
- implement `TrustedEntityBorrow` for the `EntityRef` family
    - Doesn't require, but makes sense after: `UniqueEntityVec`
2024-12-18 00:49:01 +00:00
Zachary Harrold
1f2d0e6308
Add no_std support to bevy_ecs (#16758)
# Objective

- Contributes to #15460

## Solution

- Added the following features:
  - `std` (default)
  - `async_executor` (default)
  - `edge_executor`
  - `critical-section`
  - `portable-atomic`
- Gated `tracing` in `bevy_utils` to allow compilation on certain
platforms
- Switched from `tracing` to `log` for simple message logging within
`bevy_ecs`. Note that `tracing` supports capturing from `log` so this
should be an uncontroversial change.
- Fixed imports and added feature gates as required 
- Made `bevy_tasks` optional within `bevy_ecs`. Turns out it's only
needed for parallel operations which are already gated behind
`multi_threaded` anyway.

## Testing

- Added to `compile-check-no-std` CI command
- `cargo check -p bevy_ecs --no-default-features --features
edge_executor,critical-section,portable-atomic --target
thumbv6m-none-eabi`
- `cargo check -p bevy_ecs --no-default-features --features
edge_executor,critical-section`
- `cargo check -p bevy_ecs --no-default-features`

## Draft Release Notes

Bevy's core ECS now supports `no_std` platforms.

In prior versions of Bevy, it was not possible to work with embedded or
niche platforms due to our reliance on the standard library, `std`. This
has blocked a number of novel use-cases for Bevy, such as an embedded
database for IoT devices, or for creating games on retro consoles.

With this release, `bevy_ecs` no longer requires `std`. To use Bevy on a
`no_std` platform, you must disable default features and enable the new
`edge_executor` and `critical-section` features. You may also need to
enable `portable-atomic` and `critical-section` if your platform does
not natively support all atomic types and operations used by Bevy.

```toml
[dependencies]
bevy_ecs = { version = "0.16", default-features = false, features = [
  # Required for platforms with incomplete atomics (e.g., Raspberry Pi Pico)
  "portable-atomic",
  "critical-section",

  # Optional
  "bevy_reflect",
  "serialize",
  "bevy_debug_stepping",
  "edge_executor"
] }
```

Currently, this has been tested on bare-metal x86 and the Raspberry Pi
Pico. If you have trouble using `bevy_ecs` on a particular platform,
please reach out either through a GitHub issue or in the `no_std`
working group on the Bevy Discord server.

Keep an eye out for future `no_std` updates as we continue to improve
the parity between `std` and `no_std`. We look forward to seeing what
kinds of applications are now possible with Bevy!

## Notes

- Creating PR in draft to ensure CI is passing before requesting
reviews.
- This implementation has no support for multithreading in `no_std`,
especially due to `NonSend` being unsound if allowed in multithreading.
The reason is we cannot check the `ThreadId` in `no_std`, so we have no
mechanism to at-runtime determine if access is sound.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Vic <59878206+Victoronz@users.noreply.github.com>
2024-12-17 21:40:36 +00:00
SpecificProtagonist
21195a75e6
track_change_detection: Also track spawns/despawns (#16047)
# Objective

Expand `track_change_detection` feature to also track entity spawns and
despawns. Use this to create better error messages.

# Solution

Adds `Entities::entity_get_spawned_or_despawned_by` as well as `{all
entity reference types}::spawned_by`.

This also removes the deprecated `get_many_entities_mut` & co (and
therefore can't land in 0.15) because we don't yet have no Polonius.

## Testing

Added a test that checks that the locations get updated and these
updates are ordered correctly vs hooks & observers.

---

## Showcase

Access location:
```rust
let mut world = World::new();
let entity = world.spawn_empty().id();
println!("spawned by: {}", world.entity(entity).spawned_by());
```
```
spawned by: src/main.rs:5:24
```
Error message (with `track_change_detection`):
```rust
world.despawn(entity);
world.entity(entity);
```
```
thread 'main' panicked at src/main.rs:11:11:
Entity 0v1#4294967296 was despawned by src/main.rs:10:11
```
and without:
```
thread 'main' panicked at src/main.rs:11:11:
Entity 0v1#4294967296 does not exist (enable `track_change_detection` feature for more details)
```
Similar error messages now also exists for `Query::get`,
`World::entity_mut`, `EntityCommands` creation and everything that
causes `B0003`, e.g.
```
error[B0003]: Could not insert a bundle (of type `MaterialMeshBundle<StandardMaterial>`) for entity Entity { index: 7, generation: 1 }, which was despawned by src/main.rs:10:11. See: https://bevyengine.org/learn/errors/#b0003
```

---------

Co-authored-by: kurk070ff <108901106+kurk070ff@users.noreply.github.com>
Co-authored-by: Freya Pines <freya@MacBookAir.lan>
Co-authored-by: Freya Pines <freya@Freyas-MacBook-Air.local>
Co-authored-by: Matty Weatherley <weatherleymatthew@gmail.com>
2024-12-17 04:46:31 +00:00
Chris Russell
5f4b5a37f1
Support declaring resource access in Queries. (#16843)
# Objective

Allow resources to be accessed soundly by `QueryData` and `QueryFilter`
implementations.

This mostly works today, and is used in `bevy-trait-query` and will be
used by #16810. The problem is that the access is not made visible to
the executor, so it would be possible for a system with resource access
in a query to run concurrently with a system that accesses the resource
with `ResMut`, resulting in Undefined Behavior.

## Solution

Define calling `add_resource_read` or `add_resource_write` in
`WorldQuery::update_component_access` to be a supported way to declare
resource access in a query.
Modify `QueryState::new_with_access` to check for resource access and
report it in `archetype_component_acccess`.
Modify `FilteredAccess::is_compatible` to consider resource access
conflicting even on queries with disjoint filters.
2024-12-17 00:03:20 +00:00
vil'mo
2a1064ec5e
Getting QueryState from immutable World reference (#16434)
# Objective

There is currently no way of getting `QueryState` from `&World`, so it
is hard to, for example, iterate over all entities with a component,
only having `&World`.

## Solution

Add `try_new` function to `QueryState` that internally uses
`WorldQuery`'s `get_state`.

## Testing

No testing
2024-12-01 20:09:29 +00:00
Zachary Harrold
d70595b667
Add core and alloc over std Lints (#15281)
# Objective

- Fixes #6370
- Closes #6581

## Solution

- Added the following lints to the workspace:
  - `std_instead_of_core`
  - `std_instead_of_alloc`
  - `alloc_instead_of_core`
- Used `cargo +nightly fmt` with [item level use
formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Item%5C%3A)
to split all `use` statements into single items.
- Used `cargo clippy --workspace --all-targets --all-features --fix
--allow-dirty` to _attempt_ to resolve the new linting issues, and
intervened where the lint was unable to resolve the issue automatically
(usually due to needing an `extern crate alloc;` statement in a crate
root).
- Manually removed certain uses of `std` where negative feature gating
prevented `--all-features` from finding the offending uses.
- Used `cargo +nightly fmt` with [crate level use
formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Crate%5C%3A)
to re-merge all `use` statements matching Bevy's previous styling.
- Manually fixed cases where the `fmt` tool could not re-merge `use`
statements due to conditional compilation attributes.

## Testing

- Ran CI locally

## Migration Guide

The MSRV is now 1.81. Please update to this version or higher.

## Notes

- This is a _massive_ change to try and push through, which is why I've
outlined the semi-automatic steps I used to create this PR, in case this
fails and someone else tries again in the future.
- Making this change has no impact on user code, but does mean Bevy
contributors will be warned to use `core` and `alloc` instead of `std`
where possible.
- This lint is a critical first step towards investigating `no_std`
options for Bevy.

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-09-27 00:59:59 +00:00
hshrimp
35d10866b8
Rename init_component & friends (#15454)
# Objective

- Fixes #15451 

## Migration Guide

- `World::init_component` has been renamed to `register_component`.
- `World::init_component_with_descriptor` has been renamed to
`register_component_with_descriptor`.
- `World::init_bundle` has been renamed to `register_bundle`.
- `Components::init_component` has been renamed to `register_component`.
- `Components::init_component_with_descriptor` has been renamed to
`register_component_with_descriptor`.
- `Components::init_resource` has been renamed to `register_resource`.
- `Components::init_non_send` had been renamed to `register_non_send`.
2024-09-26 22:47:28 +00:00
SpecificProtagonist
5e6b141c13
List components for QueryEntityError::QueryDoesNotMatch (#15435)
# Objective

Make it easier to debug why an entity doesn't match a query.

## Solution

List the entities components in `QueryEntityError::QueryDoesNotMatch`'s
message, e.g. `The query does not match the entity 0v1, which has
components foo::Bar, foo::Baz`.
This covers most cases as expected components are typically known and
filtering for change detection is rare when assessing a query by entity
id.

## Testing

Added a test confirming the new message matches the entity's components.

## Migration Guide

- `QueryEntityError` now has a lifetime. Convert it to a custom error if
you need to store it.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: poopy <gonesbird@gmail.com>
2024-09-26 13:31:11 +00:00
Clar Fon
efda7f3f9c
Simpler lint fixes: makes ci lints work but disables a lint for now (#15376)
Takes the first two commits from #15375 and adds suggestions from this
comment:
https://github.com/bevyengine/bevy/pull/15375#issuecomment-2366968300

See #15375 for more reasoning/motivation.

## Rebasing (rerunning)

```rust
git switch simpler-lint-fixes
git reset --hard main
cargo fmt --all -- --unstable-features --config normalize_comments=true,imports_granularity=Crate
cargo fmt --all
git add --update
git commit --message "rustfmt"
cargo clippy --workspace --all-targets --all-features --fix
cargo fmt --all -- --unstable-features --config normalize_comments=true,imports_granularity=Crate
cargo fmt --all
git add --update
git commit --message "clippy"
git cherry-pick e6c0b94f6795222310fb812fa5c4512661fc7887
```
2024-09-24 11:42:59 +00:00
TheBigCheese
b1273d48cb
Enable clippy::check-private-items so that missing_safety_doc will apply to private functions as well (#15161)
Enabled `check-private-items` in `clippy.toml` and then fixed the
resulting errors. Most of these were simply misformatted and of the
remaining:
- ~Added `#[allow(clippy::missing_safety_doc)]` to~ Removed unsafe from
a pair of functions in `bevy_utils/futures` which are only unsafe so
that they can be passed to a function which requires `unsafe fn`
- Removed `unsafe` from `UnsafeWorldCell::observers` as from what I can
tell it is always safe like `components`, `bundles` etc. (this should be
checked)
- Added safety docs to:
- `Bundles::get_storage_unchecked`: Based on the function that writes to
`dynamic_component_storages`
- `Bundles::get_storages_unchecked`: Based on the function that writes
to `dynamic_bundle_storages`
   - `QueryIterationCursor::init_empty`: Duplicated from `init`
- `QueryIterationCursor::peek_last`: Thanks Giooschi (also added
internal unsafe blocks)
   - `tests::drop_ptr`: Moved safety comment out to the doc string
 
This lint would also apply to `missing_errors_doc`, `missing_panics_doc`
and `unnecessary_safety_doc` if we chose to enable any of those at some
point, although there is an open
[issue](https://github.com/rust-lang/rust-clippy/issues/13074) to
separate these options.
2024-09-18 15:28:41 +00:00
Patrick Walton
3c41586154
Add EntityRefExcept and EntityMutExcept world queries, in preparation for generalized animation. (#15207)
This commit adds two new `WorldQuery` types: `EntityRefExcept` and
`EntityMutExcept`. These types work just like `EntityRef` and
`EntityMut`, but they prevent access to a statically-specified list of
components. For example, `EntityMutExcept<(AnimationPlayer,
Handle<AnimationGraph>)>` provides mutable access to all components
except for `AnimationPlayer` and `Handle<AnimationGraph>`. These types
are useful when you need to be able to process arbitrary queries while
iterating over the results of another `EntityMut` query.

The motivating use case is *generalized animation*, which is an upcoming
feature that allows animation of any component property, not just
rotation, translation, scaling, or morph weights. To implement this, we
must change the current `AnyOf<(&mut Transform, &mut MorphWeights)>` to
instead be `EntityMutExcept<(AnimationPlayer, Handle<AnimationGraph>)>`.
It's possible to use `FilteredEntityMut` in conjunction with a
dynamically-generated system instead, but `FilteredEntityMut` isn't
optimized for the use case of a large number of allowed components
coupled with a small set of disallowed components. No amount of
optimization of `FilteredEntityMut` produced acceptable performance on
the `many_foxes` benchmark. `Query<EntityMut, Without<AnimationPlayer>>`
will not suffice either, as it's legal and idiomatic for an
`AnimationTarget` and an `AnimationPlayer` to coexist on the same
entity.

An alternate proposal was to implement a somewhat-more-general
`Except<Q, CL>` feature, where Q is a `WorldQuery` and CL is a
`ComponentList`. I wasn't able to implement that proposal in a
reasonable way, because of the fact that methods like
`EntityMut::get_mut` and `EntityRef::get` are inherent methods instead
of methods on `WorldQuery`, and therefore there was no way to delegate
methods like `get` and `get_mut` to the inner query in a generic way.
Refactoring those methods into a trait would probably be possible.
However, I didn't see a use case for a hypothetical `Except` with
arbitrary queries: `Query<Except<(&Transform, &Visibility),
Visibility>>` would just be a complicated equivalent to
`Query<&Transform>`, for instance. So, out of a desire for simplicity, I
omitted a generic `Except` mechanism.

I've tested the performance of generalized animation on `many_foxes` and
found that, with this patch, `animate_targets` has a 7.4% slowdown over
`main`. With `FilteredEntityMut` optimized to use `Arc<Access>`, the
slowdown is 75.6%, due to contention on the reference count. Without
`Arc<Access>`, the slowdown is even worse, over 2x.

## Testing

New tests have been added that check that `EntityRefExcept` and
`EntityMutExcept` allow and disallow access to components properly and
that the query engine can correctly reject conflicting queries involving
those types.

A Tracy profile of `many_foxes` with 10,000 foxes showing generalized
animation using `FilteredEntityMut` (red) vs. main (yellow) is as
follows:

![Screenshot 2024-09-12
225914](https://github.com/user-attachments/assets/2993d74c-a513-4ba4-85bd-225672e7170a)

A Tracy profile of `many_foxes` with 10,000 foxes showing generalized
animation using this `EntityMutExcept` (yellow) vs. main (red) is as
follows:

![Screenshot 2024-09-14
205831](https://github.com/user-attachments/assets/4241015e-0c5d-44ef-835b-43f78a24e604)
2024-09-17 14:53:39 +00:00
Tim
5adacf014c
Use associated type bounds for iter_many and friends (#15040)
# Objective

Make the bounds for these query methods less intimidating.
Continuation of #14107

<sub>My last pr was back in february 💀
2024-09-09 16:24:39 +00:00
re0312
739007f148
Opportunistically use dense iter for archetypal iteration in Par_iter (#14673)
# Objective

- follow of #14049 ,we could use it on our Parallel Iterator,this pr
also unified the used function in both regular iter and parallel
iterations.


## Performance 


![image](https://github.com/user-attachments/assets/cba700bc-169c-4b58-b504-823bdca8ec05)

no performance regression for regular itertaion

3.5X faster in hybrid parallel iteraion,this number is far greater than
the benefits obtained in regular iteration(~1.81) because mutable
iterations on continuous memory can effectively reduce the cost of
mataining core cache coherence
2024-09-03 23:41:10 +00:00
Giacomo Stevanato
e320fa0738
Fix query transmute from table to archetype iteration unsoundness (#14615)
# Objective

- Fixes #14348 
- Fixes #14528
- Less complex (but also likely less performant) alternative to #14611

## Solution

- Add a `is_dense` field flag to `QueryIter` indicating whether it is
dense or not, that is whether it can perform dense iteration or not;
- Check this flag any time iteration over a query is performed.

---

It would be nice if someone could try benching this change to see if it
actually matters.

~Note that this not 100% ready for mergin, since there are a bunch of
safety comments on the use of the various `IS_DENSE` for checks that
still need to be updated.~ This is ready modulo benchmarks

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-08-27 00:58:40 +00:00
EdJoPaTo
938d810766
Apply unused_qualifications lint (#14828)
# Objective

Fixes #14782

## Solution

Enable the lint and fix all upcoming hints (`--fix`). Also tried to
figure out the false-positive (see review comment). Maybe split this PR
up into multiple parts where only the last one enables the lint, so some
can already be merged resulting in less many files touched / less
potential for merge conflicts?

Currently, there are some cases where it might be easier to read the
code with the qualifier, so perhaps remove the import of it and adapt
its cases? In the current stage it's just a plain adoption of the
suggestions in order to have a base to discuss.

## Testing

`cargo clippy` and `cargo run -p ci` are happy.
2024-08-21 12:29:33 +00:00
Periwink
3a664b052d
Separate component and resource access (#14561)
# Objective

- Fixes https://github.com/bevyengine/bevy/issues/13139
- Fixes https://github.com/bevyengine/bevy/issues/7255
- Separates component from resource access so that we can correctly
handles edge cases like the issue above
- Inspired from https://github.com/bevyengine/bevy/pull/14472

## Solution

- Update access to have `component` fields and `resource` fields

## Testing

- Added some unit tests
2024-08-06 01:19:39 +00:00
Periwink
ec4cf024f8
Add a ComponentIndex and update QueryState creation/update to use it (#13460)
# Objective

To implement relations we will need to add a `ComponentIndex`, which is
a map from a Component to the list of archetypes that contain this
component.
One of the reasons is that with fragmenting relations the number of
archetypes will explode, so it will become inefficient to create and
update the query caches by iterating through the list of all archetypes.

In this PR, we introduce the `ComponentIndex`, and we update the
`QueryState` to make use of it:
- if a query has at least 1 required component (i.e. something other
than `()`, `Entity` or `Option<>`, etc.): for each of the required
components we find the list of archetypes that contain it (using the
ComponentIndex). Then, we select the smallest list among these. This
gives a small subset of archetypes to iterate through compared with
iterating through all new archetypes
- if it doesn't, then we keep using the current approach of iterating
through all new archetypes


# Implementation
- This breaks query iteration order, in the sense that we are not
guaranteed anymore to return results in the order in which the
archetypes were created. I think this should be fine because this wasn't
an explicit bevy guarantee so users should not be relying on this. I
updated a bunch of unit tests that were failing because of this.

- I had an issue with the borrow checker because iterating the list of
potential archetypes requires access to `&state.component_access`, which
was conflicting with the calls to
```
  if state.new_archetype_internal(archetype) {
      state.update_archetype_component_access(archetype, access);
  }
```
which need a mutable access to the state.

The solution I chose was to introduce a `QueryStateView` which is a
temporary view into the `QueryState` which enables a "split-borrows"
kind of approach. It is described in detail in this blog post:
https://smallcultfollowing.com/babysteps/blog/2018/11/01/after-nll-interprocedural-conflicts/

# Test

The unit tests pass.

Benchmark results:
```
❯ critcmp main pr
group                                  main                                   pr
-----                                  ----                                   --
iter_fragmented/base                   1.00   342.2±25.45ns        ? ?/sec    1.02   347.5±16.24ns        ? ?/sec
iter_fragmented/foreach                1.04   165.4±11.29ns        ? ?/sec    1.00    159.5±4.27ns        ? ?/sec
iter_fragmented/foreach_wide           1.03      3.3±0.04µs        ? ?/sec    1.00      3.2±0.06µs        ? ?/sec
iter_fragmented/wide                   1.03      3.1±0.06µs        ? ?/sec    1.00      3.0±0.08µs        ? ?/sec
iter_fragmented_sparse/base            1.00      6.5±0.14ns        ? ?/sec    1.02      6.6±0.08ns        ? ?/sec
iter_fragmented_sparse/foreach         1.00      6.3±0.08ns        ? ?/sec    1.04      6.6±0.08ns        ? ?/sec
iter_fragmented_sparse/foreach_wide    1.00     43.8±0.15ns        ? ?/sec    1.02     44.6±0.53ns        ? ?/sec
iter_fragmented_sparse/wide            1.00     29.8±0.44ns        ? ?/sec    1.00     29.8±0.26ns        ? ?/sec
iter_simple/base                       1.00      8.2±0.10µs        ? ?/sec    1.00      8.2±0.09µs        ? ?/sec
iter_simple/foreach                    1.00      3.8±0.02µs        ? ?/sec    1.02      3.9±0.03µs        ? ?/sec
iter_simple/foreach_sparse_set         1.00     19.0±0.26µs        ? ?/sec    1.01     19.3±0.16µs        ? ?/sec
iter_simple/foreach_wide               1.00     17.8±0.24µs        ? ?/sec    1.00     17.9±0.31µs        ? ?/sec
iter_simple/foreach_wide_sparse_set    1.06     95.6±6.23µs        ? ?/sec    1.00     90.6±0.59µs        ? ?/sec
iter_simple/sparse_set                 1.00     19.3±1.63µs        ? ?/sec    1.01     19.5±0.29µs        ? ?/sec
iter_simple/system                     1.00      8.1±0.10µs        ? ?/sec    1.00      8.1±0.09µs        ? ?/sec
iter_simple/wide                       1.05     37.7±2.53µs        ? ?/sec    1.00     35.8±0.57µs        ? ?/sec
iter_simple/wide_sparse_set            1.00     95.7±1.62µs        ? ?/sec    1.00     95.9±0.76µs        ? ?/sec
par_iter_simple/with_0_fragment        1.04     35.0±2.51µs        ? ?/sec    1.00     33.7±0.49µs        ? ?/sec
par_iter_simple/with_1000_fragment     1.00     50.4±2.52µs        ? ?/sec    1.01     51.0±3.84µs        ? ?/sec
par_iter_simple/with_100_fragment      1.02     40.3±2.23µs        ? ?/sec    1.00     39.5±1.32µs        ? ?/sec
par_iter_simple/with_10_fragment       1.14     38.8±7.79µs        ? ?/sec    1.00     34.0±0.78µs        ? ?/sec
```
2024-08-06 00:57:15 +00:00
Giacomo Stevanato
68ec6f4f50
Make QueryState::transmute&co validate the world of the &Components used (#14631)
# Objective

- Fix #14629

## Solution

- Make `QueryState::transmute`, `QueryState::transmute_filtered`,
`QueryState::join` and `QueryState::join_filtered` take a `impl
Into<UnsafeWorldCell>` instead of a `&Components` and validate their
`WorldId`

## Migration Guide

- `QueryState::transmute`, `QueryState::transmute_filtered`,
`QueryState::join` and `QueryState::join_filtered` now take a `impl
Into<UnsafeWorldCell>` instead of a `&Components`

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-08-05 22:39:31 +00:00
Jan Hohenheim
6273227e09
Fix lints introduced in Rust beta 1.80 (#13899)
Resolves #13895

Mostly just involves being more explicit about which parts of the docs
belong to a list and which begin a new paragraph.
- found a few docs that were malformed because of exactly this, so I
fixed that by introducing a paragraph
- added indentation to nearly all multiline lists
- fixed a few minor typos
- added `#[allow(dead_code)]` to types that are needed to test
annotations but are never constructed
([here](https://github.com/bevyengine/bevy/pull/13899/files#diff-b02b63604e569c8577c491e7a2030d456886d8f6716eeccd46b11df8aac75dafR1514)
and
[here](https://github.com/bevyengine/bevy/pull/13899/files#diff-b02b63604e569c8577c491e7a2030d456886d8f6716eeccd46b11df8aac75dafR1523))
- verified that  `cargo +beta run -p ci -- lints` passes
- verified that `cargo +beta run -p ci -- test` passes
2024-06-17 17:22:01 +00:00
Mike
07a85676b3
Revert "constrain WorldQuery::init_state argument to ComponentInitial… (#13804)
…izer (#13442)"

This reverts commit 5cfb063d4a.

- This PR broke bevy-trait-query, which needs to be able to write a
resource in init_state. See #13798 for more details.
- Note this doesn't fix everything as transmutes for bevy-trait-query
will still be broken,. But the current usage in that crate is UB, so we
need to find another solution.
2024-06-11 22:54:42 +00:00
Vic
5cfb063d4a
constrain WorldQuery::init_state argument to ComponentInitializer (#13442)
# Objective

In #13343, `WorldQuery::get_state` was constrained from `&World` as the
argument to `&Components`, but `WorldQuery::init_state` hasn't yet been
changed from `&mut World` to match.

Fixes #13358

## Solution

Create a wrapper around `&mut Components` and `&mut Storages` that can
be obtained from `&mut World` with a `component_initializer` method.
This new `ComponentInitializer` re-exposes the API on `&mut Components`
minus the `&mut Storages` parameter where it was present. For the
`&Components` API, it simply derefs to its `components` field.

## Changelog

### Added
The `World::component_initializer` method.
The `ComponentInitializer` struct that re-exposes `Components` API.
### Changed
`WorldQuery::init_state` now takes `&mut ComponentInitializer` instead
of `&mut World`.

## Migration Guide
Instead of passing `&mut World` to `WorldQuery::init_state` directly,
pass in a mutable reference to the struct returned from
`World::component_initializer`.
2024-05-30 14:47:22 +00:00
Vic
0eb4bb6bab
constrain WorldQuery::get_state to only use &Components (#13343)
# Objective

Passing `&World` in the `WorldQuery::get_state` method is unnecessary,
as all implementations of this method in the engine either only access
`Components` in `&World`, or do nothing with it.
It can introduce UB by necessitating the creation of a `&World` from a
`UnsafeWorldCell`.
This currently happens in `Query::transmute_lens`, which obtains a
`&World` from the internal `UnsafeWorldCell` solely to pass to
`get_state`. `Query::join` suffers from the same issue.
Other cases of UB come from allowing implementors of `WorldQuery` to
freely access `&World`, like in the `bevy-trait-query` crate, where a
[reference to a resource is
obtained](0c0e7dd646/src/lib.rs (L445))
inside of
[`get_state`](0c0e7dd646/src/one.rs (L245)),
potentially aliasing with a `ResMut` parameter in the same system.

`WorldQuery::init_state` currently requires `&mut World`, which doesn't
suffer from these issues.
But that too can be changed to receive a wrapper around `&mut
Components` and `&mut Storages` for consistency in a follow-up PR.

## Solution

Replace the `&World` parameter in `get_state` with `&Components`.

## Changelog

 `WorldQuery::get_state` now takes `&Components` instead of `&World`.
The `transmute`, `transmute_filtered`, `join` and `join_filtered`
methods on `QueryState` now similarly take `&Components` instead of
`&World`.

## Migration Guide

Users of `WorldQuery::get_state` or `transmute`, `transmute_filtered`,
`join` and `join_filtered` methods on `QueryState` now need to pass
`&Components` instead of `&World`.
`&Components` can be trivially obtained from either `components` method
on `&World` or `UnsafeWorldCell`.
For implementors of `WorldQuery::get_state` that were accessing more
than the `Components` inside `&World` and its methods, this is no longer
allowed.
2024-05-13 21:00:01 +00:00
andristarr
bb76a2c69c
multi_threaded feature rename (#12997)
# Objective

Fixes #12966

## Solution

Renaming multi_threaded feature to match snake case

## Migration Guide

Bevy feature multi-threaded should be refered to multi_threaded from now
on.
2024-05-06 20:49:32 +00:00
re0312
0f27500e46
Improve par_iter and Parallel (#12904)
# Objective

- bevy usually use `Parallel::scope` to collect items from `par_iter`,
but `scope` will be called with every satifified items. it will cause a
lot of unnecessary lookup.

## Solution

- similar to Rayon ,we introduce `for_each_init` for `par_iter` which
only be invoked when spawn a task for a group of items.

---

## Changelog

- added  `for_each_init`

## Performance
`check_visibility `  in  `many_foxes ` 

![image](https://github.com/bevyengine/bevy/assets/45868716/030c41cf-0d2f-4a36-a071-35097d93e494)
 
~40% performance gain in `check_visibility`.

---------

Co-authored-by: James Liu <contact@jamessliu.com>
2024-04-23 12:05:34 +00:00
Jonathan
e9be54b0ea
Parallel event reader (#12554)
# Objective

Allow parallel iteration over events, resolve #10766

## Solution

- Add `EventParIter` which works similarly to `QueryParIter`,
implementing a `for_each{_with_id}` operator.
I chose to not mirror `EventIteratorWithId` and instead implement both
operations on a single struct.
- Reuse `BatchingStrategy` from `QueryParIter`

## Changelog

- `EventReader` now supports parallel event iteration using
`par_read().for_each(|event| ...)`.

---------

Co-authored-by: James Liu <contact@jamessliu.com>
Co-authored-by: Pablo Reinhardt <126117294+pablo-lua@users.noreply.github.com>
2024-04-22 16:37:42 +00:00
James Liu
54456b7ea6
Make SystemParam::new_archetype and QueryState::new_archetype unsafe functions (#13044)
# Objective
Fix #2128. Both `Query::new_archetype` and `SystemParam::new_archetype`
do not check if the `Archetype` comes from the same World the state is
initialized from. This could result in unsoundness via invalid accesses
if called incorrectly.

## Solution
Make them `unsafe` functions and lift the invariant to the caller. This
also caught one instance of us not validating the World in
`SystemState::update_archetypes_unsafe_world_cell`'s implementation.

---

## Changelog
Changed: `QueryState::new_archetype` is now an unsafe function.
Changed: `SystemParam::new_archetype` is now an unsafe function.

## Migration Guide
`QueryState::new_archetype` and `SystemParam::new_archetype` are now an
unsafe functions that must be sure that the provided `Archetype` is from
the same `World` that the state was initialized from. Callers may need
to add additional assertions or propagate the safety invariant upwards
through the callstack to ensure safety.
2024-04-21 02:49:42 +00:00
targrub
8316166622
Fix uses of "it's" vs "its". (#13033)
Grammar changes only.
2024-04-19 18:17:31 +00:00
re0312
4ca8cf5d66
Cluster small table/archetype into single Task in parallel iteration (#12846)
# Objective

- Fix #7303
- bevy would spawn a lot of tasks in parallel iteration when it matchs a
large storage and many small storage ,it significantly increase the
overhead of schedule.

## Solution

- collect small storage into one task
2024-04-04 07:09:26 +00:00
James Liu
286bc8cce5
Store only the IDs needed for Query iteration (#12476)
# Objective
Other than the exposed functions for reading matched tables and
archetypes, a `QueryState` does not actually need both internal Vecs for
storing matched archetypes and tables. In practice, it will only use one
of the two depending on if it uses dense or archetypal iteration.

Same vein as #12474. The goal is to reduce the memory overhead of using
queries, which Bevy itself, ecosystem plugins, and end users are already
fairly liberally using.

## Solution
Add `StorageId`, which is a union over `TableId` and `ArchetypeId`, and
store only one of the two at runtime. Read the slice as if it was one ID
depending on whether the query is dense or not.

This follows in the same vein as #5085; however, this one directly
impacts heap memory usage at runtime, while #5085 primarily targeted
transient pointers that might not actually exist at runtime.

---

## Changelog
Changed: `QueryState::matched_tables` now returns an iterator instead of
a reference to a slice.
Changed: `QueryState::matched_archetypes` now returns an iterator
instead of a reference to a slice.

## Migration Guide
`QueryState::matched_tables` and `QueryState::matched_archetypes` does
not return a reference to a slice, but an iterator instead. You may need
to use iterator combinators or collect them into a Vec to use it as a
slice.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-03-30 10:15:55 +00:00