Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

1
vendor/bevy_ecs/.cargo-checksum.json vendored Normal file

File diff suppressed because one or more lines are too long

1033
vendor/bevy_ecs/Cargo.lock generated vendored Normal file

File diff suppressed because it is too large Load Diff

267
vendor/bevy_ecs/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,267 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2024"
rust-version = "1.85.0"
name = "bevy_ecs"
version = "0.16.1"
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "Bevy Engine's entity component system"
homepage = "https://bevyengine.org"
readme = "README.md"
keywords = [
"ecs",
"game",
"bevy",
]
categories = [
"game-engines",
"data-structures",
]
license = "MIT OR Apache-2.0"
repository = "https://github.com/bevyengine/bevy"
resolver = "2"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = [
"-Zunstable-options",
"--generate-link-to-definition",
]
[features]
async_executor = [
"std",
"bevy_tasks/async_executor",
]
backtrace = ["std"]
bevy_debug_stepping = []
bevy_reflect = ["dep:bevy_reflect"]
configurable_error_handler = []
critical-section = [
"bevy_tasks/critical-section",
"bevy_platform/critical-section",
"bevy_reflect?/critical-section",
]
default = [
"std",
"bevy_reflect",
"async_executor",
"backtrace",
]
detailed_trace = ["trace"]
multi_threaded = [
"bevy_tasks/multi_threaded",
"dep:arrayvec",
]
reflect_functions = [
"bevy_reflect",
"bevy_reflect/functions",
]
serialize = [
"dep:serde",
"bevy_utils/serde",
"bevy_platform/serialize",
"indexmap/serde",
]
std = [
"bevy_reflect?/std",
"bevy_tasks/std",
"bevy_utils/std",
"bitflags/std",
"concurrent-queue/std",
"disqualified/alloc",
"fixedbitset/std",
"indexmap/std",
"serde?/std",
"nonmax/std",
"arrayvec?/std",
"log/std",
"bevy_platform/std",
]
trace = [
"std",
"dep:tracing",
]
track_location = []
[lib]
name = "bevy_ecs"
path = "src/lib.rs"
[[example]]
name = "change_detection"
path = "examples/change_detection.rs"
[[example]]
name = "events"
path = "examples/events.rs"
[[example]]
name = "resources"
path = "examples/resources.rs"
[dependencies.arrayvec]
version = "0.7.4"
optional = true
default-features = false
[dependencies.bevy_ecs_macros]
version = "0.16.1"
[dependencies.bevy_platform]
version = "0.16.1"
features = ["alloc"]
default-features = false
[dependencies.bevy_ptr]
version = "0.16.1"
[dependencies.bevy_reflect]
version = "0.16.1"
features = ["smallvec"]
optional = true
default-features = false
[dependencies.bevy_tasks]
version = "0.16.1"
default-features = false
[dependencies.bevy_utils]
version = "0.16.1"
features = ["alloc"]
default-features = false
[dependencies.bitflags]
version = "2.3"
default-features = false
[dependencies.bumpalo]
version = "3"
[dependencies.concurrent-queue]
version = "2.5.0"
default-features = false
[dependencies.derive_more]
version = "1"
features = [
"from",
"display",
"into",
"as_ref",
]
default-features = false
[dependencies.disqualified]
version = "1.0"
default-features = false
[dependencies.fixedbitset]
version = "0.5"
default-features = false
[dependencies.indexmap]
version = "2.5.0"
default-features = false
[dependencies.log]
version = "0.4"
default-features = false
[dependencies.nonmax]
version = "0.5"
default-features = false
[dependencies.serde]
version = "1"
features = [
"alloc",
"serde_derive",
]
optional = true
default-features = false
[dependencies.smallvec]
version = "1"
features = [
"union",
"const_generics",
]
[dependencies.thiserror]
version = "2"
default-features = false
[dependencies.tracing]
version = "0.1"
optional = true
default-features = false
[dependencies.variadics_please]
version = "1.1"
default-features = false
[dev-dependencies.rand]
version = "0.8"
[dev-dependencies.serde_test]
version = "1.0"
[dev-dependencies.static_assertions]
version = "1.1.0"
[target.'cfg(not(all(target_has_atomic = "8", target_has_atomic = "16", target_has_atomic = "32", target_has_atomic = "64", target_has_atomic = "ptr")))'.dependencies.concurrent-queue]
version = "2.5.0"
features = ["portable-atomic"]
default-features = false
[lints.clippy]
alloc_instead_of_core = "warn"
allow_attributes = "warn"
allow_attributes_without_reason = "warn"
doc_markdown = "warn"
manual_let_else = "warn"
match_same_arms = "warn"
needless_lifetimes = "allow"
nonstandard_macro_braces = "warn"
print_stderr = "warn"
print_stdout = "warn"
ptr_as_ptr = "warn"
ptr_cast_constness = "warn"
redundant_closure_for_method_calls = "warn"
redundant_else = "warn"
ref_as_ptr = "warn"
semicolon_if_nothing_returned = "warn"
std_instead_of_alloc = "warn"
std_instead_of_core = "warn"
too_long_first_doc_paragraph = "allow"
too_many_arguments = "allow"
type_complexity = "allow"
undocumented_unsafe_blocks = "warn"
unwrap_or_default = "warn"
[lints.rust]
missing_docs = "warn"
unsafe_code = "deny"
unsafe_op_in_unsafe_fn = "warn"
unused_qualifications = "warn"
[lints.rust.unexpected_cfgs]
level = "warn"
priority = 0
check-cfg = ["cfg(docsrs_dep)"]

176
vendor/bevy_ecs/LICENSE-APACHE vendored Normal file
View File

@@ -0,0 +1,176 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

19
vendor/bevy_ecs/LICENSE-MIT vendored Normal file
View File

@@ -0,0 +1,19 @@
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

352
vendor/bevy_ecs/README.md vendored Normal file
View File

@@ -0,0 +1,352 @@
# Bevy ECS
[![License](https://img.shields.io/badge/license-MIT%2FApache-blue.svg)](https://github.com/bevyengine/bevy#license)
[![Crates.io](https://img.shields.io/crates/v/bevy_ecs.svg)](https://crates.io/crates/bevy_ecs)
[![Downloads](https://img.shields.io/crates/d/bevy_ecs.svg)](https://crates.io/crates/bevy_ecs)
[![Docs](https://docs.rs/bevy_ecs/badge.svg)](https://docs.rs/bevy_ecs/latest/bevy_ecs/)
[![Discord](https://img.shields.io/discord/691052431525675048.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/bevy)
## What is Bevy ECS?
Bevy ECS is an Entity Component System custom-built for the [Bevy][bevy] game engine.
It aims to be simple to use, ergonomic, fast, massively parallel, opinionated, and featureful.
It was created specifically for Bevy's needs, but it can easily be used as a standalone crate in other projects.
## ECS
All app logic in Bevy uses the Entity Component System paradigm, which is often shortened to ECS. ECS is a software pattern that involves breaking your program up into Entities, Components, and Systems. Entities are unique "things" that are assigned groups of Components, which are then processed using Systems.
For example, one entity might have a `Position` and `Velocity` component, whereas another entity might have a `Position` and `UI` component. You might have a movement system that runs on all entities with a Position and Velocity component.
The ECS pattern encourages clean, decoupled designs by forcing you to break up your app data and logic into its core components. It also helps make your code faster by optimizing memory access patterns and making parallelism easier.
## Concepts
Bevy ECS is Bevy's implementation of the ECS pattern. Unlike other Rust ECS implementations, which often require complex lifetimes, traits, builder patterns, or macros, Bevy ECS uses normal Rust data types for all of these concepts:
### Components
Components are normal Rust structs. They are data stored in a `World` and specific instances of Components correlate to Entities.
```rust
use bevy_ecs::prelude::*;
#[derive(Component)]
struct Position { x: f32, y: f32 }
```
### Worlds
Entities, Components, and Resources are stored in a `World`. Worlds, much like `std::collections`'s `HashSet` and `Vec`, expose operations to insert, read, write, and remove the data they store.
```rust
use bevy_ecs::world::World;
let world = World::default();
```
### Entities
Entities are unique identifiers that correlate to zero or more Components.
```rust
use bevy_ecs::prelude::*;
#[derive(Component)]
struct Position { x: f32, y: f32 }
#[derive(Component)]
struct Velocity { x: f32, y: f32 }
let mut world = World::new();
let entity = world
.spawn((Position { x: 0.0, y: 0.0 }, Velocity { x: 1.0, y: 0.0 }))
.id();
let entity_ref = world.entity(entity);
let position = entity_ref.get::<Position>().unwrap();
let velocity = entity_ref.get::<Velocity>().unwrap();
```
### Systems
Systems are normal Rust functions. Thanks to the Rust type system, Bevy ECS can use function parameter types to determine what data needs to be sent to the system. It also uses this "data access" information to determine what Systems can run in parallel with each other.
```rust
use bevy_ecs::prelude::*;
#[derive(Component)]
struct Position { x: f32, y: f32 }
fn print_position(query: Query<(Entity, &Position)>) {
for (entity, position) in &query {
println!("Entity {} is at position: x {}, y {}", entity, position.x, position.y);
}
}
```
### Resources
Apps often require unique resources, such as asset collections, renderers, audio servers, time, etc. Bevy ECS makes this pattern a first class citizen. `Resource` is a special kind of component that does not belong to any entity. Instead, it is identified uniquely by its type:
```rust
use bevy_ecs::prelude::*;
#[derive(Resource, Default)]
struct Time {
seconds: f32,
}
let mut world = World::new();
world.insert_resource(Time::default());
let time = world.get_resource::<Time>().unwrap();
// You can also access resources from Systems
fn print_time(time: Res<Time>) {
println!("{}", time.seconds);
}
```
### Schedules
Schedules run a set of Systems according to some execution strategy.
Systems can be added to any number of System Sets, which are used to control their scheduling metadata.
The built in "parallel executor" considers dependencies between systems and (by default) run as many of them in parallel as possible. This maximizes performance, while keeping the system execution safe. To control the system ordering, define explicit dependencies between systems and their sets.
## Using Bevy ECS
Bevy ECS should feel very natural for those familiar with Rust syntax:
```rust
use bevy_ecs::prelude::*;
#[derive(Component)]
struct Position { x: f32, y: f32 }
#[derive(Component)]
struct Velocity { x: f32, y: f32 }
// This system moves each entity with a Position and Velocity component
fn movement(mut query: Query<(&mut Position, &Velocity)>) {
for (mut position, velocity) in &mut query {
position.x += velocity.x;
position.y += velocity.y;
}
}
fn main() {
// Create a new empty World to hold our Entities and Components
let mut world = World::new();
// Spawn an entity with Position and Velocity components
world.spawn((
Position { x: 0.0, y: 0.0 },
Velocity { x: 1.0, y: 0.0 },
));
// Create a new Schedule, which defines an execution strategy for Systems
let mut schedule = Schedule::default();
// Add our system to the schedule
schedule.add_systems(movement);
// Run the schedule once. If your app has a "loop", you would run this once per loop
schedule.run(&mut world);
}
```
## Features
### Query Filters
```rust
use bevy_ecs::prelude::*;
#[derive(Component)]
struct Position { x: f32, y: f32 }
#[derive(Component)]
struct Player;
#[derive(Component)]
struct Alive;
// Gets the Position component of all Entities with Player component and without the Alive
// component.
fn system(query: Query<&Position, (With<Player>, Without<Alive>)>) {
for position in &query {
}
}
```
### Change Detection
Bevy ECS tracks _all_ changes to Components and Resources.
Queries can filter for changed Components:
```rust
use bevy_ecs::prelude::*;
#[derive(Component)]
struct Position { x: f32, y: f32 }
#[derive(Component)]
struct Velocity { x: f32, y: f32 }
// Gets the Position component of all Entities whose Velocity has changed since the last run of the System
fn system_changed(query: Query<&Position, Changed<Velocity>>) {
for position in &query {
}
}
// Gets the Position component of all Entities that had a Velocity component added since the last run of the System
fn system_added(query: Query<&Position, Added<Velocity>>) {
for position in &query {
}
}
```
Resources also expose change state:
```rust
use bevy_ecs::prelude::*;
#[derive(Resource)]
struct Time(f32);
// Prints "time changed!" if the Time resource has changed since the last run of the System
fn system(time: Res<Time>) {
if time.is_changed() {
println!("time changed!");
}
}
```
### Component Storage
Bevy ECS supports multiple component storage types.
Components can be stored in:
* **Tables**: Fast and cache friendly iteration, but slower adding and removing of components. This is the default storage type.
* **Sparse Sets**: Fast adding and removing of components, but slower iteration.
Component storage types are configurable, and they default to table storage if the storage is not manually defined.
```rust
use bevy_ecs::prelude::*;
#[derive(Component)]
struct TableStoredComponent;
#[derive(Component)]
#[component(storage = "SparseSet")]
struct SparseStoredComponent;
```
### Component Bundles
Define sets of Components that should be added together.
```rust
use bevy_ecs::prelude::*;
#[derive(Default, Component)]
struct Player;
#[derive(Default, Component)]
struct Position { x: f32, y: f32 }
#[derive(Default, Component)]
struct Velocity { x: f32, y: f32 }
#[derive(Bundle, Default)]
struct PlayerBundle {
player: Player,
position: Position,
velocity: Velocity,
}
let mut world = World::new();
// Spawn a new entity and insert the default PlayerBundle
world.spawn(PlayerBundle::default());
// Bundles play well with Rust's struct update syntax
world.spawn(PlayerBundle {
position: Position { x: 1.0, y: 1.0 },
..Default::default()
});
```
### Events
Events offer a communication channel between one or more systems. Events can be sent using the system parameter `EventWriter` and received with `EventReader`.
```rust
use bevy_ecs::prelude::*;
#[derive(Event)]
struct MyEvent {
message: String,
}
fn writer(mut writer: EventWriter<MyEvent>) {
writer.send(MyEvent {
message: "hello!".to_string(),
});
}
fn reader(mut reader: EventReader<MyEvent>) {
for event in reader.read() {
}
}
```
### Observers
Observers are systems that listen for a "trigger" of a specific `Event`:
```rust
use bevy_ecs::prelude::*;
#[derive(Event)]
struct MyEvent {
message: String
}
let mut world = World::new();
world.add_observer(|trigger: Trigger<MyEvent>| {
println!("{}", trigger.event().message);
});
world.flush();
world.trigger(MyEvent {
message: "hello!".to_string(),
});
```
These differ from `EventReader` and `EventWriter` in that they are "reactive". Rather than happening at a specific point in a schedule, they happen _immediately_ whenever a trigger happens. Triggers can trigger other triggers, and they all will be evaluated at the same time!
Events can also be triggered to target specific entities:
```rust
use bevy_ecs::prelude::*;
#[derive(Event)]
struct Explode;
let mut world = World::new();
let entity = world.spawn_empty().id();
world.add_observer(|trigger: Trigger<Explode>, mut commands: Commands| {
println!("Entity {} goes BOOM!", trigger.target());
commands.entity(trigger.target()).despawn();
});
world.flush();
world.trigger_targets(Explode, entity);
```
[bevy]: https://bevyengine.org/

4
vendor/bevy_ecs/clippy.toml vendored Normal file
View File

@@ -0,0 +1,4 @@
disallowed-methods = [
{ path = "UniqueEntityVec::from_iter", reason = "Use UniqueEntityVec::from_entity_set_iter if possible, it skips validation" },
{ path = "EntitySetIterator::collect::<UniqueEntityVec>", reason = "Use EntitySetIterator::collect_set if possible, it skips validation" },
]

View File

@@ -0,0 +1,120 @@
//! In this example we will simulate a population of entities. In every tick we will:
//! 1. spawn a new entity with a certain possibility
//! 2. age all entities
//! 3. despawn entities with age > 2
//!
//! To demonstrate change detection, there are some console outputs based on changes in
//! the `EntityCounter` resource and updated Age components
#![expect(
clippy::std_instead_of_core,
clippy::print_stdout,
reason = "Examples should not follow this lint"
)]
use bevy_ecs::prelude::*;
use rand::Rng;
use std::ops::Deref;
fn main() {
// Create a new empty World to hold our Entities, Components and Resources
let mut world = World::new();
// Add the counter resource to remember how many entities where spawned
world.insert_resource(EntityCounter { value: 0 });
// Create a new Schedule, which stores systems and controls their relative ordering
let mut schedule = Schedule::default();
// Add systems to the Schedule to execute our app logic
// We can label our systems to force a specific run-order between some of them
schedule.add_systems((
spawn_entities.in_set(SimulationSet::Spawn),
print_counter_when_changed.after(SimulationSet::Spawn),
age_all_entities.in_set(SimulationSet::Age),
remove_old_entities.after(SimulationSet::Age),
print_changed_entities.after(SimulationSet::Age),
));
// Simulate 10 frames in our world
for iteration in 1..=10 {
println!("Simulating frame {iteration}/10");
schedule.run(&mut world);
}
}
// This struct will be used as a Resource keeping track of the total amount of spawned entities
#[derive(Debug, Resource)]
struct EntityCounter {
pub value: i32,
}
// This struct represents a Component and holds the age in frames of the entity it gets assigned to
#[derive(Component, Default, Debug)]
struct Age {
frames: i32,
}
// System sets can be used to group systems and configured to control relative ordering
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
enum SimulationSet {
Spawn,
Age,
}
// This system randomly spawns a new entity in 60% of all frames
// The entity will start with an age of 0 frames
// If an entity gets spawned, we increase the counter in the EntityCounter resource
fn spawn_entities(mut commands: Commands, mut entity_counter: ResMut<EntityCounter>) {
if rand::thread_rng().gen_bool(0.6) {
let entity_id = commands.spawn(Age::default()).id();
println!(" spawning {entity_id:?}");
entity_counter.value += 1;
}
}
// This system prints out changes in our entity collection
// For every entity that just got the Age component added we will print that it's the
// entities first birthday. These entities where spawned in the previous frame.
// For every entity with a changed Age component we will print the new value.
// In this example the Age component is changed in every frame, so we don't actually
// need the `Changed` here, but it is still used for the purpose of demonstration.
fn print_changed_entities(
entity_with_added_component: Query<Entity, Added<Age>>,
entity_with_mutated_component: Query<(Entity, &Age), Changed<Age>>,
) {
for entity in &entity_with_added_component {
println!(" {entity} has it's first birthday!");
}
for (entity, value) in &entity_with_mutated_component {
println!(" {entity} is now {value:?} frames old");
}
}
// This system iterates over all entities and increases their age in every frame
fn age_all_entities(mut entities: Query<&mut Age>) {
for mut age in &mut entities {
age.frames += 1;
}
}
// This system iterates over all entities in every frame and despawns entities older than 2 frames
fn remove_old_entities(mut commands: Commands, entities: Query<(Entity, &Age)>) {
for (entity, age) in &entities {
if age.frames > 2 {
println!(" despawning {entity} due to age > 2");
commands.entity(entity).despawn();
}
}
}
// This system will print the new counter value every time it was changed since
// the last execution of the system.
fn print_counter_when_changed(entity_counter: Res<EntityCounter>) {
if entity_counter.is_changed() {
println!(
" total number of entities spawned: {}",
entity_counter.deref().value
);
}
}

66
vendor/bevy_ecs/examples/events.rs vendored Normal file
View File

@@ -0,0 +1,66 @@
//! In this example a system sends a custom event with a 50/50 chance during any frame.
//! If an event was send, it will be printed by the console in a receiving system.
#![expect(clippy::print_stdout, reason = "Allowed in examples.")]
use bevy_ecs::{event::EventRegistry, prelude::*};
fn main() {
// Create a new empty world and add the event as a resource
let mut world = World::new();
// The event registry is stored as a resource, and allows us to quickly update all events at once.
// This call adds both the registry resource and the events resource into the world.
EventRegistry::register_event::<MyEvent>(&mut world);
// Create a schedule to store our systems
let mut schedule = Schedule::default();
// Events need to be updated in every frame in order to clear our buffers.
// This update should happen before we use the events.
// Here, we use system sets to control the ordering.
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
pub struct FlushEvents;
schedule.add_systems(bevy_ecs::event::event_update_system.in_set(FlushEvents));
// Add systems sending and receiving events after the events are flushed.
schedule.add_systems((
sending_system.after(FlushEvents),
receiving_system.after(sending_system),
));
// Simulate 10 frames of our world
for iteration in 1..=10 {
println!("Simulating frame {iteration}/10");
schedule.run(&mut world);
}
}
// This is our event that we will send and receive in systems
#[derive(Event)]
struct MyEvent {
pub message: String,
pub random_value: f32,
}
// In every frame we will send an event with a 50/50 chance
fn sending_system(mut event_writer: EventWriter<MyEvent>) {
let random_value: f32 = rand::random();
if random_value > 0.5 {
event_writer.write(MyEvent {
message: "A random event with value > 0.5".to_string(),
random_value,
});
}
}
// This system listens for events of the type MyEvent
// If an event is received it will be printed to the console
fn receiving_system(mut event_reader: EventReader<MyEvent>) {
for my_event in event_reader.read() {
println!(
" Received message {}, with random value of {}",
my_event.message, my_event.random_value
);
}
}

48
vendor/bevy_ecs/examples/resources.rs vendored Normal file
View File

@@ -0,0 +1,48 @@
//! In this example we add a counter resource and increase its value in one system,
//! while a different system prints the current count to the console.
#![expect(
clippy::std_instead_of_core,
clippy::print_stdout,
reason = "Examples should not follow this lint"
)]
use bevy_ecs::prelude::*;
use rand::Rng;
use std::ops::Deref;
fn main() {
// Create a world
let mut world = World::new();
// Add the counter resource
world.insert_resource(Counter { value: 0 });
// Create a schedule
let mut schedule = Schedule::default();
// Add systems to increase the counter and to print out the current value
schedule.add_systems((increase_counter, print_counter).chain());
for iteration in 1..=10 {
println!("Simulating frame {iteration}/10");
schedule.run(&mut world);
}
}
// Counter resource to be increased and read by systems
#[derive(Debug, Resource)]
struct Counter {
pub value: i32,
}
fn increase_counter(mut counter: ResMut<Counter>) {
if rand::thread_rng().gen_bool(0.5) {
counter.value += 1;
println!(" Increased counter value");
}
}
fn print_counter(counter: Res<Counter>) {
println!(" {:?}", counter.deref());
}

1041
vendor/bevy_ecs/src/archetype.rs vendored Normal file

File diff suppressed because it is too large Load Diff

107
vendor/bevy_ecs/src/batching.rs vendored Normal file
View File

@@ -0,0 +1,107 @@
//! Types for controlling batching behavior during parallel processing.
use core::ops::Range;
/// Dictates how a parallel operation chunks up large quantities
/// during iteration.
///
/// A parallel query will chunk up large tables and archetypes into
/// chunks of at most a certain batch size. Similarly, a parallel event
/// reader will chunk up the remaining events.
///
/// By default, this batch size is automatically determined by dividing
/// the size of the largest matched archetype by the number
/// of threads (rounded up). This attempts to minimize the overhead of scheduling
/// tasks onto multiple threads, but assumes each entity has roughly the
/// same amount of work to be done, which may not hold true in every
/// workload.
///
/// See [`Query::par_iter`], [`EventReader::par_read`] for more information.
///
/// [`Query::par_iter`]: crate::system::Query::par_iter
/// [`EventReader::par_read`]: crate::event::EventReader::par_read
#[derive(Clone, Debug)]
pub struct BatchingStrategy {
/// The upper and lower limits for a batch of entities.
///
/// Setting the bounds to the same value will result in a fixed
/// batch size.
///
/// Defaults to `[1, usize::MAX]`.
pub batch_size_limits: Range<usize>,
/// The number of batches per thread in the [`ComputeTaskPool`].
/// Increasing this value will decrease the batch size, which may
/// increase the scheduling overhead for the iteration.
///
/// Defaults to 1.
///
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
pub batches_per_thread: usize,
}
impl Default for BatchingStrategy {
fn default() -> Self {
Self::new()
}
}
impl BatchingStrategy {
/// Creates a new unconstrained default batching strategy.
pub const fn new() -> Self {
Self {
batch_size_limits: 1..usize::MAX,
batches_per_thread: 1,
}
}
/// Declares a batching strategy with a fixed batch size.
pub const fn fixed(batch_size: usize) -> Self {
Self {
batch_size_limits: batch_size..batch_size,
batches_per_thread: 1,
}
}
/// Configures the minimum allowed batch size of this instance.
pub const fn min_batch_size(mut self, batch_size: usize) -> Self {
self.batch_size_limits.start = batch_size;
self
}
/// Configures the maximum allowed batch size of this instance.
pub const fn max_batch_size(mut self, batch_size: usize) -> Self {
self.batch_size_limits.end = batch_size;
self
}
/// Configures the number of batches to assign to each thread for this instance.
pub fn batches_per_thread(mut self, batches_per_thread: usize) -> Self {
assert!(
batches_per_thread > 0,
"The number of batches per thread must be non-zero."
);
self.batches_per_thread = batches_per_thread;
self
}
/// Calculate the batch size according to the given thread count and max item count.
/// The count is provided as a closure so that it can be calculated only if needed.
///
/// # Panics
///
/// Panics if `thread_count` is 0.
#[inline]
pub fn calc_batch_size(&self, max_items: impl FnOnce() -> usize, thread_count: usize) -> usize {
if self.batch_size_limits.is_empty() {
return self.batch_size_limits.start;
}
assert!(
thread_count > 0,
"Attempted to run parallel iteration with an empty TaskPool"
);
let batches = thread_count * self.batches_per_thread;
// Round up to the nearest batch size.
let batch_size = max_items().div_ceil(batches);
batch_size.clamp(self.batch_size_limits.start, self.batch_size_limits.end)
}
}

1989
vendor/bevy_ecs/src/bundle.rs vendored Normal file

File diff suppressed because it is too large Load Diff

1888
vendor/bevy_ecs/src/change_detection.rs vendored Normal file

File diff suppressed because it is too large Load Diff

3178
vendor/bevy_ecs/src/component.rs vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

547
vendor/bevy_ecs/src/entity/entity_set.rs vendored Normal file
View File

@@ -0,0 +1,547 @@
use alloc::{
boxed::Box,
collections::{btree_map, btree_set},
rc::Rc,
};
use bevy_platform::collections::HashSet;
use core::{
array,
fmt::{Debug, Formatter},
hash::{BuildHasher, Hash},
iter::{self, FusedIterator},
option, result,
};
use super::{Entity, UniqueEntityEquivalentSlice};
use bevy_platform::sync::Arc;
/// A trait for types that contain an [`Entity`].
///
/// This trait behaves similarly to `Borrow<Entity>`, but yielding `Entity` directly.
///
/// It should only be implemented when:
/// - Retrieving the [`Entity`] is a simple operation.
/// - The [`Entity`] contained by the type is unambiguous.
pub trait ContainsEntity {
/// Returns the contained entity.
fn entity(&self) -> Entity;
}
/// A trait for types that represent an [`Entity`].
///
/// Comparison trait behavior between an [`EntityEquivalent`] type and its underlying entity will match.
/// This property includes [`PartialEq`], [`Eq`], [`PartialOrd`], [`Ord`] and [`Hash`],
/// and remains even after [`Clone`] and/or [`Borrow`] calls.
///
/// # Safety
/// Any [`PartialEq`], [`Eq`], [`PartialOrd`], and [`Ord`] impls must evaluate the same for `Self` and
/// its underlying entity.
/// `x.entity() == y.entity()` must be equivalent to `x == y`.
///
/// The above equivalence must also hold through and between calls to any [`Clone`] and
/// [`Borrow`]/[`BorrowMut`] impls in place of [`entity()`].
///
/// The result of [`entity()`] must be unaffected by any interior mutability.
///
/// The aforementioned properties imply determinism in both [`entity()`] calls
/// and comparison trait behavior.
///
/// All [`Hash`] impls except that for [`Entity`] must delegate to the [`Hash`] impl of
/// another [`EntityEquivalent`] type. All conversions to the delegatee within the [`Hash`] impl must
/// follow [`entity()`] equivalence.
///
/// It should be noted that [`Hash`] is *not* a comparison trait, and with [`Hash::hash`] being forcibly
/// generic over all [`Hasher`]s, **cannot** guarantee determinism or uniqueness of any final hash values
/// on its own.
/// To obtain hash values forming the same total order as [`Entity`], any [`Hasher`] used must be
/// deterministic and concerning [`Entity`], collisionless.
/// Standard library hash collections handle collisions with an [`Eq`] fallback, but do not account for
/// determinism when [`BuildHasher`] is unspecified,.
///
/// [`Hash`]: core::hash::Hash
/// [`Hasher`]: core::hash::Hasher
/// [`Borrow`]: core::borrow::Borrow
/// [`BorrowMut`]: core::borrow::BorrowMut
/// [`entity()`]: ContainsEntity::entity
pub unsafe trait EntityEquivalent: ContainsEntity + Eq {}
impl ContainsEntity for Entity {
fn entity(&self) -> Entity {
*self
}
}
// SAFETY:
// The trait implementations of Entity are correct and deterministic.
unsafe impl EntityEquivalent for Entity {}
impl<T: ContainsEntity> ContainsEntity for &T {
fn entity(&self) -> Entity {
(**self).entity()
}
}
// SAFETY:
// `&T` delegates `PartialEq`, `Eq`, `PartialOrd`, `Ord`, and `Hash` to T.
// `Clone` and `Borrow` maintain equality.
// `&T` is `Freeze`.
unsafe impl<T: EntityEquivalent> EntityEquivalent for &T {}
impl<T: ContainsEntity> ContainsEntity for &mut T {
fn entity(&self) -> Entity {
(**self).entity()
}
}
// SAFETY:
// `&mut T` delegates `PartialEq`, `Eq`, `PartialOrd`, `Ord`, and `Hash` to T.
// `Borrow` and `BorrowMut` maintain equality.
// `&mut T` is `Freeze`.
unsafe impl<T: EntityEquivalent> EntityEquivalent for &mut T {}
impl<T: ContainsEntity> ContainsEntity for Box<T> {
fn entity(&self) -> Entity {
(**self).entity()
}
}
// SAFETY:
// `Box<T>` delegates `PartialEq`, `Eq`, `PartialOrd`, `Ord`, and `Hash` to T.
// `Clone`, `Borrow` and `BorrowMut` maintain equality.
// `Box<T>` is `Freeze`.
unsafe impl<T: EntityEquivalent> EntityEquivalent for Box<T> {}
impl<T: ContainsEntity> ContainsEntity for Rc<T> {
fn entity(&self) -> Entity {
(**self).entity()
}
}
// SAFETY:
// `Rc<T>` delegates `PartialEq`, `Eq`, `PartialOrd`, `Ord`, and `Hash` to T.
// `Clone`, `Borrow` and `BorrowMut` maintain equality.
// `Rc<T>` is `Freeze`.
unsafe impl<T: EntityEquivalent> EntityEquivalent for Rc<T> {}
impl<T: ContainsEntity> ContainsEntity for Arc<T> {
fn entity(&self) -> Entity {
(**self).entity()
}
}
// SAFETY:
// `Arc<T>` delegates `PartialEq`, `Eq`, `PartialOrd`, `Ord`, and `Hash` to T.
// `Clone`, `Borrow` and `BorrowMut` maintain equality.
// `Arc<T>` is `Freeze`.
unsafe impl<T: EntityEquivalent> EntityEquivalent for Arc<T> {}
/// A set of unique entities.
///
/// Any element returned by [`Self::IntoIter`] will compare non-equal to every other element in the iterator.
/// As a consequence, [`into_iter()`] on `EntitySet` will always produce another `EntitySet`.
///
/// Implementing this trait allows for unique query iteration over a list of entities.
/// See [`iter_many_unique`] and [`iter_many_unique_mut`]
///
/// Note that there is no guarantee of the [`IntoIterator`] impl being deterministic,
/// it might return different iterators when called multiple times.
/// Neither is there a guarantee that the comparison trait impls of `EntitySet` match that
/// of the respective [`EntitySetIterator`] (or of a [`Vec`] collected from its elements)
///
/// [`Self::IntoIter`]: IntoIterator::IntoIter
/// [`into_iter()`]: IntoIterator::into_iter
/// [`iter_many_unique`]: crate::system::Query::iter_many_unique
/// [`iter_many_unique_mut`]: crate::system::Query::iter_many_unique_mut
/// [`Vec`]: alloc::vec::Vec
pub trait EntitySet: IntoIterator<IntoIter: EntitySetIterator> {}
impl<T: IntoIterator<IntoIter: EntitySetIterator>> EntitySet for T {}
/// An iterator over a set of unique entities.
///
/// Every `EntitySetIterator` is also [`EntitySet`].
///
/// # Safety
///
/// `x != y` must hold for any 2 elements returned by the iterator.
/// This is always true for iterators that cannot return more than one element.
pub unsafe trait EntitySetIterator: Iterator<Item: EntityEquivalent> {
/// Transforms an `EntitySetIterator` into a collection.
///
/// This is a specialized form of [`collect`], for collections which benefit from the uniqueness guarantee.
/// When present, this should always be preferred over [`collect`].
///
/// [`collect`]: Iterator::collect
// FIXME: When subtrait item shadowing stabilizes, this should be renamed and shadow `Iterator::collect`
fn collect_set<B: FromEntitySetIterator<Self::Item>>(self) -> B
where
Self: Sized,
{
FromEntitySetIterator::from_entity_set_iter(self)
}
}
// SAFETY:
// A correct `BTreeMap` contains only unique keys.
// EntityEquivalent guarantees a trustworthy Ord impl for T, and thus a correct `BTreeMap`.
unsafe impl<K: EntityEquivalent, V> EntitySetIterator for btree_map::Keys<'_, K, V> {}
// SAFETY:
// A correct `BTreeMap` contains only unique keys.
// EntityEquivalent guarantees a trustworthy Ord impl for T, and thus a correct `BTreeMap`.
unsafe impl<K: EntityEquivalent, V> EntitySetIterator for btree_map::IntoKeys<K, V> {}
// SAFETY:
// A correct `BTreeSet` contains only unique elements.
// EntityEquivalent guarantees a trustworthy Ord impl for T, and thus a correct `BTreeSet`.
// The sub-range maintains uniqueness.
unsafe impl<T: EntityEquivalent> EntitySetIterator for btree_set::Range<'_, T> {}
// SAFETY:
// A correct `BTreeSet` contains only unique elements.
// EntityEquivalent guarantees a trustworthy Ord impl for T, and thus a correct `BTreeSet`.
// The "intersection" operation maintains uniqueness.
unsafe impl<T: EntityEquivalent + Ord> EntitySetIterator for btree_set::Intersection<'_, T> {}
// SAFETY:
// A correct `BTreeSet` contains only unique elements.
// EntityEquivalent guarantees a trustworthy Ord impl for T, and thus a correct `BTreeSet`.
// The "union" operation maintains uniqueness.
unsafe impl<T: EntityEquivalent + Ord> EntitySetIterator for btree_set::Union<'_, T> {}
// SAFETY:
// A correct `BTreeSet` contains only unique elements.
// EntityEquivalent guarantees a trustworthy Ord impl for T, and thus a correct `BTreeSet`.
// The "difference" operation maintains uniqueness.
unsafe impl<T: EntityEquivalent + Ord> EntitySetIterator for btree_set::Difference<'_, T> {}
// SAFETY:
// A correct `BTreeSet` contains only unique elements.
// EntityEquivalent guarantees a trustworthy Ord impl for T, and thus a correct `BTreeSet`.
// The "symmetric difference" operation maintains uniqueness.
unsafe impl<T: EntityEquivalent + Ord> EntitySetIterator for btree_set::SymmetricDifference<'_, T> {}
// SAFETY:
// A correct `BTreeSet` contains only unique elements.
// EntityEquivalent guarantees a trustworthy Ord impl for T, and thus a correct `BTreeSet`.
unsafe impl<T: EntityEquivalent> EntitySetIterator for btree_set::Iter<'_, T> {}
// SAFETY:
// A correct `BTreeSet` contains only unique elements.
// EntityEquivalent guarantees a trustworthy Ord impl for T, and thus a correct `BTreeSet`.
unsafe impl<T: EntityEquivalent> EntitySetIterator for btree_set::IntoIter<T> {}
// SAFETY: This iterator only returns one element.
unsafe impl<T: EntityEquivalent> EntitySetIterator for option::Iter<'_, T> {}
// SAFETY: This iterator only returns one element.
// unsafe impl<T: EntityEquivalent> EntitySetIterator for option::IterMut<'_, T> {}
// SAFETY: This iterator only returns one element.
unsafe impl<T: EntityEquivalent> EntitySetIterator for option::IntoIter<T> {}
// SAFETY: This iterator only returns one element.
unsafe impl<T: EntityEquivalent> EntitySetIterator for result::Iter<'_, T> {}
// SAFETY: This iterator only returns one element.
// unsafe impl<T: EntityEquivalent> EntitySetIterator for result::IterMut<'_, T> {}
// SAFETY: This iterator only returns one element.
unsafe impl<T: EntityEquivalent> EntitySetIterator for result::IntoIter<T> {}
// SAFETY: This iterator only returns one element.
unsafe impl<T: EntityEquivalent> EntitySetIterator for array::IntoIter<T, 1> {}
// SAFETY: This iterator does not return any elements.
unsafe impl<T: EntityEquivalent> EntitySetIterator for array::IntoIter<T, 0> {}
// SAFETY: This iterator only returns one element.
unsafe impl<T: EntityEquivalent, F: FnOnce() -> T> EntitySetIterator for iter::OnceWith<F> {}
// SAFETY: This iterator only returns one element.
unsafe impl<T: EntityEquivalent> EntitySetIterator for iter::Once<T> {}
// SAFETY: This iterator does not return any elements.
unsafe impl<T: EntityEquivalent> EntitySetIterator for iter::Empty<T> {}
// SAFETY: Taking a mutable reference of an iterator has no effect on its elements.
unsafe impl<I: EntitySetIterator + ?Sized> EntitySetIterator for &mut I {}
// SAFETY: Boxing an iterator has no effect on its elements.
unsafe impl<I: EntitySetIterator + ?Sized> EntitySetIterator for Box<I> {}
// SAFETY: EntityEquivalent ensures that Copy does not affect equality, via its restrictions on Clone.
unsafe impl<'a, T: 'a + EntityEquivalent + Copy, I: EntitySetIterator<Item = &'a T>>
EntitySetIterator for iter::Copied<I>
{
}
// SAFETY: EntityEquivalent ensures that Clone does not affect equality.
unsafe impl<'a, T: 'a + EntityEquivalent + Clone, I: EntitySetIterator<Item = &'a T>>
EntitySetIterator for iter::Cloned<I>
{
}
// SAFETY: Discarding elements maintains uniqueness.
unsafe impl<I: EntitySetIterator, P: FnMut(&<I as Iterator>::Item) -> bool> EntitySetIterator
for iter::Filter<I, P>
{
}
// SAFETY: Yielding only `None` after yielding it once can only remove elements, which maintains uniqueness.
unsafe impl<I: EntitySetIterator> EntitySetIterator for iter::Fuse<I> {}
// SAFETY:
// Obtaining immutable references the elements of an iterator does not affect uniqueness.
// EntityEquivalent ensures the lack of interior mutability.
unsafe impl<I: EntitySetIterator, F: FnMut(&<I as Iterator>::Item)> EntitySetIterator
for iter::Inspect<I, F>
{
}
// SAFETY: Reversing an iterator does not affect uniqueness.
unsafe impl<I: DoubleEndedIterator + EntitySetIterator> EntitySetIterator for iter::Rev<I> {}
// SAFETY: Discarding elements maintains uniqueness.
unsafe impl<I: EntitySetIterator> EntitySetIterator for iter::Skip<I> {}
// SAFETY: Discarding elements maintains uniqueness.
unsafe impl<I: EntitySetIterator, P: FnMut(&<I as Iterator>::Item) -> bool> EntitySetIterator
for iter::SkipWhile<I, P>
{
}
// SAFETY: Discarding elements maintains uniqueness.
unsafe impl<I: EntitySetIterator> EntitySetIterator for iter::Take<I> {}
// SAFETY: Discarding elements maintains uniqueness.
unsafe impl<I: EntitySetIterator, P: FnMut(&<I as Iterator>::Item) -> bool> EntitySetIterator
for iter::TakeWhile<I, P>
{
}
// SAFETY: Discarding elements maintains uniqueness.
unsafe impl<I: EntitySetIterator> EntitySetIterator for iter::StepBy<I> {}
/// Conversion from an `EntitySetIterator`.
///
/// Some collections, while they can be constructed from plain iterators,
/// benefit strongly from the additional uniqueness guarantee [`EntitySetIterator`] offers.
/// Mirroring [`Iterator::collect`]/[`FromIterator::from_iter`], [`EntitySetIterator::collect_set`] and
/// `FromEntitySetIterator::from_entity_set_iter` can be used for construction.
///
/// See also: [`EntitySet`].
// FIXME: When subtrait item shadowing stabilizes, this should be renamed and shadow `FromIterator::from_iter`
pub trait FromEntitySetIterator<A: EntityEquivalent>: FromIterator<A> {
/// Creates a value from an [`EntitySetIterator`].
fn from_entity_set_iter<T: EntitySet<Item = A>>(set_iter: T) -> Self;
}
impl<T: EntityEquivalent + Hash, S: BuildHasher + Default> FromEntitySetIterator<T>
for HashSet<T, S>
{
fn from_entity_set_iter<I: EntitySet<Item = T>>(set_iter: I) -> Self {
let iter = set_iter.into_iter();
let set = HashSet::<T, S>::with_capacity_and_hasher(iter.size_hint().0, S::default());
iter.fold(set, |mut set, e| {
// SAFETY: Every element in self is unique.
unsafe {
set.insert_unique_unchecked(e);
}
set
})
}
}
/// An iterator that yields unique entities.
///
/// This wrapper can provide an [`EntitySetIterator`] implementation when an instance of `I` is known to uphold uniqueness.
pub struct UniqueEntityIter<I: Iterator<Item: EntityEquivalent>> {
iter: I,
}
impl<I: EntitySetIterator> UniqueEntityIter<I> {
/// Constructs a `UniqueEntityIter` from an [`EntitySetIterator`].
pub fn from_entity_set_iterator<S>(iter: I) -> Self {
Self { iter }
}
}
impl<I: Iterator<Item: EntityEquivalent>> UniqueEntityIter<I> {
/// Constructs a [`UniqueEntityIter`] from an iterator unsafely.
///
/// # Safety
/// `iter` must only yield unique elements.
/// As in, the resulting iterator must adhere to the safety contract of [`EntitySetIterator`].
pub unsafe fn from_iterator_unchecked(iter: I) -> Self {
Self { iter }
}
/// Returns the inner `I`.
pub fn into_inner(self) -> I {
self.iter
}
/// Returns a reference to the inner `I`.
pub fn as_inner(&self) -> &I {
&self.iter
}
/// Returns a mutable reference to the inner `I`.
///
/// # Safety
///
/// `self` must always contain an iterator that yields unique elements,
/// even while this reference is live.
pub unsafe fn as_mut_inner(&mut self) -> &mut I {
&mut self.iter
}
}
impl<I: Iterator<Item: EntityEquivalent>> Iterator for UniqueEntityIter<I> {
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<I: ExactSizeIterator<Item: EntityEquivalent>> ExactSizeIterator for UniqueEntityIter<I> {}
impl<I: DoubleEndedIterator<Item: EntityEquivalent>> DoubleEndedIterator for UniqueEntityIter<I> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back()
}
}
impl<I: FusedIterator<Item: EntityEquivalent>> FusedIterator for UniqueEntityIter<I> {}
// SAFETY: The underlying iterator is ensured to only return unique elements by its construction.
unsafe impl<I: Iterator<Item: EntityEquivalent>> EntitySetIterator for UniqueEntityIter<I> {}
impl<T, I: Iterator<Item: EntityEquivalent> + AsRef<[T]>> AsRef<[T]> for UniqueEntityIter<I> {
fn as_ref(&self) -> &[T] {
self.iter.as_ref()
}
}
impl<T: EntityEquivalent, I: Iterator<Item: EntityEquivalent> + AsRef<[T]>>
AsRef<UniqueEntityEquivalentSlice<T>> for UniqueEntityIter<I>
{
fn as_ref(&self) -> &UniqueEntityEquivalentSlice<T> {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(self.iter.as_ref()) }
}
}
impl<T: EntityEquivalent, I: Iterator<Item: EntityEquivalent> + AsMut<[T]>>
AsMut<UniqueEntityEquivalentSlice<T>> for UniqueEntityIter<I>
{
fn as_mut(&mut self) -> &mut UniqueEntityEquivalentSlice<T> {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked_mut(self.iter.as_mut()) }
}
}
// Default does not guarantee uniqueness, meaning `I` needs to be EntitySetIterator.
impl<I: EntitySetIterator + Default> Default for UniqueEntityIter<I> {
fn default() -> Self {
Self {
iter: Default::default(),
}
}
}
// Clone does not guarantee to maintain uniqueness, meaning `I` needs to be EntitySetIterator.
impl<I: EntitySetIterator + Clone> Clone for UniqueEntityIter<I> {
fn clone(&self) -> Self {
Self {
iter: self.iter.clone(),
}
}
}
impl<I: Iterator<Item: EntityEquivalent> + Debug> Debug for UniqueEntityIter<I> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("UniqueEntityIter")
.field("iter", &self.iter)
.finish()
}
}
#[cfg(test)]
mod tests {
use alloc::{vec, vec::Vec};
use crate::prelude::{Schedule, World};
use crate::component::Component;
use crate::entity::Entity;
use crate::query::{QueryState, With};
use crate::system::Query;
use crate::world::Mut;
use super::UniqueEntityIter;
#[derive(Component, Clone)]
pub struct Thing;
#[expect(
clippy::iter_skip_zero,
reason = "The `skip(0)` is used to ensure that the `Skip` iterator implements `EntitySet`, which is needed to pass the iterator as the `entities` parameter."
)]
#[test]
fn preserving_uniqueness() {
let mut world = World::new();
let mut query = QueryState::<&mut Thing>::new(&mut world);
let spawn_batch: Vec<Entity> = world.spawn_batch(vec![Thing; 1000]).collect();
// SAFETY: SpawnBatchIter is `EntitySetIterator`,
let mut unique_entity_iter =
unsafe { UniqueEntityIter::from_iterator_unchecked(spawn_batch.iter()) };
let entity_set = unique_entity_iter
.by_ref()
.filter(|_| true)
.fuse()
.inspect(|_| ())
.rev()
.skip(0)
.skip_while(|_| false)
.take(1000)
.take_while(|_| true)
.step_by(2)
.cloned();
// With `iter_many_mut` collecting is not possible, because you need to drop each `Mut`/`&mut` before the next is retrieved.
let _results: Vec<Mut<Thing>> =
query.iter_many_unique_mut(&mut world, entity_set).collect();
}
#[test]
fn nesting_queries() {
let mut world = World::new();
world.spawn_batch(vec![Thing; 1000]);
pub fn system(
mut thing_entities: Query<Entity, With<Thing>>,
mut things: Query<&mut Thing>,
) {
things.iter_many_unique(thing_entities.iter());
things.iter_many_unique_mut(thing_entities.iter_mut());
}
let mut schedule = Schedule::default();
schedule.add_systems(system);
schedule.run(&mut world);
}
}

77
vendor/bevy_ecs/src/entity/hash.rs vendored Normal file
View File

@@ -0,0 +1,77 @@
use core::hash::{BuildHasher, Hasher};
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
/// A [`BuildHasher`] that results in a [`EntityHasher`].
#[derive(Debug, Default, Clone)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Default, Clone))]
pub struct EntityHash;
impl BuildHasher for EntityHash {
type Hasher = EntityHasher;
fn build_hasher(&self) -> Self::Hasher {
Self::Hasher::default()
}
}
/// A very fast hash that is only designed to work on generational indices
/// like [`Entity`](super::Entity). It will panic if attempting to hash a type containing
/// non-u64 fields.
///
/// This is heavily optimized for typical cases, where you have mostly live
/// entities, and works particularly well for contiguous indices.
///
/// If you have an unusual case -- say all your indices are multiples of 256
/// or most of the entities are dead generations -- then you might want also to
/// try [`DefaultHasher`](bevy_platform::hash::DefaultHasher) for a slower hash
/// computation but fewer lookup conflicts.
#[derive(Debug, Default)]
pub struct EntityHasher {
hash: u64,
}
impl Hasher for EntityHasher {
#[inline]
fn finish(&self) -> u64 {
self.hash
}
fn write(&mut self, _bytes: &[u8]) {
panic!("EntityHasher can only hash u64 fields.");
}
#[inline]
fn write_u64(&mut self, bits: u64) {
// SwissTable (and thus `hashbrown`) cares about two things from the hash:
// - H1: low bits (masked by `2ⁿ-1`) to pick the slot in which to store the item
// - H2: high 7 bits are used to SIMD optimize hash collision probing
// For more see <https://abseil.io/about/design/swisstables#metadata-layout>
// This hash function assumes that the entity ids are still well-distributed,
// so for H1 leaves the entity id alone in the low bits so that id locality
// will also give memory locality for things spawned together.
// For H2, take advantage of the fact that while multiplication doesn't
// spread entropy to the low bits, it's incredibly good at spreading it
// upward, which is exactly where we need it the most.
// While this does include the generation in the output, it doesn't do so
// *usefully*. H1 won't care until you have over 3 billion entities in
// the table, and H2 won't care until something hits generation 33 million.
// Thus the comment suggesting that this is best for live entities,
// where there won't be generation conflicts where it would matter.
// The high 32 bits of this are ⅟φ for Fibonacci hashing. That works
// particularly well for hashing for the same reason as described in
// <https://extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences/>
// It loses no information because it has a modular inverse.
// (Specifically, `0x144c_bc89_u32 * 0x9e37_79b9_u32 == 1`.)
//
// The low 32 bits make that part of the just product a pass-through.
const UPPER_PHI: u64 = 0x9e37_79b9_0000_0001;
// This is `(MAGIC * index + generation) << 32 + index`, in a single instruction.
self.hash = bits.wrapping_mul(UPPER_PHI);
}
}

272
vendor/bevy_ecs/src/entity/hash_map.rs vendored Normal file
View File

@@ -0,0 +1,272 @@
//! Contains the [`EntityHashMap`] type, a [`HashMap`] pre-configured to use [`EntityHash`] hashing.
//!
//! This module is a lightweight wrapper around Bevy's [`HashMap`] that is more performant for [`Entity`] keys.
use core::{
fmt::{self, Debug, Formatter},
iter::FusedIterator,
marker::PhantomData,
ops::{Deref, DerefMut, Index},
};
use bevy_platform::collections::hash_map::{self, HashMap};
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::Reflect;
use super::{Entity, EntityEquivalent, EntityHash, EntitySetIterator};
/// A [`HashMap`] pre-configured to use [`EntityHash`] hashing.
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "serialize", derive(serde::Deserialize, serde::Serialize))]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EntityHashMap<V>(pub(crate) HashMap<Entity, V, EntityHash>);
impl<V> EntityHashMap<V> {
/// Creates an empty `EntityHashMap`.
///
/// Equivalent to [`HashMap::with_hasher(EntityHash)`].
///
/// [`HashMap::with_hasher(EntityHash)`]: HashMap::with_hasher
pub const fn new() -> Self {
Self(HashMap::with_hasher(EntityHash))
}
/// Creates an empty `EntityHashMap` with the specified capacity.
///
/// Equivalent to [`HashMap::with_capacity_and_hasher(n, EntityHash)`].
///
/// [`HashMap:with_capacity_and_hasher(n, EntityHash)`]: HashMap::with_capacity_and_hasher
pub fn with_capacity(n: usize) -> Self {
Self(HashMap::with_capacity_and_hasher(n, EntityHash))
}
/// Returns the inner [`HashMap`].
pub fn into_inner(self) -> HashMap<Entity, V, EntityHash> {
self.0
}
/// An iterator visiting all keys in arbitrary order.
/// The iterator element type is `&'a Entity`.
///
/// Equivalent to [`HashMap::keys`].
pub fn keys(&self) -> Keys<'_, V> {
Keys(self.0.keys(), PhantomData)
}
/// Creates a consuming iterator visiting all the keys in arbitrary order.
/// The map cannot be used after calling this.
/// The iterator element type is [`Entity`].
///
/// Equivalent to [`HashMap::into_keys`].
pub fn into_keys(self) -> IntoKeys<V> {
IntoKeys(self.0.into_keys(), PhantomData)
}
}
impl<V> Default for EntityHashMap<V> {
fn default() -> Self {
Self(Default::default())
}
}
impl<V> Deref for EntityHashMap<V> {
type Target = HashMap<Entity, V, EntityHash>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<V> DerefMut for EntityHashMap<V> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<'a, V: Copy> Extend<&'a (Entity, V)> for EntityHashMap<V> {
fn extend<T: IntoIterator<Item = &'a (Entity, V)>>(&mut self, iter: T) {
self.0.extend(iter);
}
}
impl<'a, V: Copy> Extend<(&'a Entity, &'a V)> for EntityHashMap<V> {
fn extend<T: IntoIterator<Item = (&'a Entity, &'a V)>>(&mut self, iter: T) {
self.0.extend(iter);
}
}
impl<V> Extend<(Entity, V)> for EntityHashMap<V> {
fn extend<T: IntoIterator<Item = (Entity, V)>>(&mut self, iter: T) {
self.0.extend(iter);
}
}
impl<V, const N: usize> From<[(Entity, V); N]> for EntityHashMap<V> {
fn from(value: [(Entity, V); N]) -> Self {
Self(HashMap::from_iter(value))
}
}
impl<V> FromIterator<(Entity, V)> for EntityHashMap<V> {
fn from_iter<I: IntoIterator<Item = (Entity, V)>>(iterable: I) -> Self {
Self(HashMap::from_iter(iterable))
}
}
impl<V, Q: EntityEquivalent + ?Sized> Index<&Q> for EntityHashMap<V> {
type Output = V;
fn index(&self, key: &Q) -> &V {
self.0.index(&key.entity())
}
}
impl<'a, V> IntoIterator for &'a EntityHashMap<V> {
type Item = (&'a Entity, &'a V);
type IntoIter = hash_map::Iter<'a, Entity, V>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<'a, V> IntoIterator for &'a mut EntityHashMap<V> {
type Item = (&'a Entity, &'a mut V);
type IntoIter = hash_map::IterMut<'a, Entity, V>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter_mut()
}
}
impl<V> IntoIterator for EntityHashMap<V> {
type Item = (Entity, V);
type IntoIter = hash_map::IntoIter<Entity, V>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
/// An iterator over the keys of a [`EntityHashMap`] in arbitrary order.
/// The iterator element type is `&'a Entity`.
///
/// This struct is created by the [`keys`] method on [`EntityHashMap`]. See its documentation for more.
///
/// [`keys`]: EntityHashMap::keys
pub struct Keys<'a, V, S = EntityHash>(hash_map::Keys<'a, Entity, V>, PhantomData<S>);
impl<'a, V> Keys<'a, V> {
/// Returns the inner [`Keys`](hash_map::Keys).
pub fn into_inner(self) -> hash_map::Keys<'a, Entity, V> {
self.0
}
}
impl<'a, V> Deref for Keys<'a, V> {
type Target = hash_map::Keys<'a, Entity, V>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a, V> Iterator for Keys<'a, V> {
type Item = &'a Entity;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl<V> ExactSizeIterator for Keys<'_, V> {}
impl<V> FusedIterator for Keys<'_, V> {}
impl<V> Clone for Keys<'_, V> {
fn clone(&self) -> Self {
Self(self.0.clone(), PhantomData)
}
}
impl<V: Debug> Debug for Keys<'_, V> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("Keys").field(&self.0).field(&self.1).finish()
}
}
impl<V> Default for Keys<'_, V> {
fn default() -> Self {
Self(Default::default(), PhantomData)
}
}
// SAFETY: Keys stems from a correctly behaving `HashMap<Entity, V, EntityHash>`.
unsafe impl<V> EntitySetIterator for Keys<'_, V> {}
/// An owning iterator over the keys of a [`EntityHashMap`] in arbitrary order.
/// The iterator element type is [`Entity`].
///
/// This struct is created by the [`into_keys`] method on [`EntityHashMap`].
/// See its documentation for more.
/// The map cannot be used after calling that method.
///
/// [`into_keys`]: EntityHashMap::into_keys
pub struct IntoKeys<V, S = EntityHash>(hash_map::IntoKeys<Entity, V>, PhantomData<S>);
impl<V> IntoKeys<V> {
/// Returns the inner [`IntoKeys`](hash_map::IntoKeys).
pub fn into_inner(self) -> hash_map::IntoKeys<Entity, V> {
self.0
}
}
impl<V> Deref for IntoKeys<V> {
type Target = hash_map::IntoKeys<Entity, V>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<V> Iterator for IntoKeys<V> {
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl<V> ExactSizeIterator for IntoKeys<V> {}
impl<V> FusedIterator for IntoKeys<V> {}
impl<V: Debug> Debug for IntoKeys<V> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("IntoKeys")
.field(&self.0)
.field(&self.1)
.finish()
}
}
impl<V> Default for IntoKeys<V> {
fn default() -> Self {
Self(Default::default(), PhantomData)
}
}
// SAFETY: IntoKeys stems from a correctly behaving `HashMap<Entity, V, EntityHash>`.
unsafe impl<V> EntitySetIterator for IntoKeys<V> {}
#[cfg(test)]
mod tests {
use super::*;
use bevy_reflect::Reflect;
use static_assertions::assert_impl_all;
// Check that the HashMaps are Clone if the key/values are Clone
assert_impl_all!(EntityHashMap::<usize>: Clone);
// EntityHashMap should implement Reflect
#[cfg(feature = "bevy_reflect")]
assert_impl_all!(EntityHashMap::<i32>: Reflect);
}

420
vendor/bevy_ecs/src/entity/hash_set.rs vendored Normal file
View File

@@ -0,0 +1,420 @@
//! Contains the [`EntityHashSet`] type, a [`HashSet`] pre-configured to use [`EntityHash`] hashing.
//!
//! This module is a lightweight wrapper around Bevy's [`HashSet`] that is more performant for [`Entity`] keys.
use core::{
fmt::{self, Debug, Formatter},
iter::FusedIterator,
marker::PhantomData,
ops::{
BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Deref, DerefMut, Sub,
SubAssign,
},
};
use bevy_platform::collections::hash_set::{self, HashSet};
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::Reflect;
use super::{Entity, EntityHash, EntitySet, EntitySetIterator, FromEntitySetIterator};
/// A [`HashSet`] pre-configured to use [`EntityHash`] hashing.
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "serialize", derive(serde::Deserialize, serde::Serialize))]
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct EntityHashSet(pub(crate) HashSet<Entity, EntityHash>);
impl EntityHashSet {
/// Creates an empty `EntityHashSet`.
///
/// Equivalent to [`HashSet::with_hasher(EntityHash)`].
///
/// [`HashSet::with_hasher(EntityHash)`]: HashSet::with_hasher
pub const fn new() -> Self {
Self(HashSet::with_hasher(EntityHash))
}
/// Creates an empty `EntityHashSet` with the specified capacity.
///
/// Equivalent to [`HashSet::with_capacity_and_hasher(n, EntityHash)`].
///
/// [`HashSet::with_capacity_and_hasher(n, EntityHash)`]: HashSet::with_capacity_and_hasher
pub fn with_capacity(n: usize) -> Self {
Self(HashSet::with_capacity_and_hasher(n, EntityHash))
}
/// Returns the number of elements in the set.
pub fn len(&self) -> usize {
self.0.len()
}
/// Returns `true` if the set contains no elements.
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
/// Returns the inner [`HashSet`].
pub fn into_inner(self) -> HashSet<Entity, EntityHash> {
self.0
}
/// Clears the set, returning all elements in an iterator.
///
/// Equivalent to [`HashSet::drain`].
pub fn drain(&mut self) -> Drain<'_> {
Drain(self.0.drain(), PhantomData)
}
/// An iterator visiting all elements in arbitrary order.
/// The iterator element type is `&'a Entity`.
///
/// Equivalent to [`HashSet::iter`].
pub fn iter(&self) -> Iter<'_> {
Iter(self.0.iter(), PhantomData)
}
/// Drains elements which are true under the given predicate,
/// and returns an iterator over the removed items.
///
/// Equivalent to [`HashSet::extract_if`].
pub fn extract_if<F: FnMut(&Entity) -> bool>(&mut self, f: F) -> ExtractIf<'_, F> {
ExtractIf(self.0.extract_if(f), PhantomData)
}
}
impl Deref for EntityHashSet {
type Target = HashSet<Entity, EntityHash>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for EntityHashSet {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<'a> IntoIterator for &'a EntityHashSet {
type Item = &'a Entity;
type IntoIter = Iter<'a>;
fn into_iter(self) -> Self::IntoIter {
Iter((&self.0).into_iter(), PhantomData)
}
}
impl IntoIterator for EntityHashSet {
type Item = Entity;
type IntoIter = IntoIter;
fn into_iter(self) -> Self::IntoIter {
IntoIter(self.0.into_iter(), PhantomData)
}
}
impl BitAnd for &EntityHashSet {
type Output = EntityHashSet;
fn bitand(self, rhs: Self) -> Self::Output {
EntityHashSet(self.0.bitand(&rhs.0))
}
}
impl BitAndAssign<&EntityHashSet> for EntityHashSet {
fn bitand_assign(&mut self, rhs: &Self) {
self.0.bitand_assign(&rhs.0);
}
}
impl BitOr for &EntityHashSet {
type Output = EntityHashSet;
fn bitor(self, rhs: Self) -> Self::Output {
EntityHashSet(self.0.bitor(&rhs.0))
}
}
impl BitOrAssign<&EntityHashSet> for EntityHashSet {
fn bitor_assign(&mut self, rhs: &Self) {
self.0.bitor_assign(&rhs.0);
}
}
impl BitXor for &EntityHashSet {
type Output = EntityHashSet;
fn bitxor(self, rhs: Self) -> Self::Output {
EntityHashSet(self.0.bitxor(&rhs.0))
}
}
impl BitXorAssign<&EntityHashSet> for EntityHashSet {
fn bitxor_assign(&mut self, rhs: &Self) {
self.0.bitxor_assign(&rhs.0);
}
}
impl Sub for &EntityHashSet {
type Output = EntityHashSet;
fn sub(self, rhs: Self) -> Self::Output {
EntityHashSet(self.0.sub(&rhs.0))
}
}
impl SubAssign<&EntityHashSet> for EntityHashSet {
fn sub_assign(&mut self, rhs: &Self) {
self.0.sub_assign(&rhs.0);
}
}
impl<'a> Extend<&'a Entity> for EntityHashSet {
fn extend<T: IntoIterator<Item = &'a Entity>>(&mut self, iter: T) {
self.0.extend(iter);
}
}
impl Extend<Entity> for EntityHashSet {
fn extend<T: IntoIterator<Item = Entity>>(&mut self, iter: T) {
self.0.extend(iter);
}
}
impl<const N: usize> From<[Entity; N]> for EntityHashSet {
fn from(value: [Entity; N]) -> Self {
Self(HashSet::from_iter(value))
}
}
impl FromIterator<Entity> for EntityHashSet {
fn from_iter<I: IntoIterator<Item = Entity>>(iterable: I) -> Self {
Self(HashSet::from_iter(iterable))
}
}
impl FromEntitySetIterator<Entity> for EntityHashSet {
fn from_entity_set_iter<I: EntitySet<Item = Entity>>(set_iter: I) -> Self {
let iter = set_iter.into_iter();
let set = EntityHashSet::with_capacity(iter.size_hint().0);
iter.fold(set, |mut set, e| {
// SAFETY: Every element in self is unique.
unsafe {
set.insert_unique_unchecked(e);
}
set
})
}
}
/// An iterator over the items of an [`EntityHashSet`].
///
/// This struct is created by the [`iter`] method on [`EntityHashSet`]. See its documentation for more.
///
/// [`iter`]: EntityHashSet::iter
pub struct Iter<'a, S = EntityHash>(hash_set::Iter<'a, Entity>, PhantomData<S>);
impl<'a> Iter<'a> {
/// Returns the inner [`Iter`](hash_set::Iter).
pub fn into_inner(self) -> hash_set::Iter<'a, Entity> {
self.0
}
}
impl<'a> Deref for Iter<'a> {
type Target = hash_set::Iter<'a, Entity>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a> Iterator for Iter<'a> {
type Item = &'a Entity;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl ExactSizeIterator for Iter<'_> {}
impl FusedIterator for Iter<'_> {}
impl Clone for Iter<'_> {
fn clone(&self) -> Self {
Self(self.0.clone(), PhantomData)
}
}
impl Debug for Iter<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("Iter").field(&self.0).field(&self.1).finish()
}
}
impl Default for Iter<'_> {
fn default() -> Self {
Self(Default::default(), PhantomData)
}
}
// SAFETY: Iter stems from a correctly behaving `HashSet<Entity, EntityHash>`.
unsafe impl EntitySetIterator for Iter<'_> {}
/// Owning iterator over the items of an [`EntityHashSet`].
///
/// This struct is created by the [`into_iter`] method on [`EntityHashSet`] (provided by the [`IntoIterator`] trait). See its documentation for more.
///
/// [`into_iter`]: EntityHashSet::into_iter
pub struct IntoIter<S = EntityHash>(hash_set::IntoIter<Entity>, PhantomData<S>);
impl IntoIter {
/// Returns the inner [`IntoIter`](hash_set::IntoIter).
pub fn into_inner(self) -> hash_set::IntoIter<Entity> {
self.0
}
}
impl Deref for IntoIter {
type Target = hash_set::IntoIter<Entity>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Iterator for IntoIter {
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl ExactSizeIterator for IntoIter {}
impl FusedIterator for IntoIter {}
impl Debug for IntoIter {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("IntoIter")
.field(&self.0)
.field(&self.1)
.finish()
}
}
impl Default for IntoIter {
fn default() -> Self {
Self(Default::default(), PhantomData)
}
}
// SAFETY: IntoIter stems from a correctly behaving `HashSet<Entity, EntityHash>`.
unsafe impl EntitySetIterator for IntoIter {}
/// A draining iterator over the items of an [`EntityHashSet`].
///
/// This struct is created by the [`drain`] method on [`EntityHashSet`]. See its documentation for more.
///
/// [`drain`]: EntityHashSet::drain
pub struct Drain<'a, S = EntityHash>(hash_set::Drain<'a, Entity>, PhantomData<S>);
impl<'a> Drain<'a> {
/// Returns the inner [`Drain`](hash_set::Drain).
pub fn into_inner(self) -> hash_set::Drain<'a, Entity> {
self.0
}
}
impl<'a> Deref for Drain<'a> {
type Target = hash_set::Drain<'a, Entity>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a> Iterator for Drain<'a> {
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl ExactSizeIterator for Drain<'_> {}
impl FusedIterator for Drain<'_> {}
impl Debug for Drain<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("Drain")
.field(&self.0)
.field(&self.1)
.finish()
}
}
// SAFETY: Drain stems from a correctly behaving `HashSet<Entity, EntityHash>`.
unsafe impl EntitySetIterator for Drain<'_> {}
/// A draining iterator over entries of a [`EntityHashSet`] which don't satisfy the predicate `f`.
///
/// This struct is created by the [`extract_if`] method on [`EntityHashSet`]. See its documentation for more.
///
/// [`extract_if`]: EntityHashSet::extract_if
pub struct ExtractIf<'a, F: FnMut(&Entity) -> bool, S = EntityHash>(
hash_set::ExtractIf<'a, Entity, F>,
PhantomData<S>,
);
impl<'a, F: FnMut(&Entity) -> bool> ExtractIf<'a, F> {
/// Returns the inner [`ExtractIf`](hash_set::ExtractIf).
pub fn into_inner(self) -> hash_set::ExtractIf<'a, Entity, F> {
self.0
}
}
impl<'a, F: FnMut(&Entity) -> bool> Deref for ExtractIf<'a, F> {
type Target = hash_set::ExtractIf<'a, Entity, F>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a, F: FnMut(&Entity) -> bool> Iterator for ExtractIf<'a, F> {
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl<F: FnMut(&Entity) -> bool> FusedIterator for ExtractIf<'_, F> {}
impl<F: FnMut(&Entity) -> bool> Debug for ExtractIf<'_, F> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("ExtractIf").finish()
}
}
// SAFETY: ExtractIf stems from a correctly behaving `HashSet<Entity, EntityHash>`.
unsafe impl<F: FnMut(&Entity) -> bool> EntitySetIterator for ExtractIf<'_, F> {}
// SAFETY: Difference stems from two correctly behaving `HashSet<Entity, EntityHash>`s.
unsafe impl EntitySetIterator for hash_set::Difference<'_, Entity, EntityHash> {}
// SAFETY: Intersection stems from two correctly behaving `HashSet<Entity, EntityHash>`s.
unsafe impl EntitySetIterator for hash_set::Intersection<'_, Entity, EntityHash> {}
// SAFETY: SymmetricDifference stems from two correctly behaving `HashSet<Entity, EntityHash>`s.
unsafe impl EntitySetIterator for hash_set::SymmetricDifference<'_, Entity, EntityHash> {}
// SAFETY: Union stems from two correctly behaving `HashSet<Entity, EntityHash>`s.
unsafe impl EntitySetIterator for hash_set::Union<'_, Entity, EntityHash> {}

1218
vendor/bevy_ecs/src/entity/index_map.rs vendored Normal file

File diff suppressed because it is too large Load Diff

766
vendor/bevy_ecs/src/entity/index_set.rs vendored Normal file
View File

@@ -0,0 +1,766 @@
//! Contains the [`EntityIndexSet`] type, a [`IndexSet`] pre-configured to use [`EntityHash`] hashing.
//!
//! This module is a lightweight wrapper around `indexmap`'ss [`IndexSet`] that is more performant for [`Entity`] keys.
use core::{
cmp::Ordering,
fmt::{self, Debug, Formatter},
hash::BuildHasher,
hash::{Hash, Hasher},
iter::FusedIterator,
marker::PhantomData,
ops::{
BitAnd, BitOr, BitXor, Bound, Deref, DerefMut, Index, Range, RangeBounds, RangeFrom,
RangeFull, RangeInclusive, RangeTo, RangeToInclusive, Sub,
},
ptr,
};
use indexmap::set::{self, IndexSet};
use super::{Entity, EntityHash, EntitySetIterator};
use bevy_platform::prelude::Box;
/// An [`IndexSet`] pre-configured to use [`EntityHash`] hashing.
#[cfg_attr(feature = "serialize", derive(serde::Deserialize, serde::Serialize))]
#[derive(Debug, Clone, Default)]
pub struct EntityIndexSet(pub(crate) IndexSet<Entity, EntityHash>);
impl EntityIndexSet {
/// Creates an empty `EntityIndexSet`.
///
/// Equivalent to [`IndexSet::with_hasher(EntityHash)`].
///
/// [`IndexSet::with_hasher(EntityHash)`]: IndexSet::with_hasher
pub const fn new() -> Self {
Self(IndexSet::with_hasher(EntityHash))
}
/// Creates an empty `EntityIndexSet` with the specified capacity.
///
/// Equivalent to [`IndexSet::with_capacity_and_hasher(n, EntityHash)`].
///
/// [`IndexSet::with_capacity_and_hasher(n, EntityHash)`]: IndexSet::with_capacity_and_hasher
pub fn with_capacity(n: usize) -> Self {
Self(IndexSet::with_capacity_and_hasher(n, EntityHash))
}
/// Returns the inner [`IndexSet`].
pub fn into_inner(self) -> IndexSet<Entity, EntityHash> {
self.0
}
/// Returns a slice of all the values in the set.
///
/// Equivalent to [`IndexSet::as_slice`].
pub fn as_slice(&self) -> &Slice {
// SAFETY: Slice is a transparent wrapper around indexmap::set::Slice.
unsafe { Slice::from_slice_unchecked(self.0.as_slice()) }
}
/// Clears the `IndexSet` in the given index range, returning those values
/// as a drain iterator.
///
/// Equivalent to [`IndexSet::drain`].
pub fn drain<R: RangeBounds<usize>>(&mut self, range: R) -> Drain<'_> {
Drain(self.0.drain(range), PhantomData)
}
/// Returns a slice of values in the given range of indices.
///
/// Equivalent to [`IndexSet::get_range`].
pub fn get_range<R: RangeBounds<usize>>(&self, range: R) -> Option<&Slice> {
self.0.get_range(range).map(|slice|
// SAFETY: The source IndexSet uses EntityHash.
unsafe { Slice::from_slice_unchecked(slice) })
}
/// Return an iterator over the values of the set, in their order.
///
/// Equivalent to [`IndexSet::iter`].
pub fn iter(&self) -> Iter<'_> {
Iter(self.0.iter(), PhantomData)
}
/// Converts into a boxed slice of all the values in the set.
///
/// Equivalent to [`IndexSet::into_boxed_slice`].
pub fn into_boxed_slice(self) -> Box<Slice> {
// SAFETY: Slice is a transparent wrapper around indexmap::set::Slice.
unsafe { Slice::from_boxed_slice_unchecked(self.0.into_boxed_slice()) }
}
}
impl Deref for EntityIndexSet {
type Target = IndexSet<Entity, EntityHash>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for EntityIndexSet {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<'a> IntoIterator for &'a EntityIndexSet {
type Item = &'a Entity;
type IntoIter = Iter<'a>;
fn into_iter(self) -> Self::IntoIter {
Iter((&self.0).into_iter(), PhantomData)
}
}
impl IntoIterator for EntityIndexSet {
type Item = Entity;
type IntoIter = IntoIter;
fn into_iter(self) -> Self::IntoIter {
IntoIter(self.0.into_iter(), PhantomData)
}
}
impl BitAnd for &EntityIndexSet {
type Output = EntityIndexSet;
fn bitand(self, rhs: Self) -> Self::Output {
EntityIndexSet(self.0.bitand(&rhs.0))
}
}
impl BitOr for &EntityIndexSet {
type Output = EntityIndexSet;
fn bitor(self, rhs: Self) -> Self::Output {
EntityIndexSet(self.0.bitor(&rhs.0))
}
}
impl BitXor for &EntityIndexSet {
type Output = EntityIndexSet;
fn bitxor(self, rhs: Self) -> Self::Output {
EntityIndexSet(self.0.bitxor(&rhs.0))
}
}
impl Sub for &EntityIndexSet {
type Output = EntityIndexSet;
fn sub(self, rhs: Self) -> Self::Output {
EntityIndexSet(self.0.sub(&rhs.0))
}
}
impl<'a> Extend<&'a Entity> for EntityIndexSet {
fn extend<T: IntoIterator<Item = &'a Entity>>(&mut self, iter: T) {
self.0.extend(iter);
}
}
impl Extend<Entity> for EntityIndexSet {
fn extend<T: IntoIterator<Item = Entity>>(&mut self, iter: T) {
self.0.extend(iter);
}
}
impl<const N: usize> From<[Entity; N]> for EntityIndexSet {
fn from(value: [Entity; N]) -> Self {
Self(IndexSet::from_iter(value))
}
}
impl FromIterator<Entity> for EntityIndexSet {
fn from_iter<I: IntoIterator<Item = Entity>>(iterable: I) -> Self {
Self(IndexSet::from_iter(iterable))
}
}
impl<S2> PartialEq<IndexSet<Entity, S2>> for EntityIndexSet
where
S2: BuildHasher,
{
fn eq(&self, other: &IndexSet<Entity, S2>) -> bool {
self.0.eq(other)
}
}
impl PartialEq for EntityIndexSet {
fn eq(&self, other: &EntityIndexSet) -> bool {
self.0.eq(other)
}
}
impl Eq for EntityIndexSet {}
impl Index<(Bound<usize>, Bound<usize>)> for EntityIndexSet {
type Output = Slice;
fn index(&self, key: (Bound<usize>, Bound<usize>)) -> &Self::Output {
// SAFETY: The source IndexSet uses EntityHash.
unsafe { Slice::from_slice_unchecked(self.0.index(key)) }
}
}
impl Index<Range<usize>> for EntityIndexSet {
type Output = Slice;
fn index(&self, key: Range<usize>) -> &Self::Output {
// SAFETY: The source IndexSet uses EntityHash.
unsafe { Slice::from_slice_unchecked(self.0.index(key)) }
}
}
impl Index<RangeFrom<usize>> for EntityIndexSet {
type Output = Slice;
fn index(&self, key: RangeFrom<usize>) -> &Self::Output {
// SAFETY: The source IndexSet uses EntityHash.
unsafe { Slice::from_slice_unchecked(self.0.index(key)) }
}
}
impl Index<RangeFull> for EntityIndexSet {
type Output = Slice;
fn index(&self, key: RangeFull) -> &Self::Output {
// SAFETY: The source IndexSet uses EntityHash.
unsafe { Slice::from_slice_unchecked(self.0.index(key)) }
}
}
impl Index<RangeInclusive<usize>> for EntityIndexSet {
type Output = Slice;
fn index(&self, key: RangeInclusive<usize>) -> &Self::Output {
// SAFETY: The source IndexSet uses EntityHash.
unsafe { Slice::from_slice_unchecked(self.0.index(key)) }
}
}
impl Index<RangeTo<usize>> for EntityIndexSet {
type Output = Slice;
fn index(&self, key: RangeTo<usize>) -> &Self::Output {
// SAFETY: The source IndexSet uses EntityHash.
unsafe { Slice::from_slice_unchecked(self.0.index(key)) }
}
}
impl Index<RangeToInclusive<usize>> for EntityIndexSet {
type Output = Slice;
fn index(&self, key: RangeToInclusive<usize>) -> &Self::Output {
// SAFETY: The source IndexSet uses EntityHash.
unsafe { Slice::from_slice_unchecked(self.0.index(key)) }
}
}
impl Index<usize> for EntityIndexSet {
type Output = Entity;
fn index(&self, key: usize) -> &Entity {
self.0.index(key)
}
}
/// A dynamically-sized slice of values in an [`EntityIndexSet`].
///
/// Equivalent to an [`indexmap::set::Slice<V>`] whose source [`IndexSet`]
/// uses [`EntityHash`].
#[repr(transparent)]
pub struct Slice<S = EntityHash>(PhantomData<S>, set::Slice<Entity>);
impl Slice {
/// Returns an empty slice.
///
/// Equivalent to [`set::Slice::new`].
pub const fn new<'a>() -> &'a Self {
// SAFETY: The source slice is empty.
unsafe { Self::from_slice_unchecked(set::Slice::new()) }
}
/// Constructs a [`entity::index_set::Slice`] from a [`indexmap::set::Slice`] unsafely.
///
/// # Safety
///
/// `slice` must stem from an [`IndexSet`] using [`EntityHash`].
///
/// [`entity::index_set::Slice`]: `crate::entity::index_set::Slice`
pub const unsafe fn from_slice_unchecked(slice: &set::Slice<Entity>) -> &Self {
// SAFETY: Slice is a transparent wrapper around indexmap::set::Slice.
unsafe { &*(ptr::from_ref(slice) as *const Self) }
}
/// Constructs a [`entity::index_set::Slice`] from a [`indexmap::set::Slice`] unsafely.
///
/// # Safety
///
/// `slice` must stem from an [`IndexSet`] using [`EntityHash`].
///
/// [`entity::index_set::Slice`]: `crate::entity::index_set::Slice`
pub const unsafe fn from_slice_unchecked_mut(slice: &mut set::Slice<Entity>) -> &mut Self {
// SAFETY: Slice is a transparent wrapper around indexmap::set::Slice.
unsafe { &mut *(ptr::from_mut(slice) as *mut Self) }
}
/// Casts `self` to the inner slice.
pub const fn as_inner(&self) -> &set::Slice<Entity> {
&self.1
}
/// Constructs a boxed [`entity::index_set::Slice`] from a boxed [`indexmap::set::Slice`] unsafely.
///
/// # Safety
///
/// `slice` must stem from an [`IndexSet`] using [`EntityHash`].
///
/// [`entity::index_set::Slice`]: `crate::entity::index_set::Slice`
pub unsafe fn from_boxed_slice_unchecked(slice: Box<set::Slice<Entity>>) -> Box<Self> {
// SAFETY: Slice is a transparent wrapper around indexmap::set::Slice.
unsafe { Box::from_raw(Box::into_raw(slice) as *mut Self) }
}
/// Casts a reference to `self` to the inner slice.
#[expect(
clippy::borrowed_box,
reason = "We wish to access the Box API of the inner type, without consuming it."
)]
pub fn as_boxed_inner(self: &Box<Self>) -> &Box<set::Slice<Entity>> {
// SAFETY: Slice is a transparent wrapper around indexmap::set::Slice.
unsafe { &*(ptr::from_ref(self).cast::<Box<set::Slice<Entity>>>()) }
}
/// Casts `self` to the inner slice.
pub fn into_boxed_inner(self: Box<Self>) -> Box<set::Slice<Entity>> {
// SAFETY: Slice is a transparent wrapper around indexmap::set::Slice.
unsafe { Box::from_raw(Box::into_raw(self) as *mut set::Slice<Entity>) }
}
/// Returns a slice of values in the given range of indices.
///
/// Equivalent to [`set::Slice::get_range`].
pub fn get_range<R: RangeBounds<usize>>(&self, range: R) -> Option<&Self> {
self.1.get_range(range).map(|slice|
// SAFETY: This a subslice of a valid slice.
unsafe { Self::from_slice_unchecked(slice) })
}
/// Divides one slice into two at an index.
///
/// Equivalent to [`set::Slice::split_at`].
pub fn split_at(&self, index: usize) -> (&Self, &Self) {
let (slice_1, slice_2) = self.1.split_at(index);
// SAFETY: These are subslices of a valid slice.
unsafe {
(
Self::from_slice_unchecked(slice_1),
Self::from_slice_unchecked(slice_2),
)
}
}
/// Returns the first value and the rest of the slice,
/// or `None` if it is empty.
///
/// Equivalent to [`set::Slice::split_first`].
pub fn split_first(&self) -> Option<(&Entity, &Self)> {
self.1.split_first().map(|(first, rest)| {
(
first,
// SAFETY: This a subslice of a valid slice.
unsafe { Self::from_slice_unchecked(rest) },
)
})
}
/// Returns the last value and the rest of the slice,
/// or `None` if it is empty.
///
/// Equivalent to [`set::Slice::split_last`].
pub fn split_last(&self) -> Option<(&Entity, &Self)> {
self.1.split_last().map(|(last, rest)| {
(
last,
// SAFETY: This a subslice of a valid slice.
unsafe { Self::from_slice_unchecked(rest) },
)
})
}
/// Return an iterator over the values of the set slice.
///
/// Equivalent to [`set::Slice::iter`].
pub fn iter(&self) -> Iter<'_> {
Iter(self.1.iter(), PhantomData)
}
}
impl Deref for Slice {
type Target = set::Slice<Entity>;
fn deref(&self) -> &Self::Target {
&self.1
}
}
impl<'a> IntoIterator for &'a Slice {
type IntoIter = Iter<'a>;
type Item = &'a Entity;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl IntoIterator for Box<Slice> {
type IntoIter = IntoIter;
type Item = Entity;
fn into_iter(self) -> Self::IntoIter {
IntoIter(self.into_boxed_inner().into_iter(), PhantomData)
}
}
impl Clone for Box<Slice> {
fn clone(&self) -> Self {
// SAFETY: This is a clone of a valid slice.
unsafe { Slice::from_boxed_slice_unchecked(self.as_boxed_inner().clone()) }
}
}
impl Default for &Slice {
fn default() -> Self {
// SAFETY: The source slice is empty.
unsafe { Slice::from_slice_unchecked(<&set::Slice<Entity>>::default()) }
}
}
impl Default for Box<Slice> {
fn default() -> Self {
// SAFETY: The source slice is empty.
unsafe { Slice::from_boxed_slice_unchecked(<Box<set::Slice<Entity>>>::default()) }
}
}
impl<V: Debug> Debug for Slice<V> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("Slice")
.field(&self.0)
.field(&&self.1)
.finish()
}
}
impl From<&Slice> for Box<Slice> {
fn from(value: &Slice) -> Self {
// SAFETY: This slice is a copy of a valid slice.
unsafe { Slice::from_boxed_slice_unchecked(value.1.into()) }
}
}
impl Hash for Slice {
fn hash<H: Hasher>(&self, state: &mut H) {
self.1.hash(state);
}
}
impl PartialOrd for Slice {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Slice {
fn cmp(&self, other: &Self) -> Ordering {
self.1.cmp(other)
}
}
impl PartialEq for Slice {
fn eq(&self, other: &Self) -> bool {
self.1 == other.1
}
}
impl Eq for Slice {}
impl Index<(Bound<usize>, Bound<usize>)> for Slice {
type Output = Self;
fn index(&self, key: (Bound<usize>, Bound<usize>)) -> &Self {
// SAFETY: This a subslice of a valid slice.
unsafe { Self::from_slice_unchecked(self.1.index(key)) }
}
}
impl Index<Range<usize>> for Slice {
type Output = Self;
fn index(&self, key: Range<usize>) -> &Self {
// SAFETY: This a subslice of a valid slice.
unsafe { Self::from_slice_unchecked(self.1.index(key)) }
}
}
impl Index<RangeFrom<usize>> for Slice {
type Output = Slice;
fn index(&self, key: RangeFrom<usize>) -> &Self {
// SAFETY: This a subslice of a valid slice.
unsafe { Self::from_slice_unchecked(self.1.index(key)) }
}
}
impl Index<RangeFull> for Slice {
type Output = Self;
fn index(&self, key: RangeFull) -> &Self {
// SAFETY: This a subslice of a valid slice.
unsafe { Self::from_slice_unchecked(self.1.index(key)) }
}
}
impl Index<RangeInclusive<usize>> for Slice {
type Output = Self;
fn index(&self, key: RangeInclusive<usize>) -> &Self {
// SAFETY: This a subslice of a valid slice.
unsafe { Self::from_slice_unchecked(self.1.index(key)) }
}
}
impl Index<RangeTo<usize>> for Slice {
type Output = Self;
fn index(&self, key: RangeTo<usize>) -> &Self {
// SAFETY: This a subslice of a valid slice.
unsafe { Self::from_slice_unchecked(self.1.index(key)) }
}
}
impl Index<RangeToInclusive<usize>> for Slice {
type Output = Self;
fn index(&self, key: RangeToInclusive<usize>) -> &Self {
// SAFETY: This a subslice of a valid slice.
unsafe { Self::from_slice_unchecked(self.1.index(key)) }
}
}
impl Index<usize> for Slice {
type Output = Entity;
fn index(&self, key: usize) -> &Entity {
self.1.index(key)
}
}
/// An iterator over the items of an [`EntityIndexSet`].
///
/// This struct is created by the [`iter`] method on [`EntityIndexSet`]. See its documentation for more.
///
/// [`iter`]: EntityIndexSet::iter
pub struct Iter<'a, S = EntityHash>(set::Iter<'a, Entity>, PhantomData<S>);
impl<'a> Iter<'a> {
/// Returns the inner [`Iter`](set::Iter).
pub fn into_inner(self) -> set::Iter<'a, Entity> {
self.0
}
/// Returns a slice of the remaining entries in the iterator.
///
/// Equivalent to [`set::Iter::as_slice`].
pub fn as_slice(&self) -> &Slice {
// SAFETY: The source IndexSet uses EntityHash.
unsafe { Slice::from_slice_unchecked(self.0.as_slice()) }
}
}
impl<'a> Deref for Iter<'a> {
type Target = set::Iter<'a, Entity>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a> Iterator for Iter<'a> {
type Item = &'a Entity;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl DoubleEndedIterator for Iter<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
impl ExactSizeIterator for Iter<'_> {}
impl FusedIterator for Iter<'_> {}
impl Clone for Iter<'_> {
fn clone(&self) -> Self {
Self(self.0.clone(), PhantomData)
}
}
impl Debug for Iter<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("Iter").field(&self.0).field(&self.1).finish()
}
}
impl Default for Iter<'_> {
fn default() -> Self {
Self(Default::default(), PhantomData)
}
}
// SAFETY: Iter stems from a correctly behaving `IndexSet<Entity, EntityHash>`.
unsafe impl EntitySetIterator for Iter<'_> {}
/// Owning iterator over the items of an [`EntityIndexSet`].
///
/// This struct is created by the [`into_iter`] method on [`EntityIndexSet`] (provided by the [`IntoIterator`] trait). See its documentation for more.
///
/// [`into_iter`]: EntityIndexSet::into_iter
pub struct IntoIter<S = EntityHash>(set::IntoIter<Entity>, PhantomData<S>);
impl IntoIter {
/// Returns the inner [`IntoIter`](set::IntoIter).
pub fn into_inner(self) -> set::IntoIter<Entity> {
self.0
}
/// Returns a slice of the remaining entries in the iterator.
///
/// Equivalent to [`set::IntoIter::as_slice`].
pub fn as_slice(&self) -> &Slice {
// SAFETY: The source IndexSet uses EntityHash.
unsafe { Slice::from_slice_unchecked(self.0.as_slice()) }
}
}
impl Deref for IntoIter {
type Target = set::IntoIter<Entity>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Iterator for IntoIter {
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl DoubleEndedIterator for IntoIter {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
impl ExactSizeIterator for IntoIter {}
impl FusedIterator for IntoIter {}
impl Clone for IntoIter {
fn clone(&self) -> Self {
Self(self.0.clone(), PhantomData)
}
}
impl Debug for IntoIter {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("IntoIter")
.field(&self.0)
.field(&self.1)
.finish()
}
}
impl Default for IntoIter {
fn default() -> Self {
Self(Default::default(), PhantomData)
}
}
// SAFETY: IntoIter stems from a correctly behaving `IndexSet<Entity, EntityHash>`.
unsafe impl EntitySetIterator for IntoIter {}
/// A draining iterator over the items of an [`EntityIndexSet`].
///
/// This struct is created by the [`drain`] method on [`EntityIndexSet`]. See its documentation for more.
///
/// [`drain`]: EntityIndexSet::drain
pub struct Drain<'a, S = EntityHash>(set::Drain<'a, Entity>, PhantomData<S>);
impl<'a> Drain<'a> {
/// Returns the inner [`Drain`](set::Drain).
pub fn into_inner(self) -> set::Drain<'a, Entity> {
self.0
}
/// Returns a slice of the remaining entries in the iterator.$
///
/// Equivalent to [`set::Drain::as_slice`].
pub fn as_slice(&self) -> &Slice {
// SAFETY: The source IndexSet uses EntityHash.
unsafe { Slice::from_slice_unchecked(self.0.as_slice()) }
}
}
impl<'a> Deref for Drain<'a> {
type Target = set::Drain<'a, Entity>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a> Iterator for Drain<'a> {
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl DoubleEndedIterator for Drain<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
impl ExactSizeIterator for Drain<'_> {}
impl FusedIterator for Drain<'_> {}
impl Debug for Drain<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("Drain")
.field(&self.0)
.field(&self.1)
.finish()
}
}
// SAFETY: Drain stems from a correctly behaving `IndexSet<Entity, EntityHash>`.
unsafe impl EntitySetIterator for Drain<'_> {}
// SAFETY: Difference stems from two correctly behaving `IndexSet<Entity, EntityHash>`s.
unsafe impl EntitySetIterator for set::Difference<'_, Entity, EntityHash> {}
// SAFETY: Intersection stems from two correctly behaving `IndexSet<Entity, EntityHash>`s.
unsafe impl EntitySetIterator for set::Intersection<'_, Entity, EntityHash> {}
// SAFETY: SymmetricDifference stems from two correctly behaving `IndexSet<Entity, EntityHash>`s.
unsafe impl EntitySetIterator for set::SymmetricDifference<'_, Entity, EntityHash, EntityHash> {}
// SAFETY: Union stems from two correctly behaving `IndexSet<Entity, EntityHash>`s.
unsafe impl EntitySetIterator for set::Union<'_, Entity, EntityHash> {}
// SAFETY: Splice stems from a correctly behaving `IndexSet<Entity, EntityHash>`s.
unsafe impl<I: Iterator<Item = Entity>> EntitySetIterator
for set::Splice<'_, I, Entity, EntityHash>
{
}

View File

@@ -0,0 +1,349 @@
pub use bevy_ecs_macros::MapEntities;
use crate::{
entity::{hash_map::EntityHashMap, Entity},
identifier::masks::{IdentifierMask, HIGH_MASK},
world::World,
};
use alloc::{collections::VecDeque, vec::Vec};
use bevy_platform::collections::HashSet;
use core::hash::BuildHasher;
use smallvec::SmallVec;
/// Operation to map all contained [`Entity`] fields in a type to new values.
///
/// As entity IDs are valid only for the [`World`] they're sourced from, using [`Entity`]
/// as references in components copied from another world will be invalid. This trait
/// allows defining custom mappings for these references via [`EntityMappers`](EntityMapper), which
/// inject the entity mapping strategy between your `MapEntities` type and the current world
/// (usually by using an [`EntityHashMap<Entity>`] between source entities and entities in the
/// current world).
///
/// Components use [`Component::map_entities`](crate::component::Component::map_entities) to map
/// entities in the context of scenes and entity cloning, which generally uses [`MapEntities`] internally
/// to map each field (see those docs for usage).
///
/// [`HashSet<Entity>`]: bevy_platform::collections::HashSet
///
/// ## Example
///
/// ```
/// use bevy_ecs::prelude::*;
/// use bevy_ecs::entity::MapEntities;
///
/// #[derive(Component)]
/// struct Spring {
/// a: Entity,
/// b: Entity,
/// }
///
/// impl MapEntities for Spring {
/// fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
/// self.a = entity_mapper.get_mapped(self.a);
/// self.b = entity_mapper.get_mapped(self.b);
/// }
/// }
/// ```
pub trait MapEntities {
/// Updates all [`Entity`] references stored inside using `entity_mapper`.
///
/// Implementors should look up any and all [`Entity`] values stored within `self` and
/// update them to the mapped values via `entity_mapper`.
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E);
}
impl MapEntities for Entity {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
*self = entity_mapper.get_mapped(*self);
}
}
impl MapEntities for Option<Entity> {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
if let Some(entity) = self {
*entity = entity_mapper.get_mapped(*entity);
}
}
}
impl<S: BuildHasher + Default> MapEntities for HashSet<Entity, S> {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
*self = self.drain().map(|e| entity_mapper.get_mapped(e)).collect();
}
}
impl MapEntities for Vec<Entity> {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
for entity in self.iter_mut() {
*entity = entity_mapper.get_mapped(*entity);
}
}
}
impl MapEntities for VecDeque<Entity> {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
for entity in self.iter_mut() {
*entity = entity_mapper.get_mapped(*entity);
}
}
}
impl<A: smallvec::Array<Item = Entity>> MapEntities for SmallVec<A> {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
for entity in self.iter_mut() {
*entity = entity_mapper.get_mapped(*entity);
}
}
}
/// An implementor of this trait knows how to map an [`Entity`] into another [`Entity`].
///
/// Usually this is done by using an [`EntityHashMap<Entity>`] to map source entities
/// (mapper inputs) to the current world's entities (mapper outputs).
///
/// More generally, this can be used to map [`Entity`] references between any two [`Worlds`](World).
///
/// This is used by [`MapEntities`] implementors.
///
/// ## Example
///
/// ```
/// # use bevy_ecs::entity::{Entity, EntityMapper};
/// # use bevy_ecs::entity::EntityHashMap;
/// #
/// pub struct SimpleEntityMapper {
/// map: EntityHashMap<Entity>,
/// }
///
/// // Example implementation of EntityMapper where we map an entity to another entity if it exists
/// // in the underlying `EntityHashMap`, otherwise we just return the original entity.
/// impl EntityMapper for SimpleEntityMapper {
/// fn get_mapped(&mut self, entity: Entity) -> Entity {
/// self.map.get(&entity).copied().unwrap_or(entity)
/// }
///
/// fn set_mapped(&mut self, source: Entity, target: Entity) {
/// self.map.insert(source, target);
/// }
/// }
/// ```
pub trait EntityMapper {
/// Returns the "target" entity that maps to the given `source`.
fn get_mapped(&mut self, source: Entity) -> Entity;
/// Maps the `target` entity to the given `source`. For some implementations this might not actually determine the result
/// of [`EntityMapper::get_mapped`].
fn set_mapped(&mut self, source: Entity, target: Entity);
}
impl EntityMapper for () {
#[inline]
fn get_mapped(&mut self, source: Entity) -> Entity {
source
}
#[inline]
fn set_mapped(&mut self, _source: Entity, _target: Entity) {}
}
impl EntityMapper for (Entity, Entity) {
#[inline]
fn get_mapped(&mut self, source: Entity) -> Entity {
if source == self.0 {
self.1
} else {
source
}
}
fn set_mapped(&mut self, _source: Entity, _target: Entity) {}
}
impl EntityMapper for &mut dyn EntityMapper {
fn get_mapped(&mut self, source: Entity) -> Entity {
(*self).get_mapped(source)
}
fn set_mapped(&mut self, source: Entity, target: Entity) {
(*self).set_mapped(source, target);
}
}
impl EntityMapper for SceneEntityMapper<'_> {
/// Returns the corresponding mapped entity or reserves a new dead entity ID in the current world if it is absent.
fn get_mapped(&mut self, source: Entity) -> Entity {
if let Some(&mapped) = self.map.get(&source) {
return mapped;
}
// this new entity reference is specifically designed to never represent any living entity
let new = Entity::from_raw_and_generation(
self.dead_start.index(),
IdentifierMask::inc_masked_high_by(self.dead_start.generation, self.generations),
);
// Prevent generations counter from being a greater value than HIGH_MASK.
self.generations = (self.generations + 1) & HIGH_MASK;
self.map.insert(source, new);
new
}
fn set_mapped(&mut self, source: Entity, target: Entity) {
self.map.insert(source, target);
}
}
impl EntityMapper for EntityHashMap<Entity> {
/// Returns the corresponding mapped entity or returns `entity` if there is no mapped entity
fn get_mapped(&mut self, source: Entity) -> Entity {
self.get(&source).cloned().unwrap_or(source)
}
fn set_mapped(&mut self, source: Entity, target: Entity) {
self.insert(source, target);
}
}
/// A wrapper for [`EntityHashMap<Entity>`], augmenting it with the ability to allocate new [`Entity`] references in a destination
/// world. These newly allocated references are guaranteed to never point to any living entity in that world.
///
/// References are allocated by returning increasing generations starting from an internally initialized base
/// [`Entity`]. After it is finished being used, this entity is despawned and the requisite number of generations reserved.
pub struct SceneEntityMapper<'m> {
/// A mapping from one set of entities to another.
///
/// This is typically used to coordinate data transfer between sets of entities, such as between a scene and the world
/// or over the network. This is required as [`Entity`] identifiers are opaque; you cannot and do not want to reuse
/// identifiers directly.
///
/// On its own, a [`EntityHashMap<Entity>`] is not capable of allocating new entity identifiers, which is needed to map references
/// to entities that lie outside the source entity set. This functionality can be accessed through [`SceneEntityMapper::world_scope()`].
map: &'m mut EntityHashMap<Entity>,
/// A base [`Entity`] used to allocate new references.
dead_start: Entity,
/// The number of generations this mapper has allocated thus far.
generations: u32,
}
impl<'m> SceneEntityMapper<'m> {
/// Gets a reference to the underlying [`EntityHashMap<Entity>`].
pub fn get_map(&'m self) -> &'m EntityHashMap<Entity> {
self.map
}
/// Gets a mutable reference to the underlying [`EntityHashMap<Entity>`].
pub fn get_map_mut(&'m mut self) -> &'m mut EntityHashMap<Entity> {
self.map
}
/// Creates a new [`SceneEntityMapper`], spawning a temporary base [`Entity`] in the provided [`World`]
pub fn new(map: &'m mut EntityHashMap<Entity>, world: &mut World) -> Self {
// We're going to be calling methods on `Entities` that require advance
// flushing, such as `alloc` and `free`.
world.flush_entities();
Self {
map,
// SAFETY: Entities data is kept in a valid state via `EntityMapper::world_scope`
dead_start: unsafe { world.entities_mut().alloc() },
generations: 0,
}
}
/// Reserves the allocated references to dead entities within the world. This frees the temporary base
/// [`Entity`] while reserving extra generations. Because this makes the [`SceneEntityMapper`] unable to
/// safely allocate any more references, this method takes ownership of `self` in order to render it unusable.
pub fn finish(self, world: &mut World) {
// SAFETY: Entities data is kept in a valid state via `EntityMap::world_scope`
let entities = unsafe { world.entities_mut() };
assert!(entities.free(self.dead_start).is_some());
assert!(entities.reserve_generations(self.dead_start.index(), self.generations));
}
/// Creates an [`SceneEntityMapper`] from a provided [`World`] and [`EntityHashMap<Entity>`], then calls the
/// provided function with it. This allows one to allocate new entity references in this [`World`] that are
/// guaranteed to never point at a living entity now or in the future. This functionality is useful for safely
/// mapping entity identifiers that point at entities outside the source world. The passed function, `f`, is called
/// within the scope of this world. Its return value is then returned from `world_scope` as the generic type
/// parameter `R`.
pub fn world_scope<R>(
entity_map: &'m mut EntityHashMap<Entity>,
world: &mut World,
f: impl FnOnce(&mut World, &mut Self) -> R,
) -> R {
let mut mapper = Self::new(entity_map, world);
let result = f(world, &mut mapper);
mapper.finish(world);
result
}
}
#[cfg(test)]
mod tests {
use crate::{
entity::{Entity, EntityHashMap, EntityMapper, SceneEntityMapper},
world::World,
};
#[test]
fn entity_mapper() {
const FIRST_IDX: u32 = 1;
const SECOND_IDX: u32 = 2;
let mut map = EntityHashMap::default();
let mut world = World::new();
let mut mapper = SceneEntityMapper::new(&mut map, &mut world);
let mapped_ent = Entity::from_raw(FIRST_IDX);
let dead_ref = mapper.get_mapped(mapped_ent);
assert_eq!(
dead_ref,
mapper.get_mapped(mapped_ent),
"should persist the allocated mapping from the previous line"
);
assert_eq!(
mapper.get_mapped(Entity::from_raw(SECOND_IDX)).index(),
dead_ref.index(),
"should re-use the same index for further dead refs"
);
mapper.finish(&mut world);
// Next allocated entity should be a further generation on the same index
let entity = world.spawn_empty().id();
assert_eq!(entity.index(), dead_ref.index());
assert!(entity.generation() > dead_ref.generation());
}
#[test]
fn world_scope_reserves_generations() {
let mut map = EntityHashMap::default();
let mut world = World::new();
let dead_ref = SceneEntityMapper::world_scope(&mut map, &mut world, |_, mapper| {
mapper.get_mapped(Entity::from_raw(0))
});
// Next allocated entity should be a further generation on the same index
let entity = world.spawn_empty().id();
assert_eq!(entity.index(), dead_ref.index());
assert!(entity.generation() > dead_ref.generation());
}
#[test]
fn entity_mapper_no_panic() {
let mut world = World::new();
// "Dirty" the `Entities`, requiring a flush afterward.
world.entities.reserve_entity();
assert!(world.entities.needs_flush());
// Create and exercise a SceneEntityMapper - should not panic because it flushes
// `Entities` first.
SceneEntityMapper::world_scope(&mut Default::default(), &mut world, |_, m| {
m.get_mapped(Entity::PLACEHOLDER);
});
// The SceneEntityMapper should leave `Entities` in a flushed state.
assert!(!world.entities.needs_flush());
}
}

1377
vendor/bevy_ecs/src/entity/mod.rs vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,587 @@
//! A wrapper around entity arrays with a uniqueness invariant.
use core::{
array,
borrow::{Borrow, BorrowMut},
fmt::Debug,
ops::{
Bound, Deref, DerefMut, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive,
RangeTo, RangeToInclusive,
},
ptr,
};
use alloc::{
boxed::Box,
collections::{BTreeSet, BinaryHeap, LinkedList, VecDeque},
rc::Rc,
vec::Vec,
};
use bevy_platform::sync::Arc;
use super::{
unique_slice::{self, UniqueEntityEquivalentSlice},
Entity, EntityEquivalent, UniqueEntityIter,
};
/// An array that contains only unique entities.
///
/// It can be obtained through certain methods on [`UniqueEntityEquivalentSlice`],
/// and some [`TryFrom`] implementations.
///
/// When `T` is [`Entity`], use [`UniqueEntityArray`].
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct UniqueEntityEquivalentArray<T: EntityEquivalent, const N: usize>([T; N]);
/// An array that contains only unique [`Entity`].
///
/// This is the default case of a [`UniqueEntityEquivalentArray`].
pub type UniqueEntityArray<const N: usize> = UniqueEntityEquivalentArray<Entity, N>;
impl<T: EntityEquivalent, const N: usize> UniqueEntityEquivalentArray<T, N> {
/// Constructs a `UniqueEntityEquivalentArray` from a [`[T; N]`] unsafely.
///
/// # Safety
///
/// `array` must contain only unique elements.
pub const unsafe fn from_array_unchecked(array: [T; N]) -> Self {
Self(array)
}
/// Constructs a `&UniqueEntityEquivalentArray` from a [`&[T; N]`] unsafely.
///
/// # Safety
///
/// `array` must contain only unique elements.
pub const unsafe fn from_array_ref_unchecked(array: &[T; N]) -> &Self {
// SAFETY: UniqueEntityEquivalentArray is a transparent wrapper around [T; N].
unsafe { &*(ptr::from_ref(array).cast()) }
}
/// Constructs a `Box<UniqueEntityEquivalentArray>` from a [`Box<[T; N]>`] unsafely.
///
/// # Safety
///
/// `array` must contain only unique elements.
pub unsafe fn from_boxed_array_unchecked(array: Box<[T; N]>) -> Box<Self> {
// SAFETY: UniqueEntityEquivalentArray is a transparent wrapper around [T; N].
unsafe { Box::from_raw(Box::into_raw(array).cast()) }
}
/// Casts `self` into the inner array.
pub fn into_boxed_inner(self: Box<Self>) -> Box<[T; N]> {
// SAFETY: UniqueEntityEquivalentArray is a transparent wrapper around [T; N].
unsafe { Box::from_raw(Box::into_raw(self).cast()) }
}
/// Constructs a `Arc<UniqueEntityEquivalentArray>` from a [`Arc<[T; N]>`] unsafely.
///
/// # Safety
///
/// `slice` must contain only unique elements.
pub unsafe fn from_arc_array_unchecked(slice: Arc<[T; N]>) -> Arc<Self> {
// SAFETY: UniqueEntityEquivalentArray is a transparent wrapper around [T; N].
unsafe { Arc::from_raw(Arc::into_raw(slice).cast()) }
}
/// Casts `self` to the inner array.
pub fn into_arc_inner(this: Arc<Self>) -> Arc<[T; N]> {
// SAFETY: UniqueEntityEquivalentArray is a transparent wrapper around [T; N].
unsafe { Arc::from_raw(Arc::into_raw(this).cast()) }
}
// Constructs a `Rc<UniqueEntityEquivalentArray>` from a [`Rc<[T; N]>`] unsafely.
///
/// # Safety
///
/// `slice` must contain only unique elements.
pub unsafe fn from_rc_array_unchecked(slice: Rc<[T; N]>) -> Rc<Self> {
// SAFETY: UniqueEntityEquivalentArray is a transparent wrapper around [T; N].
unsafe { Rc::from_raw(Rc::into_raw(slice).cast()) }
}
/// Casts `self` to the inner array.
pub fn into_rc_inner(self: Rc<Self>) -> Rc<[T; N]> {
// SAFETY: UniqueEntityEquivalentArray is a transparent wrapper around [T; N].
unsafe { Rc::from_raw(Rc::into_raw(self).cast()) }
}
/// Return the inner array.
pub fn into_inner(self) -> [T; N] {
self.0
}
/// Returns a reference to the inner array.
pub fn as_inner(&self) -> &[T; N] {
&self.0
}
/// Returns a slice containing the entire array. Equivalent to `&s[..]`.
pub const fn as_slice(&self) -> &UniqueEntityEquivalentSlice<T> {
// SAFETY: All elements in the original array are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(self.0.as_slice()) }
}
/// Returns a mutable slice containing the entire array. Equivalent to
/// `&mut s[..]`.
pub fn as_mut_slice(&mut self) -> &mut UniqueEntityEquivalentSlice<T> {
// SAFETY: All elements in the original array are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked_mut(self.0.as_mut_slice()) }
}
/// Borrows each element and returns an array of references with the same
/// size as `self`.
///
/// Equivalent to [`[T; N]::as_ref`](array::each_ref).
pub fn each_ref(&self) -> UniqueEntityEquivalentArray<&T, N> {
UniqueEntityEquivalentArray(self.0.each_ref())
}
}
impl<T: EntityEquivalent, const N: usize> Deref for UniqueEntityEquivalentArray<T, N> {
type Target = UniqueEntityEquivalentSlice<T>;
fn deref(&self) -> &Self::Target {
// SAFETY: All elements in the original array are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(&self.0) }
}
}
impl<T: EntityEquivalent, const N: usize> DerefMut for UniqueEntityEquivalentArray<T, N> {
fn deref_mut(&mut self) -> &mut Self::Target {
// SAFETY: All elements in the original array are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked_mut(&mut self.0) }
}
}
impl<T: EntityEquivalent> Default for UniqueEntityEquivalentArray<T, 0> {
fn default() -> Self {
Self(Default::default())
}
}
impl<'a, T: EntityEquivalent, const N: usize> IntoIterator
for &'a UniqueEntityEquivalentArray<T, N>
{
type Item = &'a T;
type IntoIter = unique_slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
// SAFETY: All elements in the original array are unique.
unsafe { UniqueEntityIter::from_iterator_unchecked(self.0.iter()) }
}
}
impl<T: EntityEquivalent, const N: usize> IntoIterator for UniqueEntityEquivalentArray<T, N> {
type Item = T;
type IntoIter = IntoIter<N, T>;
fn into_iter(self) -> Self::IntoIter {
// SAFETY: All elements in the original array are unique.
unsafe { UniqueEntityIter::from_iterator_unchecked(self.0.into_iter()) }
}
}
impl<T: EntityEquivalent, const N: usize> AsRef<UniqueEntityEquivalentSlice<T>>
for UniqueEntityEquivalentArray<T, N>
{
fn as_ref(&self) -> &UniqueEntityEquivalentSlice<T> {
self
}
}
impl<T: EntityEquivalent, const N: usize> AsMut<UniqueEntityEquivalentSlice<T>>
for UniqueEntityEquivalentArray<T, N>
{
fn as_mut(&mut self) -> &mut UniqueEntityEquivalentSlice<T> {
self
}
}
impl<T: EntityEquivalent, const N: usize> Borrow<UniqueEntityEquivalentSlice<T>>
for UniqueEntityEquivalentArray<T, N>
{
fn borrow(&self) -> &UniqueEntityEquivalentSlice<T> {
self
}
}
impl<T: EntityEquivalent, const N: usize> BorrowMut<UniqueEntityEquivalentSlice<T>>
for UniqueEntityEquivalentArray<T, N>
{
fn borrow_mut(&mut self) -> &mut UniqueEntityEquivalentSlice<T> {
self
}
}
impl<T: EntityEquivalent, const N: usize> Index<(Bound<usize>, Bound<usize>)>
for UniqueEntityEquivalentArray<T, N>
{
type Output = UniqueEntityEquivalentSlice<T>;
fn index(&self, key: (Bound<usize>, Bound<usize>)) -> &Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(self.0.index(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> Index<Range<usize>>
for UniqueEntityEquivalentArray<T, N>
{
type Output = UniqueEntityEquivalentSlice<T>;
fn index(&self, key: Range<usize>) -> &Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(self.0.index(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> Index<RangeFrom<usize>>
for UniqueEntityEquivalentArray<T, N>
{
type Output = UniqueEntityEquivalentSlice<T>;
fn index(&self, key: RangeFrom<usize>) -> &Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(self.0.index(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> Index<RangeFull> for UniqueEntityEquivalentArray<T, N> {
type Output = UniqueEntityEquivalentSlice<T>;
fn index(&self, key: RangeFull) -> &Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(self.0.index(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> Index<RangeInclusive<usize>>
for UniqueEntityEquivalentArray<T, N>
{
type Output = UniqueEntityEquivalentSlice<T>;
fn index(&self, key: RangeInclusive<usize>) -> &Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(self.0.index(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> Index<RangeTo<usize>>
for UniqueEntityEquivalentArray<T, N>
{
type Output = UniqueEntityEquivalentSlice<T>;
fn index(&self, key: RangeTo<usize>) -> &Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(self.0.index(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> Index<RangeToInclusive<usize>>
for UniqueEntityEquivalentArray<T, N>
{
type Output = UniqueEntityEquivalentSlice<T>;
fn index(&self, key: RangeToInclusive<usize>) -> &Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(self.0.index(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> Index<usize> for UniqueEntityEquivalentArray<T, N> {
type Output = T;
fn index(&self, key: usize) -> &T {
self.0.index(key)
}
}
impl<T: EntityEquivalent, const N: usize> IndexMut<(Bound<usize>, Bound<usize>)>
for UniqueEntityEquivalentArray<T, N>
{
fn index_mut(&mut self, key: (Bound<usize>, Bound<usize>)) -> &mut Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked_mut(self.0.index_mut(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> IndexMut<Range<usize>>
for UniqueEntityEquivalentArray<T, N>
{
fn index_mut(&mut self, key: Range<usize>) -> &mut Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked_mut(self.0.index_mut(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> IndexMut<RangeFrom<usize>>
for UniqueEntityEquivalentArray<T, N>
{
fn index_mut(&mut self, key: RangeFrom<usize>) -> &mut Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked_mut(self.0.index_mut(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> IndexMut<RangeFull>
for UniqueEntityEquivalentArray<T, N>
{
fn index_mut(&mut self, key: RangeFull) -> &mut Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked_mut(self.0.index_mut(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> IndexMut<RangeInclusive<usize>>
for UniqueEntityEquivalentArray<T, N>
{
fn index_mut(&mut self, key: RangeInclusive<usize>) -> &mut Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked_mut(self.0.index_mut(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> IndexMut<RangeTo<usize>>
for UniqueEntityEquivalentArray<T, N>
{
fn index_mut(&mut self, key: RangeTo<usize>) -> &mut Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked_mut(self.0.index_mut(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> IndexMut<RangeToInclusive<usize>>
for UniqueEntityEquivalentArray<T, N>
{
fn index_mut(&mut self, key: RangeToInclusive<usize>) -> &mut Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked_mut(self.0.index_mut(key)) }
}
}
impl<T: EntityEquivalent + Clone> From<&[T; 1]> for UniqueEntityEquivalentArray<T, 1> {
fn from(value: &[T; 1]) -> Self {
Self(value.clone())
}
}
impl<T: EntityEquivalent + Clone> From<&[T; 0]> for UniqueEntityEquivalentArray<T, 0> {
fn from(value: &[T; 0]) -> Self {
Self(value.clone())
}
}
impl<T: EntityEquivalent + Clone> From<&mut [T; 1]> for UniqueEntityEquivalentArray<T, 1> {
fn from(value: &mut [T; 1]) -> Self {
Self(value.clone())
}
}
impl<T: EntityEquivalent + Clone> From<&mut [T; 0]> for UniqueEntityEquivalentArray<T, 0> {
fn from(value: &mut [T; 0]) -> Self {
Self(value.clone())
}
}
impl<T: EntityEquivalent> From<[T; 1]> for UniqueEntityEquivalentArray<T, 1> {
fn from(value: [T; 1]) -> Self {
Self(value)
}
}
impl<T: EntityEquivalent> From<[T; 0]> for UniqueEntityEquivalentArray<T, 0> {
fn from(value: [T; 0]) -> Self {
Self(value)
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 1>> for (T,) {
fn from(array: UniqueEntityEquivalentArray<T, 1>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 2>> for (T, T) {
fn from(array: UniqueEntityEquivalentArray<T, 2>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 3>> for (T, T, T) {
fn from(array: UniqueEntityEquivalentArray<T, 3>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 4>> for (T, T, T, T) {
fn from(array: UniqueEntityEquivalentArray<T, 4>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 5>> for (T, T, T, T, T) {
fn from(array: UniqueEntityEquivalentArray<T, 5>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 6>> for (T, T, T, T, T, T) {
fn from(array: UniqueEntityEquivalentArray<T, 6>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 7>> for (T, T, T, T, T, T, T) {
fn from(array: UniqueEntityEquivalentArray<T, 7>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 8>> for (T, T, T, T, T, T, T, T) {
fn from(array: UniqueEntityEquivalentArray<T, 8>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 9>> for (T, T, T, T, T, T, T, T, T) {
fn from(array: UniqueEntityEquivalentArray<T, 9>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 10>>
for (T, T, T, T, T, T, T, T, T, T)
{
fn from(array: UniqueEntityEquivalentArray<T, 10>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 11>>
for (T, T, T, T, T, T, T, T, T, T, T)
{
fn from(array: UniqueEntityEquivalentArray<T, 11>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 12>>
for (T, T, T, T, T, T, T, T, T, T, T, T)
{
fn from(array: UniqueEntityEquivalentArray<T, 12>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent + Ord, const N: usize> From<UniqueEntityEquivalentArray<T, N>>
for BTreeSet<T>
{
fn from(value: UniqueEntityEquivalentArray<T, N>) -> Self {
BTreeSet::from(value.0)
}
}
impl<T: EntityEquivalent + Ord, const N: usize> From<UniqueEntityEquivalentArray<T, N>>
for BinaryHeap<T>
{
fn from(value: UniqueEntityEquivalentArray<T, N>) -> Self {
BinaryHeap::from(value.0)
}
}
impl<T: EntityEquivalent, const N: usize> From<UniqueEntityEquivalentArray<T, N>>
for LinkedList<T>
{
fn from(value: UniqueEntityEquivalentArray<T, N>) -> Self {
LinkedList::from(value.0)
}
}
impl<T: EntityEquivalent, const N: usize> From<UniqueEntityEquivalentArray<T, N>> for Vec<T> {
fn from(value: UniqueEntityEquivalentArray<T, N>) -> Self {
Vec::from(value.0)
}
}
impl<T: EntityEquivalent, const N: usize> From<UniqueEntityEquivalentArray<T, N>> for VecDeque<T> {
fn from(value: UniqueEntityEquivalentArray<T, N>) -> Self {
VecDeque::from(value.0)
}
}
impl<T: EntityEquivalent + PartialEq<U>, U: EntityEquivalent, const N: usize>
PartialEq<&UniqueEntityEquivalentSlice<U>> for UniqueEntityEquivalentArray<T, N>
{
fn eq(&self, other: &&UniqueEntityEquivalentSlice<U>) -> bool {
self.0.eq(&other.as_inner())
}
}
impl<T: EntityEquivalent + PartialEq<U>, U: EntityEquivalent, const N: usize>
PartialEq<UniqueEntityEquivalentSlice<U>> for UniqueEntityEquivalentArray<T, N>
{
fn eq(&self, other: &UniqueEntityEquivalentSlice<U>) -> bool {
self.0.eq(other.as_inner())
}
}
impl<T: PartialEq<U>, U: EntityEquivalent, const N: usize>
PartialEq<&UniqueEntityEquivalentArray<U, N>> for Vec<T>
{
fn eq(&self, other: &&UniqueEntityEquivalentArray<U, N>) -> bool {
self.eq(&other.0)
}
}
impl<T: PartialEq<U>, U: EntityEquivalent, const N: usize>
PartialEq<&UniqueEntityEquivalentArray<U, N>> for VecDeque<T>
{
fn eq(&self, other: &&UniqueEntityEquivalentArray<U, N>) -> bool {
self.eq(&other.0)
}
}
impl<T: PartialEq<U>, U: EntityEquivalent, const N: usize>
PartialEq<&mut UniqueEntityEquivalentArray<U, N>> for VecDeque<T>
{
fn eq(&self, other: &&mut UniqueEntityEquivalentArray<U, N>) -> bool {
self.eq(&other.0)
}
}
impl<T: PartialEq<U>, U: EntityEquivalent, const N: usize>
PartialEq<UniqueEntityEquivalentArray<U, N>> for Vec<T>
{
fn eq(&self, other: &UniqueEntityEquivalentArray<U, N>) -> bool {
self.eq(&other.0)
}
}
impl<T: PartialEq<U>, U: EntityEquivalent, const N: usize>
PartialEq<UniqueEntityEquivalentArray<U, N>> for VecDeque<T>
{
fn eq(&self, other: &UniqueEntityEquivalentArray<U, N>) -> bool {
self.eq(&other.0)
}
}
/// A by-value array iterator.
///
/// Equivalent to [`array::IntoIter`].
pub type IntoIter<const N: usize, T = Entity> = UniqueEntityIter<array::IntoIter<T, N>>;
impl<T: EntityEquivalent, const N: usize> UniqueEntityIter<array::IntoIter<T, N>> {
/// Returns an immutable slice of all elements that have not been yielded
/// yet.
///
/// Equivalent to [`array::IntoIter::as_slice`].
pub fn as_slice(&self) -> &UniqueEntityEquivalentSlice<T> {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(self.as_inner().as_slice()) }
}
/// Returns a mutable slice of all elements that have not been yielded yet.
///
/// Equivalent to [`array::IntoIter::as_mut_slice`].
pub fn as_mut_slice(&mut self) -> &mut UniqueEntityEquivalentSlice<T> {
// SAFETY: All elements in the original slice are unique.
unsafe {
UniqueEntityEquivalentSlice::from_slice_unchecked_mut(
self.as_mut_inner().as_mut_slice(),
)
}
}
}

1895
vendor/bevy_ecs/src/entity/unique_slice.rs vendored Normal file

File diff suppressed because it is too large Load Diff

1114
vendor/bevy_ecs/src/entity/unique_vec.rs vendored Normal file

File diff suppressed because it is too large Load Diff

307
vendor/bevy_ecs/src/entity_disabling.rs vendored Normal file
View File

@@ -0,0 +1,307 @@
//! Disabled entities do not show up in queries unless the query explicitly mentions them.
//!
//! Entities which are disabled in this way are not removed from the [`World`],
//! and their relationships remain intact.
//! In many cases, you may want to disable entire trees of entities at once,
//! using [`EntityCommands::insert_recursive`](crate::prelude::EntityCommands::insert_recursive).
//!
//! While Bevy ships with a built-in [`Disabled`] component, you can also create your own
//! disabling components, which will operate in the same way but can have distinct semantics.
//!
//! ```
//! use bevy_ecs::prelude::*;
//!
//! // Our custom disabling component!
//! #[derive(Component, Clone)]
//! struct Prefab;
//!
//! #[derive(Component)]
//! struct A;
//!
//! let mut world = World::new();
//! world.register_disabling_component::<Prefab>();
//! world.spawn((A, Prefab));
//! world.spawn((A,));
//! world.spawn((A,));
//!
//! let mut normal_query = world.query::<&A>();
//! assert_eq!(2, normal_query.iter(&world).count());
//!
//! let mut prefab_query = world.query_filtered::<&A, With<Prefab>>();
//! assert_eq!(1, prefab_query.iter(&world).count());
//!
//! let mut maybe_prefab_query = world.query::<(&A, Has<Prefab>)>();
//! assert_eq!(3, maybe_prefab_query.iter(&world).count());
//! ```
//!
//! ## Default query filters
//!
//! In Bevy, entity disabling is implemented through the construction of a global "default query filter".
//! Queries which do not explicitly mention the disabled component will not include entities with that component.
//! If an entity has multiple disabling components, it will only be included in queries that mention all of them.
//!
//! For example, `Query<&Position>` will not include entities with the [`Disabled`] component,
//! even if they have a `Position` component,
//! but `Query<&Position, With<Disabled>>` or `Query<(&Position, Has<Disabled>)>` will see them.
//!
//! Entities with disabling components are still present in the [`World`] and can be accessed directly,
//! using methods on [`World`] or [`Commands`](crate::prelude::Commands).
//!
//! ### Warnings
//!
//! Currently, only queries for which the cache is built after enabling a default query filter will have entities
//! with those components filtered. As a result, they should generally only be modified before the
//! app starts.
//!
//! Because filters are applied to all queries they can have performance implication for
//! the enire [`World`], especially when they cause queries to mix sparse and table components.
//! See [`Query` performance] for more info.
//!
//! Custom disabling components can cause significant interoperability issues within the ecosystem,
//! as users must be aware of each disabling component in use.
//! Libraries should think carefully about whether they need to use a new disabling component,
//! and clearly communicate their presence to their users to avoid the new for library compatibility flags.
//!
//! [`With`]: crate::prelude::With
//! [`Has`]: crate::prelude::Has
//! [`World`]: crate::prelude::World
//! [`Query` performance]: crate::prelude::Query#performance
use crate::{
component::{ComponentId, Components, StorageType},
query::FilteredAccess,
world::{FromWorld, World},
};
use bevy_ecs_macros::{Component, Resource};
use smallvec::SmallVec;
#[cfg(feature = "bevy_reflect")]
use {
crate::reflect::ReflectComponent, bevy_reflect::std_traits::ReflectDefault,
bevy_reflect::Reflect,
};
/// A marker component for disabled entities.
///
/// Semantically, this component is used to mark entities that are temporarily disabled (typically for gameplay reasons),
/// but will likely be re-enabled at some point.
///
/// Like all disabling components, this only disables the entity itself,
/// not its children or other entities that reference it.
/// To disable an entire tree of entities, use [`EntityCommands::insert_recursive`](crate::prelude::EntityCommands::insert_recursive).
///
/// Every [`World`] has a default query filter that excludes entities with this component,
/// registered in the [`DefaultQueryFilters`] resource.
/// See [the module docs] for more info.
///
/// [the module docs]: crate::entity_disabling
#[derive(Component, Clone, Debug, Default)]
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect),
reflect(Component),
reflect(Debug, Clone, Default)
)]
// This component is registered as a disabling component during World::bootstrap
pub struct Disabled;
/// Default query filters work by excluding entities with certain components from most queries.
///
/// If a query does not explicitly mention a given disabling component, it will not include entities with that component.
/// To be more precise, this checks if the query's [`FilteredAccess`] contains the component,
/// and if it does not, adds a [`Without`](crate::prelude::Without) filter for that component to the query.
///
/// This resource is initialized in the [`World`] whenever a new world is created,
/// with the [`Disabled`] component as a disabling component.
///
/// Note that you can remove default query filters by overwriting the [`DefaultQueryFilters`] resource.
/// This can be useful as a last resort escape hatch, but is liable to break compatibility with other libraries.
///
/// See the [module docs](crate::entity_disabling) for more info.
///
///
/// # Warning
///
/// Default query filters are a global setting that affects all queries in the [`World`],
/// and incur a small performance cost for each query.
///
/// They can cause significant interoperability issues within the ecosystem,
/// as users must be aware of each disabling component in use.
///
/// Think carefully about whether you need to use a new disabling component,
/// and clearly communicate their presence in any libraries you publish.
#[derive(Resource, Debug)]
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
pub struct DefaultQueryFilters {
// We only expect a few components per application to act as disabling components, so we use a SmallVec here
// to avoid heap allocation in most cases.
disabling: SmallVec<[ComponentId; 4]>,
}
impl FromWorld for DefaultQueryFilters {
fn from_world(world: &mut World) -> Self {
let mut filters = DefaultQueryFilters::empty();
let disabled_component_id = world.register_component::<Disabled>();
filters.register_disabling_component(disabled_component_id);
filters
}
}
impl DefaultQueryFilters {
/// Creates a new, completely empty [`DefaultQueryFilters`].
///
/// This is provided as an escape hatch; in most cases you should initialize this using [`FromWorld`],
/// which is automatically called when creating a new [`World`].
#[must_use]
pub fn empty() -> Self {
DefaultQueryFilters {
disabling: SmallVec::new(),
}
}
/// Adds this [`ComponentId`] to the set of [`DefaultQueryFilters`],
/// causing entities with this component to be excluded from queries.
///
/// This method is idempotent, and will not add the same component multiple times.
///
/// # Warning
///
/// This method should only be called before the app starts, as it will not affect queries
/// initialized before it is called.
///
/// As discussed in the [module docs](crate::entity_disabling), this can have performance implications,
/// as well as create interoperability issues, and should be used with caution.
pub fn register_disabling_component(&mut self, component_id: ComponentId) {
if !self.disabling.contains(&component_id) {
self.disabling.push(component_id);
}
}
/// Get an iterator over all of the components which disable entities when present.
pub fn disabling_ids(&self) -> impl Iterator<Item = ComponentId> + use<'_> {
self.disabling.iter().copied()
}
/// Modifies the provided [`FilteredAccess`] to include the filters from this [`DefaultQueryFilters`].
pub(super) fn modify_access(&self, component_access: &mut FilteredAccess<ComponentId>) {
for component_id in self.disabling_ids() {
if !component_access.contains(component_id) {
component_access.and_without(component_id);
}
}
}
pub(super) fn is_dense(&self, components: &Components) -> bool {
self.disabling_ids().all(|component_id| {
components
.get_info(component_id)
.is_some_and(|info| info.storage_type() == StorageType::Table)
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
prelude::World,
query::{Has, With},
};
use alloc::{vec, vec::Vec};
#[test]
fn filters_modify_access() {
let mut filters = DefaultQueryFilters::empty();
filters.register_disabling_component(ComponentId::new(1));
// A component access with an unrelated component
let mut component_access = FilteredAccess::<ComponentId>::default();
component_access
.access_mut()
.add_component_read(ComponentId::new(2));
let mut applied_access = component_access.clone();
filters.modify_access(&mut applied_access);
assert_eq!(0, applied_access.with_filters().count());
assert_eq!(
vec![ComponentId::new(1)],
applied_access.without_filters().collect::<Vec<_>>()
);
// We add a with filter, now we expect to see both filters
component_access.and_with(ComponentId::new(4));
let mut applied_access = component_access.clone();
filters.modify_access(&mut applied_access);
assert_eq!(
vec![ComponentId::new(4)],
applied_access.with_filters().collect::<Vec<_>>()
);
assert_eq!(
vec![ComponentId::new(1)],
applied_access.without_filters().collect::<Vec<_>>()
);
let copy = component_access.clone();
// We add a rule targeting a default component, that filter should no longer be added
component_access.and_with(ComponentId::new(1));
let mut applied_access = component_access.clone();
filters.modify_access(&mut applied_access);
assert_eq!(
vec![ComponentId::new(1), ComponentId::new(4)],
applied_access.with_filters().collect::<Vec<_>>()
);
assert_eq!(0, applied_access.without_filters().count());
// Archetypal access should also filter rules
component_access = copy.clone();
component_access
.access_mut()
.add_archetypal(ComponentId::new(1));
let mut applied_access = component_access.clone();
filters.modify_access(&mut applied_access);
assert_eq!(
vec![ComponentId::new(4)],
applied_access.with_filters().collect::<Vec<_>>()
);
assert_eq!(0, applied_access.without_filters().count());
}
#[derive(Component)]
struct CustomDisabled;
#[test]
fn multiple_disabling_components() {
let mut world = World::new();
world.register_disabling_component::<CustomDisabled>();
world.spawn_empty();
world.spawn(Disabled);
world.spawn(CustomDisabled);
world.spawn((Disabled, CustomDisabled));
let mut query = world.query::<()>();
assert_eq!(1, query.iter(&world).count());
let mut query = world.query_filtered::<(), With<Disabled>>();
assert_eq!(1, query.iter(&world).count());
let mut query = world.query::<Has<Disabled>>();
assert_eq!(2, query.iter(&world).count());
let mut query = world.query_filtered::<(), With<CustomDisabled>>();
assert_eq!(1, query.iter(&world).count());
let mut query = world.query::<Has<CustomDisabled>>();
assert_eq!(2, query.iter(&world).count());
let mut query = world.query_filtered::<(), (With<Disabled>, With<CustomDisabled>)>();
assert_eq!(1, query.iter(&world).count());
let mut query = world.query::<(Has<Disabled>, Has<CustomDisabled>)>();
assert_eq!(4, query.iter(&world).count());
}
}

249
vendor/bevy_ecs/src/error/bevy_error.rs vendored Normal file
View File

@@ -0,0 +1,249 @@
use alloc::boxed::Box;
use core::{
error::Error,
fmt::{Debug, Display},
};
/// The built in "universal" Bevy error type. This has a blanket [`From`] impl for any type that implements Rust's [`Error`],
/// meaning it can be used as a "catch all" error.
///
/// # Backtraces
///
/// When used with the `backtrace` Cargo feature, it will capture a backtrace when the error is constructed (generally in the [`From`] impl]).
/// When printed, the backtrace will be displayed. By default, the backtrace will be trimmed down to filter out noise. To see the full backtrace,
/// set the `BEVY_BACKTRACE=full` environment variable.
///
/// # Usage
///
/// ```
/// # use bevy_ecs::prelude::*;
///
/// fn fallible_system() -> Result<(), BevyError> {
/// // This will result in Rust's built-in ParseIntError, which will automatically
/// // be converted into a BevyError.
/// let parsed: usize = "I am not a number".parse()?;
/// Ok(())
/// }
/// ```
pub struct BevyError {
inner: Box<InnerBevyError>,
}
impl BevyError {
/// Attempts to downcast the internal error to the given type.
pub fn downcast_ref<E: Error + 'static>(&self) -> Option<&E> {
self.inner.error.downcast_ref::<E>()
}
fn format_backtrace(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
#[cfg(feature = "backtrace")]
{
let f = _f;
let backtrace = &self.inner.backtrace;
if let std::backtrace::BacktraceStatus::Captured = backtrace.status() {
let full_backtrace = std::env::var("BEVY_BACKTRACE").is_ok_and(|val| val == "full");
let backtrace_str = alloc::string::ToString::to_string(backtrace);
let mut skip_next_location_line = false;
for line in backtrace_str.split('\n') {
if !full_backtrace {
if skip_next_location_line {
if line.starts_with(" at") {
continue;
}
skip_next_location_line = false;
}
if line.contains("std::backtrace_rs::backtrace::") {
skip_next_location_line = true;
continue;
}
if line.contains("std::backtrace::Backtrace::") {
skip_next_location_line = true;
continue;
}
if line.contains("<bevy_ecs::error::bevy_error::BevyError as core::convert::From<E>>::from") {
skip_next_location_line = true;
continue;
}
if line.contains("<core::result::Result<T,F> as core::ops::try_trait::FromResidual<core::result::Result<core::convert::Infallible,E>>>::from_residual") {
skip_next_location_line = true;
continue;
}
if line.contains("__rust_begin_short_backtrace") {
break;
}
if line.contains("bevy_ecs::observer::Observers::invoke::{{closure}}") {
break;
}
}
writeln!(f, "{}", line)?;
}
if !full_backtrace {
if std::thread::panicking() {
SKIP_NORMAL_BACKTRACE.set(true);
}
writeln!(f, "{FILTER_MESSAGE}")?;
}
}
}
Ok(())
}
}
/// This type exists (rather than having a `BevyError(Box<dyn InnerBevyError)`) to make [`BevyError`] use a "thin pointer" instead of
/// a "fat pointer", which reduces the size of our Result by a usize. This does introduce an extra indirection, but error handling is a "cold path".
/// We don't need to optimize it to that degree.
/// PERF: We could probably have the best of both worlds with a "custom vtable" impl, but thats not a huge priority right now and the code simplicity
/// of the current impl is nice.
struct InnerBevyError {
error: Box<dyn Error + Send + Sync + 'static>,
#[cfg(feature = "backtrace")]
backtrace: std::backtrace::Backtrace,
}
// NOTE: writing the impl this way gives us From<&str> ... nice!
impl<E> From<E> for BevyError
where
Box<dyn Error + Send + Sync + 'static>: From<E>,
{
#[cold]
fn from(error: E) -> Self {
BevyError {
inner: Box::new(InnerBevyError {
error: error.into(),
#[cfg(feature = "backtrace")]
backtrace: std::backtrace::Backtrace::capture(),
}),
}
}
}
impl Display for BevyError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
writeln!(f, "{}", self.inner.error)?;
self.format_backtrace(f)?;
Ok(())
}
}
impl Debug for BevyError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
writeln!(f, "{:?}", self.inner.error)?;
self.format_backtrace(f)?;
Ok(())
}
}
#[cfg(feature = "backtrace")]
const FILTER_MESSAGE: &str = "note: Some \"noisy\" backtrace lines have been filtered out. Run with `BEVY_BACKTRACE=full` for a verbose backtrace.";
#[cfg(feature = "backtrace")]
std::thread_local! {
static SKIP_NORMAL_BACKTRACE: core::cell::Cell<bool> =
const { core::cell::Cell::new(false) };
}
/// When called, this will skip the currently configured panic hook when a [`BevyError`] backtrace has already been printed.
#[cfg(feature = "backtrace")]
#[expect(clippy::print_stdout, reason = "Allowed behind `std` feature gate.")]
pub fn bevy_error_panic_hook(
current_hook: impl Fn(&std::panic::PanicHookInfo),
) -> impl Fn(&std::panic::PanicHookInfo) {
move |info| {
if SKIP_NORMAL_BACKTRACE.replace(false) {
if let Some(payload) = info.payload().downcast_ref::<&str>() {
std::println!("{payload}");
} else if let Some(payload) = info.payload().downcast_ref::<alloc::string::String>() {
std::println!("{payload}");
}
return;
}
current_hook(info);
}
}
#[cfg(test)]
mod tests {
#[test]
#[cfg(not(miri))] // miri backtraces are weird
#[cfg(not(windows))] // the windows backtrace in this context is ... unhelpful and not worth testing
fn filtered_backtrace_test() {
fn i_fail() -> crate::error::Result {
let _: usize = "I am not a number".parse()?;
Ok(())
}
// SAFETY: this is not safe ... this test could run in parallel with another test
// that writes the environment variable. We either accept that so we can write this test,
// or we don't.
unsafe { std::env::set_var("RUST_BACKTRACE", "1") };
let error = i_fail().err().unwrap();
let debug_message = alloc::format!("{error:?}");
let mut lines = debug_message.lines().peekable();
assert_eq!(
"ParseIntError { kind: InvalidDigit }",
lines.next().unwrap()
);
// On mac backtraces can start with Backtrace::create
let mut skip = false;
if let Some(line) = lines.peek() {
if &line[6..] == "std::backtrace::Backtrace::create" {
skip = true;
}
}
if skip {
lines.next().unwrap();
}
let expected_lines = alloc::vec![
"bevy_ecs::error::bevy_error::tests::filtered_backtrace_test::i_fail",
"bevy_ecs::error::bevy_error::tests::filtered_backtrace_test",
"bevy_ecs::error::bevy_error::tests::filtered_backtrace_test::{{closure}}",
"core::ops::function::FnOnce::call_once",
];
for expected in expected_lines {
let line = lines.next().unwrap();
assert_eq!(&line[6..], expected);
let mut skip = false;
if let Some(line) = lines.peek() {
if line.starts_with(" at") {
skip = true;
}
}
if skip {
lines.next().unwrap();
}
}
// on linux there is a second call_once
let mut skip = false;
if let Some(line) = lines.peek() {
if &line[6..] == "core::ops::function::FnOnce::call_once" {
skip = true;
}
}
if skip {
lines.next().unwrap();
}
let mut skip = false;
if let Some(line) = lines.peek() {
if line.starts_with(" at") {
skip = true;
}
}
if skip {
lines.next().unwrap();
}
assert_eq!(super::FILTER_MESSAGE, lines.next().unwrap());
assert!(lines.next().is_none());
}
}

View File

@@ -0,0 +1,120 @@
use core::{any::type_name, fmt};
use crate::{
entity::Entity,
never::Never,
system::{entity_command::EntityCommandError, Command, EntityCommand},
world::{error::EntityMutableFetchError, World},
};
use super::{default_error_handler, BevyError, ErrorContext};
/// Takes a [`Command`] that returns a Result and uses a given error handler function to convert it into
/// a [`Command`] that internally handles an error if it occurs and returns `()`.
pub trait HandleError<Out = ()> {
/// Takes a [`Command`] that returns a Result and uses a given error handler function to convert it into
/// a [`Command`] that internally handles an error if it occurs and returns `()`.
fn handle_error_with(self, error_handler: fn(BevyError, ErrorContext)) -> impl Command;
/// Takes a [`Command`] that returns a Result and uses the default error handler function to convert it into
/// a [`Command`] that internally handles an error if it occurs and returns `()`.
fn handle_error(self) -> impl Command
where
Self: Sized,
{
self.handle_error_with(default_error_handler())
}
}
impl<C, T, E> HandleError<Result<T, E>> for C
where
C: Command<Result<T, E>>,
E: Into<BevyError>,
{
fn handle_error_with(self, error_handler: fn(BevyError, ErrorContext)) -> impl Command {
move |world: &mut World| match self.apply(world) {
Ok(_) => {}
Err(err) => (error_handler)(
err.into(),
ErrorContext::Command {
name: type_name::<C>().into(),
},
),
}
}
}
impl<C> HandleError<Never> for C
where
C: Command<Never>,
{
fn handle_error_with(self, _error_handler: fn(BevyError, ErrorContext)) -> impl Command {
move |world: &mut World| {
self.apply(world);
}
}
}
impl<C> HandleError for C
where
C: Command,
{
#[inline]
fn handle_error_with(self, _error_handler: fn(BevyError, ErrorContext)) -> impl Command {
self
}
#[inline]
fn handle_error(self) -> impl Command
where
Self: Sized,
{
self
}
}
/// Passes in a specific entity to an [`EntityCommand`], resulting in a [`Command`] that
/// internally runs the [`EntityCommand`] on that entity.
///
// NOTE: This is a separate trait from `EntityCommand` because "result-returning entity commands" and
// "non-result returning entity commands" require different implementations, so they cannot be automatically
// implemented. And this isn't the type of implementation that we want to thrust on people implementing
// EntityCommand.
pub trait CommandWithEntity<Out> {
/// Passes in a specific entity to an [`EntityCommand`], resulting in a [`Command`] that
/// internally runs the [`EntityCommand`] on that entity.
fn with_entity(self, entity: Entity) -> impl Command<Out> + HandleError<Out>;
}
impl<C> CommandWithEntity<Result<(), EntityMutableFetchError>> for C
where
C: EntityCommand,
{
fn with_entity(
self,
entity: Entity,
) -> impl Command<Result<(), EntityMutableFetchError>>
+ HandleError<Result<(), EntityMutableFetchError>> {
move |world: &mut World| -> Result<(), EntityMutableFetchError> {
let entity = world.get_entity_mut(entity)?;
self.apply(entity);
Ok(())
}
}
}
impl<C, T, Err> CommandWithEntity<Result<T, EntityCommandError<Err>>> for C
where
C: EntityCommand<Result<T, Err>>,
Err: fmt::Debug + fmt::Display + Send + Sync + 'static,
{
fn with_entity(
self,
entity: Entity,
) -> impl Command<Result<T, EntityCommandError<Err>>> + HandleError<Result<T, EntityCommandError<Err>>>
{
move |world: &mut World| {
let entity = world.get_entity_mut(entity)?;
self.apply(entity)
.map_err(EntityCommandError::CommandFailed)
}
}
}

183
vendor/bevy_ecs/src/error/handler.rs vendored Normal file
View File

@@ -0,0 +1,183 @@
#[cfg(feature = "configurable_error_handler")]
use bevy_platform::sync::OnceLock;
use core::fmt::Display;
use crate::{component::Tick, error::BevyError};
use alloc::borrow::Cow;
/// Context for a [`BevyError`] to aid in debugging.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum ErrorContext {
/// The error occurred in a system.
System {
/// The name of the system that failed.
name: Cow<'static, str>,
/// The last tick that the system was run.
last_run: Tick,
},
/// The error occurred in a run condition.
RunCondition {
/// The name of the run condition that failed.
name: Cow<'static, str>,
/// The last tick that the run condition was evaluated.
last_run: Tick,
},
/// The error occurred in a command.
Command {
/// The name of the command that failed.
name: Cow<'static, str>,
},
/// The error occurred in an observer.
Observer {
/// The name of the observer that failed.
name: Cow<'static, str>,
/// The last tick that the observer was run.
last_run: Tick,
},
}
impl Display for ErrorContext {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::System { name, .. } => {
write!(f, "System `{}` failed", name)
}
Self::Command { name } => write!(f, "Command `{}` failed", name),
Self::Observer { name, .. } => {
write!(f, "Observer `{}` failed", name)
}
Self::RunCondition { name, .. } => {
write!(f, "Run condition `{}` failed", name)
}
}
}
}
impl ErrorContext {
/// The name of the ECS construct that failed.
pub fn name(&self) -> &str {
match self {
Self::System { name, .. }
| Self::Command { name, .. }
| Self::Observer { name, .. }
| Self::RunCondition { name, .. } => name,
}
}
/// A string representation of the kind of ECS construct that failed.
///
/// This is a simpler helper used for logging.
pub fn kind(&self) -> &str {
match self {
Self::System { .. } => "system",
Self::Command { .. } => "command",
Self::Observer { .. } => "observer",
Self::RunCondition { .. } => "run condition",
}
}
}
/// A global error handler. This can be set at startup, as long as it is set before
/// any uses. This should generally be configured _before_ initializing the app.
///
/// This should be set inside of your `main` function, before initializing the Bevy app.
/// The value of this error handler can be accessed using the [`default_error_handler`] function,
/// which calls [`OnceLock::get_or_init`] to get the value.
///
/// **Note:** this is only available when the `configurable_error_handler` feature of `bevy_ecs` (or `bevy`) is enabled!
///
/// # Example
///
/// ```
/// # use bevy_ecs::error::{GLOBAL_ERROR_HANDLER, warn};
/// GLOBAL_ERROR_HANDLER.set(warn).expect("The error handler can only be set once, globally.");
/// // initialize Bevy App here
/// ```
///
/// To use this error handler in your app for custom error handling logic:
///
/// ```rust
/// use bevy_ecs::error::{default_error_handler, GLOBAL_ERROR_HANDLER, BevyError, ErrorContext, panic};
///
/// fn handle_errors(error: BevyError, ctx: ErrorContext) {
/// let error_handler = default_error_handler();
/// error_handler(error, ctx);
/// }
/// ```
///
/// # Warning
///
/// As this can *never* be overwritten, library code should never set this value.
#[cfg(feature = "configurable_error_handler")]
pub static GLOBAL_ERROR_HANDLER: OnceLock<fn(BevyError, ErrorContext)> = OnceLock::new();
/// The default error handler. This defaults to [`panic()`],
/// but if set, the [`GLOBAL_ERROR_HANDLER`] will be used instead, enabling error handler customization.
/// The `configurable_error_handler` feature must be enabled to change this from the panicking default behavior,
/// as there may be runtime overhead.
#[inline]
pub fn default_error_handler() -> fn(BevyError, ErrorContext) {
#[cfg(not(feature = "configurable_error_handler"))]
return panic;
#[cfg(feature = "configurable_error_handler")]
return *GLOBAL_ERROR_HANDLER.get_or_init(|| panic);
}
macro_rules! inner {
($call:path, $e:ident, $c:ident) => {
$call!(
"Encountered an error in {} `{}`: {}",
$c.kind(),
$c.name(),
$e
);
};
}
/// Error handler that panics with the system error.
#[track_caller]
#[inline]
pub fn panic(error: BevyError, ctx: ErrorContext) {
inner!(panic, error, ctx);
}
/// Error handler that logs the system error at the `error` level.
#[track_caller]
#[inline]
pub fn error(error: BevyError, ctx: ErrorContext) {
inner!(log::error, error, ctx);
}
/// Error handler that logs the system error at the `warn` level.
#[track_caller]
#[inline]
pub fn warn(error: BevyError, ctx: ErrorContext) {
inner!(log::warn, error, ctx);
}
/// Error handler that logs the system error at the `info` level.
#[track_caller]
#[inline]
pub fn info(error: BevyError, ctx: ErrorContext) {
inner!(log::info, error, ctx);
}
/// Error handler that logs the system error at the `debug` level.
#[track_caller]
#[inline]
pub fn debug(error: BevyError, ctx: ErrorContext) {
inner!(log::debug, error, ctx);
}
/// Error handler that logs the system error at the `trace` level.
#[track_caller]
#[inline]
pub fn trace(error: BevyError, ctx: ErrorContext) {
inner!(log::trace, error, ctx);
}
/// Error handler that ignores the system error.
#[track_caller]
#[inline]
pub fn ignore(_: BevyError, _: ErrorContext) {}

81
vendor/bevy_ecs/src/error/mod.rs vendored Normal file
View File

@@ -0,0 +1,81 @@
//! Error handling for Bevy systems, commands, and observers.
//!
//! When a system is added to a [`Schedule`], and its return type is that of [`Result`], then Bevy
//! considers those systems to be "fallible", and the ECS scheduler will special-case the [`Err`]
//! variant of the returned `Result`.
//!
//! All [`BevyError`]s returned by a system, observer or command are handled by an "error handler". By default, the
//! [`panic`] error handler function is used, resulting in a panic with the error message attached.
//!
//! You can change the default behavior by registering a custom error handler.
//! Modify the [`GLOBAL_ERROR_HANDLER`] value to set a custom error handler function for your entire app.
//! In practice, this is generally feature-flagged: panicking or loudly logging errors in development,
//! and quietly logging or ignoring them in production to avoid crashing the app.
//!
//! Bevy provides a number of pre-built error-handlers for you to use:
//!
//! - [`panic`] panics with the system error
//! - [`error`] logs the system error at the `error` level
//! - [`warn`] logs the system error at the `warn` level
//! - [`info`] logs the system error at the `info` level
//! - [`debug`] logs the system error at the `debug` level
//! - [`trace`] logs the system error at the `trace` level
//! - [`ignore`] ignores the system error
//!
//! However, you can use any custom error handler logic by providing your own function (or
//! non-capturing closure that coerces to the function signature) as long as it matches the
//! signature:
//!
//! ```rust,ignore
//! fn(BevyError, ErrorContext)
//! ```
//!
//! The [`ErrorContext`] allows you to access additional details relevant to providing
//! context surrounding the error such as the system's [`name`] in your error messages.
//!
//! Remember to turn on the `configurable_error_handler` feature to set a global error handler!
//!
//! ```rust, ignore
//! use bevy_ecs::error::{GLOBAL_ERROR_HANDLER, BevyError, ErrorContext};
//! use log::trace;
//!
//! fn my_error_handler(error: BevyError, ctx: ErrorContext) {
//! if ctx.name().ends_with("plz_ignore") {
//! trace!("Nothing to see here, move along.");
//! return;
//! }
//! bevy_ecs::error::error(error, ctx);
//! }
//!
//! fn main() {
//! // This requires the "configurable_error_handler" feature to be enabled to be in scope.
//! GLOBAL_ERROR_HANDLER.set(my_error_handler).expect("The error handler can only be set once.");
//!
//! // Initialize your Bevy App here
//! }
//! ```
//!
//! If you need special handling of individual fallible systems, you can use Bevy's [`system piping
//! feature`] to capture the [`Result`] output of the system and handle it accordingly.
//!
//! When working with commands, you can handle the result of each command separately using the [`HandleError::handle_error_with`] method.
//!
//! [`Schedule`]: crate::schedule::Schedule
//! [`panic`]: panic()
//! [`World`]: crate::world::World
//! [`System`]: crate::system::System
//! [`name`]: crate::system::System::name
//! [`system piping feature`]: crate::system::In
mod bevy_error;
mod command_handling;
mod handler;
pub use bevy_error::*;
pub use command_handling::*;
pub use handler::*;
/// A result type for use in fallible systems, commands and observers.
///
/// The [`BevyError`] type is a type-erased error type with optional Bevy-specific diagnostics.
pub type Result<T = (), E = BevyError> = core::result::Result<T, E>;

184
vendor/bevy_ecs/src/event/base.rs vendored Normal file
View File

@@ -0,0 +1,184 @@
use crate::change_detection::MaybeLocation;
use crate::component::ComponentId;
use crate::world::World;
use crate::{component::Component, traversal::Traversal};
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::Reflect;
use core::{
cmp::Ordering,
fmt,
hash::{Hash, Hasher},
marker::PhantomData,
};
/// Something that "happens" and might be read / observed by app logic.
///
/// Events can be stored in an [`Events<E>`] resource
/// You can conveniently access events using the [`EventReader`] and [`EventWriter`] system parameter.
///
/// Events can also be "triggered" on a [`World`], which will then cause any [`Observer`] of that trigger to run.
///
/// Events must be thread-safe.
///
/// ## Derive
/// This trait can be derived.
/// Adding `auto_propagate` sets [`Self::AUTO_PROPAGATE`] to true.
/// Adding `traversal = "X"` sets [`Self::Traversal`] to be of type "X".
///
/// ```
/// use bevy_ecs::prelude::*;
///
/// #[derive(Event)]
/// #[event(auto_propagate)]
/// struct MyEvent;
/// ```
///
///
/// [`World`]: crate::world::World
/// [`ComponentId`]: crate::component::ComponentId
/// [`Observer`]: crate::observer::Observer
/// [`Events<E>`]: super::Events
/// [`EventReader`]: super::EventReader
/// [`EventWriter`]: super::EventWriter
#[diagnostic::on_unimplemented(
message = "`{Self}` is not an `Event`",
label = "invalid `Event`",
note = "consider annotating `{Self}` with `#[derive(Event)]`"
)]
pub trait Event: Send + Sync + 'static {
/// The component that describes which Entity to propagate this event to next, when [propagation] is enabled.
///
/// [propagation]: crate::observer::Trigger::propagate
type Traversal: Traversal<Self>;
/// When true, this event will always attempt to propagate when [triggered], without requiring a call
/// to [`Trigger::propagate`].
///
/// [triggered]: crate::system::Commands::trigger_targets
/// [`Trigger::propagate`]: crate::observer::Trigger::propagate
const AUTO_PROPAGATE: bool = false;
/// Generates the [`ComponentId`] for this event type.
///
/// If this type has already been registered,
/// this will return the existing [`ComponentId`].
///
/// This is used by various dynamically typed observer APIs,
/// such as [`World::trigger_targets_dynamic`].
///
/// # Warning
///
/// This method should not be overridden by implementors,
/// and should always correspond to the implementation of [`component_id`](Event::component_id).
fn register_component_id(world: &mut World) -> ComponentId {
world.register_component::<EventWrapperComponent<Self>>()
}
/// Fetches the [`ComponentId`] for this event type,
/// if it has already been generated.
///
/// This is used by various dynamically typed observer APIs,
/// such as [`World::trigger_targets_dynamic`].
///
/// # Warning
///
/// This method should not be overridden by implementors,
/// and should always correspond to the implementation of [`register_component_id`](Event::register_component_id).
fn component_id(world: &World) -> Option<ComponentId> {
world.component_id::<EventWrapperComponent<Self>>()
}
}
/// An internal type that implements [`Component`] for a given [`Event`] type.
///
/// This exists so we can easily get access to a unique [`ComponentId`] for each [`Event`] type,
/// without requiring that [`Event`] types implement [`Component`] directly.
/// [`ComponentId`] is used internally as a unique identitifier for events because they are:
///
/// - Unique to each event type.
/// - Can be quickly generated and looked up.
/// - Are compatible with dynamic event types, which aren't backed by a Rust type.
///
/// This type is an implementation detail and should never be made public.
// TODO: refactor events to store their metadata on distinct entities, rather than using `ComponentId`
#[derive(Component)]
struct EventWrapperComponent<E: Event + ?Sized>(PhantomData<E>);
/// An `EventId` uniquely identifies an event stored in a specific [`World`].
///
/// An `EventId` can among other things be used to trace the flow of an event from the point it was
/// sent to the point it was processed. `EventId`s increase monotonically by send order.
///
/// [`World`]: crate::world::World
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect),
reflect(Clone, Debug, PartialEq, Hash)
)]
pub struct EventId<E: Event> {
/// Uniquely identifies the event associated with this ID.
// This value corresponds to the order in which each event was added to the world.
pub id: usize,
/// The source code location that triggered this event.
pub caller: MaybeLocation,
#[cfg_attr(feature = "bevy_reflect", reflect(ignore, clone))]
pub(super) _marker: PhantomData<E>,
}
impl<E: Event> Copy for EventId<E> {}
impl<E: Event> Clone for EventId<E> {
fn clone(&self) -> Self {
*self
}
}
impl<E: Event> fmt::Display for EventId<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
<Self as fmt::Debug>::fmt(self, f)
}
}
impl<E: Event> fmt::Debug for EventId<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"event<{}>#{}",
core::any::type_name::<E>().split("::").last().unwrap(),
self.id,
)
}
}
impl<E: Event> PartialEq for EventId<E> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl<E: Event> Eq for EventId<E> {}
impl<E: Event> PartialOrd for EventId<E> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<E: Event> Ord for EventId<E> {
fn cmp(&self, other: &Self) -> Ordering {
self.id.cmp(&other.id)
}
}
impl<E: Event> Hash for EventId<E> {
fn hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(&self.id, state);
}
}
#[derive(Debug)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
pub(crate) struct EventInstance<E: Event> {
pub event_id: EventId<E>,
pub event: E,
}

422
vendor/bevy_ecs/src/event/collections.rs vendored Normal file
View File

@@ -0,0 +1,422 @@
use alloc::vec::Vec;
use bevy_ecs::{
change_detection::MaybeLocation,
event::{Event, EventCursor, EventId, EventInstance},
resource::Resource,
};
use core::{
marker::PhantomData,
ops::{Deref, DerefMut},
};
#[cfg(feature = "bevy_reflect")]
use {
bevy_ecs::reflect::ReflectResource,
bevy_reflect::{std_traits::ReflectDefault, Reflect},
};
/// An event collection that represents the events that occurred within the last two
/// [`Events::update`] calls.
/// Events can be written to using an [`EventWriter`]
/// and are typically cheaply read using an [`EventReader`].
///
/// Each event can be consumed by multiple systems, in parallel,
/// with consumption tracked by the [`EventReader`] on a per-system basis.
///
/// If no [ordering](https://github.com/bevyengine/bevy/blob/main/examples/ecs/ecs_guide.rs)
/// is applied between writing and reading systems, there is a risk of a race condition.
/// This means that whether the events arrive before or after the next [`Events::update`] is unpredictable.
///
/// This collection is meant to be paired with a system that calls
/// [`Events::update`] exactly once per update/frame.
///
/// [`event_update_system`] is a system that does this, typically initialized automatically using
/// [`add_event`](https://docs.rs/bevy/*/bevy/app/struct.App.html#method.add_event).
/// [`EventReader`]s are expected to read events from this collection at least once per loop/frame.
/// Events will persist across a single frame boundary and so ordering of event producers and
/// consumers is not critical (although poorly-planned ordering may cause accumulating lag).
/// If events are not handled by the end of the frame after they are updated, they will be
/// dropped silently.
///
/// # Example
/// ```
/// use bevy_ecs::event::{Event, Events};
///
/// #[derive(Event)]
/// struct MyEvent {
/// value: usize
/// }
///
/// // setup
/// let mut events = Events::<MyEvent>::default();
/// let mut cursor = events.get_cursor();
///
/// // run this once per update/frame
/// events.update();
///
/// // somewhere else: send an event
/// events.send(MyEvent { value: 1 });
///
/// // somewhere else: read the events
/// for event in cursor.read(&events) {
/// assert_eq!(event.value, 1)
/// }
///
/// // events are only processed once per reader
/// assert_eq!(cursor.read(&events).count(), 0);
/// ```
///
/// # Details
///
/// [`Events`] is implemented using a variation of a double buffer strategy.
/// Each call to [`update`](Events::update) swaps buffers and clears out the oldest one.
/// - [`EventReader`]s will read events from both buffers.
/// - [`EventReader`]s that read at least once per update will never drop events.
/// - [`EventReader`]s that read once within two updates might still receive some events
/// - [`EventReader`]s that read after two updates are guaranteed to drop all events that occurred
/// before those updates.
///
/// The buffers in [`Events`] will grow indefinitely if [`update`](Events::update) is never called.
///
/// An alternative call pattern would be to call [`update`](Events::update)
/// manually across frames to control when events are cleared.
/// This complicates consumption and risks ever-expanding memory usage if not cleaned up,
/// but can be done by adding your event as a resource instead of using
/// [`add_event`](https://docs.rs/bevy/*/bevy/app/struct.App.html#method.add_event).
///
/// [Example usage.](https://github.com/bevyengine/bevy/blob/latest/examples/ecs/event.rs)
/// [Example usage standalone.](https://github.com/bevyengine/bevy/blob/latest/crates/bevy_ecs/examples/events.rs)
///
/// [`EventReader`]: super::EventReader
/// [`EventWriter`]: super::EventWriter
/// [`event_update_system`]: super::event_update_system
#[derive(Debug, Resource)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Resource, Default))]
pub struct Events<E: Event> {
/// Holds the oldest still active events.
/// Note that `a.start_event_count + a.len()` should always be equal to `events_b.start_event_count`.
pub(crate) events_a: EventSequence<E>,
/// Holds the newer events.
pub(crate) events_b: EventSequence<E>,
pub(crate) event_count: usize,
}
// Derived Default impl would incorrectly require E: Default
impl<E: Event> Default for Events<E> {
fn default() -> Self {
Self {
events_a: Default::default(),
events_b: Default::default(),
event_count: Default::default(),
}
}
}
impl<E: Event> Events<E> {
/// Returns the index of the oldest event stored in the event buffer.
pub fn oldest_event_count(&self) -> usize {
self.events_a.start_event_count
}
/// "Sends" an `event` by writing it to the current event buffer.
/// [`EventReader`](super::EventReader)s can then read the event.
/// This method returns the [ID](`EventId`) of the sent `event`.
#[track_caller]
pub fn send(&mut self, event: E) -> EventId<E> {
self.send_with_caller(event, MaybeLocation::caller())
}
pub(crate) fn send_with_caller(&mut self, event: E, caller: MaybeLocation) -> EventId<E> {
let event_id = EventId {
id: self.event_count,
caller,
_marker: PhantomData,
};
#[cfg(feature = "detailed_trace")]
tracing::trace!("Events::send() -> id: {}", event_id);
let event_instance = EventInstance { event_id, event };
self.events_b.push(event_instance);
self.event_count += 1;
event_id
}
/// Sends a list of `events` all at once, which can later be read by [`EventReader`](super::EventReader)s.
/// This is more efficient than sending each event individually.
/// This method returns the [IDs](`EventId`) of the sent `events`.
#[track_caller]
pub fn send_batch(&mut self, events: impl IntoIterator<Item = E>) -> SendBatchIds<E> {
let last_count = self.event_count;
self.extend(events);
SendBatchIds {
last_count,
event_count: self.event_count,
_marker: PhantomData,
}
}
/// Sends the default value of the event. Useful when the event is an empty struct.
/// This method returns the [ID](`EventId`) of the sent `event`.
#[track_caller]
pub fn send_default(&mut self) -> EventId<E>
where
E: Default,
{
self.send(Default::default())
}
/// Gets a new [`EventCursor`]. This will include all events already in the event buffers.
pub fn get_cursor(&self) -> EventCursor<E> {
EventCursor::default()
}
/// Gets a new [`EventCursor`]. This will ignore all events already in the event buffers.
/// It will read all future events.
pub fn get_cursor_current(&self) -> EventCursor<E> {
EventCursor {
last_event_count: self.event_count,
..Default::default()
}
}
/// Swaps the event buffers and clears the oldest event buffer. In general, this should be
/// called once per frame/update.
///
/// If you need access to the events that were removed, consider using [`Events::update_drain`].
pub fn update(&mut self) {
core::mem::swap(&mut self.events_a, &mut self.events_b);
self.events_b.clear();
self.events_b.start_event_count = self.event_count;
debug_assert_eq!(
self.events_a.start_event_count + self.events_a.len(),
self.events_b.start_event_count
);
}
/// Swaps the event buffers and drains the oldest event buffer, returning an iterator
/// of all events that were removed. In general, this should be called once per frame/update.
///
/// If you do not need to take ownership of the removed events, use [`Events::update`] instead.
#[must_use = "If you do not need the returned events, call .update() instead."]
pub fn update_drain(&mut self) -> impl Iterator<Item = E> + '_ {
core::mem::swap(&mut self.events_a, &mut self.events_b);
let iter = self.events_b.events.drain(..);
self.events_b.start_event_count = self.event_count;
debug_assert_eq!(
self.events_a.start_event_count + self.events_a.len(),
self.events_b.start_event_count
);
iter.map(|e| e.event)
}
#[inline]
fn reset_start_event_count(&mut self) {
self.events_a.start_event_count = self.event_count;
self.events_b.start_event_count = self.event_count;
}
/// Removes all events.
#[inline]
pub fn clear(&mut self) {
self.reset_start_event_count();
self.events_a.clear();
self.events_b.clear();
}
/// Returns the number of events currently stored in the event buffer.
#[inline]
pub fn len(&self) -> usize {
self.events_a.len() + self.events_b.len()
}
/// Returns true if there are no events currently stored in the event buffer.
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
/// Creates a draining iterator that removes all events.
pub fn drain(&mut self) -> impl Iterator<Item = E> + '_ {
self.reset_start_event_count();
// Drain the oldest events first, then the newest
self.events_a
.drain(..)
.chain(self.events_b.drain(..))
.map(|i| i.event)
}
/// Iterates over events that happened since the last "update" call.
/// WARNING: You probably don't want to use this call. In most cases you should use an
/// [`EventReader`]. You should only use this if you know you only need to consume events
/// between the last `update()` call and your call to `iter_current_update_events`.
/// If events happen outside that window, they will not be handled. For example, any events that
/// happen after this call and before the next `update()` call will be dropped.
///
/// [`EventReader`]: super::EventReader
pub fn iter_current_update_events(&self) -> impl ExactSizeIterator<Item = &E> {
self.events_b.iter().map(|i| &i.event)
}
/// Get a specific event by id if it still exists in the events buffer.
pub fn get_event(&self, id: usize) -> Option<(&E, EventId<E>)> {
if id < self.oldest_event_count() {
return None;
}
let sequence = self.sequence(id);
let index = id.saturating_sub(sequence.start_event_count);
sequence
.get(index)
.map(|instance| (&instance.event, instance.event_id))
}
/// Which event buffer is this event id a part of.
fn sequence(&self, id: usize) -> &EventSequence<E> {
if id < self.events_b.start_event_count {
&self.events_a
} else {
&self.events_b
}
}
}
impl<E: Event> Extend<E> for Events<E> {
#[track_caller]
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = E>,
{
let old_count = self.event_count;
let mut event_count = self.event_count;
let events = iter.into_iter().map(|event| {
let event_id = EventId {
id: event_count,
caller: MaybeLocation::caller(),
_marker: PhantomData,
};
event_count += 1;
EventInstance { event_id, event }
});
self.events_b.extend(events);
if old_count != event_count {
#[cfg(feature = "detailed_trace")]
tracing::trace!(
"Events::extend() -> ids: ({}..{})",
self.event_count,
event_count
);
}
self.event_count = event_count;
}
}
#[derive(Debug)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Default))]
pub(crate) struct EventSequence<E: Event> {
pub(crate) events: Vec<EventInstance<E>>,
pub(crate) start_event_count: usize,
}
// Derived Default impl would incorrectly require E: Default
impl<E: Event> Default for EventSequence<E> {
fn default() -> Self {
Self {
events: Default::default(),
start_event_count: Default::default(),
}
}
}
impl<E: Event> Deref for EventSequence<E> {
type Target = Vec<EventInstance<E>>;
fn deref(&self) -> &Self::Target {
&self.events
}
}
impl<E: Event> DerefMut for EventSequence<E> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.events
}
}
/// [`Iterator`] over sent [`EventIds`](`EventId`) from a batch.
pub struct SendBatchIds<E> {
last_count: usize,
event_count: usize,
_marker: PhantomData<E>,
}
impl<E: Event> Iterator for SendBatchIds<E> {
type Item = EventId<E>;
fn next(&mut self) -> Option<Self::Item> {
if self.last_count >= self.event_count {
return None;
}
let result = Some(EventId {
id: self.last_count,
caller: MaybeLocation::caller(),
_marker: PhantomData,
});
self.last_count += 1;
result
}
}
impl<E: Event> ExactSizeIterator for SendBatchIds<E> {
fn len(&self) -> usize {
self.event_count.saturating_sub(self.last_count)
}
}
#[cfg(test)]
mod tests {
use crate::event::Events;
use bevy_ecs_macros::Event;
#[test]
fn iter_current_update_events_iterates_over_current_events() {
#[derive(Event, Clone)]
struct TestEvent;
let mut test_events = Events::<TestEvent>::default();
// Starting empty
assert_eq!(test_events.len(), 0);
assert_eq!(test_events.iter_current_update_events().count(), 0);
test_events.update();
// Sending one event
test_events.send(TestEvent);
assert_eq!(test_events.len(), 1);
assert_eq!(test_events.iter_current_update_events().count(), 1);
test_events.update();
// Sending two events on the next frame
test_events.send(TestEvent);
test_events.send(TestEvent);
assert_eq!(test_events.len(), 3); // Events are double-buffered, so we see 1 + 2 = 3
assert_eq!(test_events.iter_current_update_events().count(), 2);
test_events.update();
// Sending zero events
assert_eq!(test_events.len(), 2); // Events are double-buffered, so we see 2 + 0 = 2
assert_eq!(test_events.iter_current_update_events().count(), 0);
}
}

View File

@@ -0,0 +1,140 @@
use bevy_ecs::event::{
Event, EventIterator, EventIteratorWithId, EventMutIterator, EventMutIteratorWithId, Events,
};
#[cfg(feature = "multi_threaded")]
use bevy_ecs::event::{EventMutParIter, EventParIter};
use core::marker::PhantomData;
/// Stores the state for an [`EventReader`] or [`EventMutator`].
///
/// Access to the [`Events<E>`] resource is required to read any incoming events.
///
/// In almost all cases, you should just use an [`EventReader`] or [`EventMutator`],
/// which will automatically manage the state for you.
///
/// However, this type can be useful if you need to manually track events,
/// such as when you're attempting to send and receive events of the same type in the same system.
///
/// # Example
///
/// ```
/// use bevy_ecs::prelude::*;
/// use bevy_ecs::event::{Event, Events, EventCursor};
///
/// #[derive(Event, Clone, Debug)]
/// struct MyEvent;
///
/// /// A system that both sends and receives events using a [`Local`] [`EventCursor`].
/// fn send_and_receive_events(
/// // The `Local` `SystemParam` stores state inside the system itself, rather than in the world.
/// // `EventCursor<T>` is the internal state of `EventMutator<T>`, which tracks which events have been seen.
/// mut local_event_reader: Local<EventCursor<MyEvent>>,
/// // We can access the `Events` resource mutably, allowing us to both read and write its contents.
/// mut events: ResMut<Events<MyEvent>>,
/// ) {
/// // We must collect the events to resend, because we can't mutate events while we're iterating over the events.
/// let mut events_to_resend = Vec::new();
///
/// for event in local_event_reader.read(&mut events) {
/// events_to_resend.push(event.clone());
/// }
///
/// for event in events_to_resend {
/// events.send(MyEvent);
/// }
/// }
///
/// # bevy_ecs::system::assert_is_system(send_and_receive_events);
/// ```
///
/// [`EventReader`]: super::EventReader
/// [`EventMutator`]: super::EventMutator
#[derive(Debug)]
pub struct EventCursor<E: Event> {
pub(super) last_event_count: usize,
pub(super) _marker: PhantomData<E>,
}
impl<E: Event> Default for EventCursor<E> {
fn default() -> Self {
EventCursor {
last_event_count: 0,
_marker: Default::default(),
}
}
}
impl<E: Event> Clone for EventCursor<E> {
fn clone(&self) -> Self {
EventCursor {
last_event_count: self.last_event_count,
_marker: PhantomData,
}
}
}
impl<E: Event> EventCursor<E> {
/// See [`EventReader::read`](super::EventReader::read)
pub fn read<'a>(&'a mut self, events: &'a Events<E>) -> EventIterator<'a, E> {
self.read_with_id(events).without_id()
}
/// See [`EventMutator::read`](super::EventMutator::read)
pub fn read_mut<'a>(&'a mut self, events: &'a mut Events<E>) -> EventMutIterator<'a, E> {
self.read_mut_with_id(events).without_id()
}
/// See [`EventReader::read_with_id`](super::EventReader::read_with_id)
pub fn read_with_id<'a>(&'a mut self, events: &'a Events<E>) -> EventIteratorWithId<'a, E> {
EventIteratorWithId::new(self, events)
}
/// See [`EventMutator::read_with_id`](super::EventMutator::read_with_id)
pub fn read_mut_with_id<'a>(
&'a mut self,
events: &'a mut Events<E>,
) -> EventMutIteratorWithId<'a, E> {
EventMutIteratorWithId::new(self, events)
}
/// See [`EventReader::par_read`](super::EventReader::par_read)
#[cfg(feature = "multi_threaded")]
pub fn par_read<'a>(&'a mut self, events: &'a Events<E>) -> EventParIter<'a, E> {
EventParIter::new(self, events)
}
/// See [`EventMutator::par_read`](super::EventMutator::par_read)
#[cfg(feature = "multi_threaded")]
pub fn par_read_mut<'a>(&'a mut self, events: &'a mut Events<E>) -> EventMutParIter<'a, E> {
EventMutParIter::new(self, events)
}
/// See [`EventReader::len`](super::EventReader::len)
pub fn len(&self, events: &Events<E>) -> usize {
// The number of events in this reader is the difference between the most recent event
// and the last event seen by it. This will be at most the number of events contained
// with the events (any others have already been dropped)
// TODO: Warn when there are dropped events, or return e.g. a `Result<usize, (usize, usize)>`
events
.event_count
.saturating_sub(self.last_event_count)
.min(events.len())
}
/// Amount of events we missed.
pub fn missed_events(&self, events: &Events<E>) -> usize {
events
.oldest_event_count()
.saturating_sub(self.last_event_count)
}
/// See [`EventReader::is_empty()`](super::EventReader::is_empty)
pub fn is_empty(&self, events: &Events<E>) -> bool {
self.len(events) == 0
}
/// See [`EventReader::clear()`](super::EventReader::clear)
pub fn clear(&mut self, events: &Events<E>) {
self.last_event_count = events.event_count;
}
}

281
vendor/bevy_ecs/src/event/iterators.rs vendored Normal file
View File

@@ -0,0 +1,281 @@
#[cfg(feature = "multi_threaded")]
use bevy_ecs::batching::BatchingStrategy;
use bevy_ecs::event::{Event, EventCursor, EventId, EventInstance, Events};
use core::{iter::Chain, slice::Iter};
/// An iterator that yields any unread events from an [`EventReader`](super::EventReader) or [`EventCursor`].
#[derive(Debug)]
pub struct EventIterator<'a, E: Event> {
iter: EventIteratorWithId<'a, E>,
}
impl<'a, E: Event> Iterator for EventIterator<'a, E> {
type Item = &'a E;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|(event, _)| event)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
fn count(self) -> usize {
self.iter.count()
}
fn last(self) -> Option<Self::Item>
where
Self: Sized,
{
self.iter.last().map(|(event, _)| event)
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.iter.nth(n).map(|(event, _)| event)
}
}
impl<'a, E: Event> ExactSizeIterator for EventIterator<'a, E> {
fn len(&self) -> usize {
self.iter.len()
}
}
/// An iterator that yields any unread events (and their IDs) from an [`EventReader`](super::EventReader) or [`EventCursor`].
#[derive(Debug)]
pub struct EventIteratorWithId<'a, E: Event> {
reader: &'a mut EventCursor<E>,
chain: Chain<Iter<'a, EventInstance<E>>, Iter<'a, EventInstance<E>>>,
unread: usize,
}
impl<'a, E: Event> EventIteratorWithId<'a, E> {
/// Creates a new iterator that yields any `events` that have not yet been seen by `reader`.
pub fn new(reader: &'a mut EventCursor<E>, events: &'a Events<E>) -> Self {
let a_index = reader
.last_event_count
.saturating_sub(events.events_a.start_event_count);
let b_index = reader
.last_event_count
.saturating_sub(events.events_b.start_event_count);
let a = events.events_a.get(a_index..).unwrap_or_default();
let b = events.events_b.get(b_index..).unwrap_or_default();
let unread_count = a.len() + b.len();
// Ensure `len` is implemented correctly
debug_assert_eq!(unread_count, reader.len(events));
reader.last_event_count = events.event_count - unread_count;
// Iterate the oldest first, then the newer events
let chain = a.iter().chain(b.iter());
Self {
reader,
chain,
unread: unread_count,
}
}
/// Iterate over only the events.
pub fn without_id(self) -> EventIterator<'a, E> {
EventIterator { iter: self }
}
}
impl<'a, E: Event> Iterator for EventIteratorWithId<'a, E> {
type Item = (&'a E, EventId<E>);
fn next(&mut self) -> Option<Self::Item> {
match self
.chain
.next()
.map(|instance| (&instance.event, instance.event_id))
{
Some(item) => {
#[cfg(feature = "detailed_trace")]
tracing::trace!("EventReader::iter() -> {}", item.1);
self.reader.last_event_count += 1;
self.unread -= 1;
Some(item)
}
None => None,
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.chain.size_hint()
}
fn count(self) -> usize {
self.reader.last_event_count += self.unread;
self.unread
}
fn last(self) -> Option<Self::Item>
where
Self: Sized,
{
let EventInstance { event_id, event } = self.chain.last()?;
self.reader.last_event_count += self.unread;
Some((event, *event_id))
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
if let Some(EventInstance { event_id, event }) = self.chain.nth(n) {
self.reader.last_event_count += n + 1;
self.unread -= n + 1;
Some((event, *event_id))
} else {
self.reader.last_event_count += self.unread;
self.unread = 0;
None
}
}
}
impl<'a, E: Event> ExactSizeIterator for EventIteratorWithId<'a, E> {
fn len(&self) -> usize {
self.unread
}
}
/// A parallel iterator over `Event`s.
#[cfg(feature = "multi_threaded")]
#[derive(Debug)]
pub struct EventParIter<'a, E: Event> {
reader: &'a mut EventCursor<E>,
slices: [&'a [EventInstance<E>]; 2],
batching_strategy: BatchingStrategy,
#[cfg(not(target_arch = "wasm32"))]
unread: usize,
}
#[cfg(feature = "multi_threaded")]
impl<'a, E: Event> EventParIter<'a, E> {
/// Creates a new parallel iterator over `events` that have not yet been seen by `reader`.
pub fn new(reader: &'a mut EventCursor<E>, events: &'a Events<E>) -> Self {
let a_index = reader
.last_event_count
.saturating_sub(events.events_a.start_event_count);
let b_index = reader
.last_event_count
.saturating_sub(events.events_b.start_event_count);
let a = events.events_a.get(a_index..).unwrap_or_default();
let b = events.events_b.get(b_index..).unwrap_or_default();
let unread_count = a.len() + b.len();
// Ensure `len` is implemented correctly
debug_assert_eq!(unread_count, reader.len(events));
reader.last_event_count = events.event_count - unread_count;
Self {
reader,
slices: [a, b],
batching_strategy: BatchingStrategy::default(),
#[cfg(not(target_arch = "wasm32"))]
unread: unread_count,
}
}
/// Changes the batching strategy used when iterating.
///
/// For more information on how this affects the resultant iteration, see
/// [`BatchingStrategy`].
pub fn batching_strategy(mut self, strategy: BatchingStrategy) -> Self {
self.batching_strategy = strategy;
self
}
/// Runs the provided closure for each unread event in parallel.
///
/// Unlike normal iteration, the event order is not guaranteed in any form.
///
/// # Panics
/// If the [`ComputeTaskPool`] is not initialized. If using this from an event reader that is being
/// initialized and run from the ECS scheduler, this should never panic.
///
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
pub fn for_each<FN: Fn(&'a E) + Send + Sync + Clone>(self, func: FN) {
self.for_each_with_id(move |e, _| func(e));
}
/// Runs the provided closure for each unread event in parallel, like [`for_each`](Self::for_each),
/// but additionally provides the `EventId` to the closure.
///
/// Note that the order of iteration is not guaranteed, but `EventId`s are ordered by send order.
///
/// # Panics
/// If the [`ComputeTaskPool`] is not initialized. If using this from an event reader that is being
/// initialized and run from the ECS scheduler, this should never panic.
///
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
#[cfg_attr(
target_arch = "wasm32",
expect(unused_mut, reason = "not mutated on this target")
)]
pub fn for_each_with_id<FN: Fn(&'a E, EventId<E>) + Send + Sync + Clone>(mut self, func: FN) {
#[cfg(target_arch = "wasm32")]
{
self.into_iter().for_each(|(e, i)| func(e, i));
}
#[cfg(not(target_arch = "wasm32"))]
{
let pool = bevy_tasks::ComputeTaskPool::get();
let thread_count = pool.thread_num();
if thread_count <= 1 {
return self.into_iter().for_each(|(e, i)| func(e, i));
}
let batch_size = self
.batching_strategy
.calc_batch_size(|| self.len(), thread_count);
let chunks = self.slices.map(|s| s.chunks_exact(batch_size));
let remainders = chunks.each_ref().map(core::slice::ChunksExact::remainder);
pool.scope(|scope| {
for batch in chunks.into_iter().flatten().chain(remainders) {
let func = func.clone();
scope.spawn(async move {
for event in batch {
func(&event.event, event.event_id);
}
});
}
});
// Events are guaranteed to be read at this point.
self.reader.last_event_count += self.unread;
self.unread = 0;
}
}
/// Returns the number of [`Event`]s to be iterated.
pub fn len(&self) -> usize {
self.slices.iter().map(|s| s.len()).sum()
}
/// Returns [`true`] if there are no events remaining in this iterator.
pub fn is_empty(&self) -> bool {
self.slices.iter().all(|x| x.is_empty())
}
}
#[cfg(feature = "multi_threaded")]
impl<'a, E: Event> IntoIterator for EventParIter<'a, E> {
type IntoIter = EventIteratorWithId<'a, E>;
type Item = <Self::IntoIter as Iterator>::Item;
fn into_iter(self) -> Self::IntoIter {
let EventParIter {
reader,
slices: [a, b],
..
} = self;
let unread = a.len() + b.len();
let chain = a.iter().chain(b);
EventIteratorWithId {
reader,
chain,
unread,
}
}
}

621
vendor/bevy_ecs/src/event/mod.rs vendored Normal file
View File

@@ -0,0 +1,621 @@
//! Event handling types.
mod base;
mod collections;
mod event_cursor;
mod iterators;
mod mut_iterators;
mod mutator;
mod reader;
mod registry;
mod update;
mod writer;
pub(crate) use base::EventInstance;
pub use base::{Event, EventId};
pub use bevy_ecs_macros::Event;
pub use collections::{Events, SendBatchIds};
pub use event_cursor::EventCursor;
#[cfg(feature = "multi_threaded")]
pub use iterators::EventParIter;
pub use iterators::{EventIterator, EventIteratorWithId};
#[cfg(feature = "multi_threaded")]
pub use mut_iterators::EventMutParIter;
pub use mut_iterators::{EventMutIterator, EventMutIteratorWithId};
pub use mutator::EventMutator;
pub use reader::EventReader;
pub use registry::{EventRegistry, ShouldUpdateEvents};
pub use update::{
event_update_condition, event_update_system, signal_event_update_system, EventUpdates,
};
pub use writer::EventWriter;
#[cfg(test)]
mod tests {
use alloc::{vec, vec::Vec};
use bevy_ecs::{event::*, system::assert_is_read_only_system};
use bevy_ecs_macros::Event;
#[derive(Event, Copy, Clone, PartialEq, Eq, Debug)]
struct TestEvent {
i: usize,
}
#[derive(Event, Clone, PartialEq, Debug, Default)]
struct EmptyTestEvent;
fn get_events<E: Event + Clone>(events: &Events<E>, cursor: &mut EventCursor<E>) -> Vec<E> {
cursor.read(events).cloned().collect::<Vec<E>>()
}
#[test]
fn test_events() {
let mut events = Events::<TestEvent>::default();
let event_0 = TestEvent { i: 0 };
let event_1 = TestEvent { i: 1 };
let event_2 = TestEvent { i: 2 };
// this reader will miss event_0 and event_1 because it wont read them over the course of
// two updates
let mut reader_missed: EventCursor<TestEvent> = events.get_cursor();
let mut reader_a: EventCursor<TestEvent> = events.get_cursor();
events.send(event_0);
assert_eq!(
get_events(&events, &mut reader_a),
vec![event_0],
"reader_a created before event receives event"
);
assert_eq!(
get_events(&events, &mut reader_a),
vec![],
"second iteration of reader_a created before event results in zero events"
);
let mut reader_b: EventCursor<TestEvent> = events.get_cursor();
assert_eq!(
get_events(&events, &mut reader_b),
vec![event_0],
"reader_b created after event receives event"
);
assert_eq!(
get_events(&events, &mut reader_b),
vec![],
"second iteration of reader_b created after event results in zero events"
);
events.send(event_1);
let mut reader_c = events.get_cursor();
assert_eq!(
get_events(&events, &mut reader_c),
vec![event_0, event_1],
"reader_c created after two events receives both events"
);
assert_eq!(
get_events(&events, &mut reader_c),
vec![],
"second iteration of reader_c created after two event results in zero events"
);
assert_eq!(
get_events(&events, &mut reader_a),
vec![event_1],
"reader_a receives next unread event"
);
events.update();
let mut reader_d = events.get_cursor();
events.send(event_2);
assert_eq!(
get_events(&events, &mut reader_a),
vec![event_2],
"reader_a receives event created after update"
);
assert_eq!(
get_events(&events, &mut reader_b),
vec![event_1, event_2],
"reader_b receives events created before and after update"
);
assert_eq!(
get_events(&events, &mut reader_d),
vec![event_0, event_1, event_2],
"reader_d receives all events created before and after update"
);
events.update();
assert_eq!(
get_events(&events, &mut reader_missed),
vec![event_2],
"reader_missed missed events unread after two update() calls"
);
}
// Events Collection
fn events_clear_and_read_impl(clear_func: impl FnOnce(&mut Events<TestEvent>)) {
let mut events = Events::<TestEvent>::default();
let mut reader = events.get_cursor();
assert!(reader.read(&events).next().is_none());
events.send(TestEvent { i: 0 });
assert_eq!(*reader.read(&events).next().unwrap(), TestEvent { i: 0 });
assert_eq!(reader.read(&events).next(), None);
events.send(TestEvent { i: 1 });
clear_func(&mut events);
assert!(reader.read(&events).next().is_none());
events.send(TestEvent { i: 2 });
events.update();
events.send(TestEvent { i: 3 });
assert!(reader
.read(&events)
.eq([TestEvent { i: 2 }, TestEvent { i: 3 }].iter()));
}
#[test]
fn test_events_clear_and_read() {
events_clear_and_read_impl(Events::clear);
}
#[test]
fn test_events_drain_and_read() {
events_clear_and_read_impl(|events| {
assert!(events
.drain()
.eq(vec![TestEvent { i: 0 }, TestEvent { i: 1 }].into_iter()));
});
}
#[test]
fn test_events_send_default() {
let mut events = Events::<EmptyTestEvent>::default();
events.send_default();
let mut reader = events.get_cursor();
assert_eq!(get_events(&events, &mut reader), vec![EmptyTestEvent]);
}
#[test]
fn test_send_events_ids() {
let mut events = Events::<TestEvent>::default();
let event_0 = TestEvent { i: 0 };
let event_1 = TestEvent { i: 1 };
let event_2 = TestEvent { i: 2 };
let event_0_id = events.send(event_0);
assert_eq!(
events.get_event(event_0_id.id),
Some((&event_0, event_0_id)),
"Getting a sent event by ID should return the original event"
);
let mut event_ids = events.send_batch([event_1, event_2]);
let event_id = event_ids.next().expect("Event 1 must have been sent");
assert_eq!(
events.get_event(event_id.id),
Some((&event_1, event_id)),
"Getting a sent event by ID should return the original event"
);
let event_id = event_ids.next().expect("Event 2 must have been sent");
assert_eq!(
events.get_event(event_id.id),
Some((&event_2, event_id)),
"Getting a sent event by ID should return the original event"
);
assert!(
event_ids.next().is_none(),
"Only sent two events; got more than two IDs"
);
}
#[test]
fn test_event_registry_can_add_and_remove_events_to_world() {
use bevy_ecs::prelude::*;
let mut world = World::new();
EventRegistry::register_event::<TestEvent>(&mut world);
let has_events = world.get_resource::<Events<TestEvent>>().is_some();
assert!(has_events, "Should have the events resource");
EventRegistry::deregister_events::<TestEvent>(&mut world);
let has_events = world.get_resource::<Events<TestEvent>>().is_some();
assert!(!has_events, "Should not have the events resource");
}
#[test]
fn test_events_update_drain() {
let mut events = Events::<TestEvent>::default();
let mut reader = events.get_cursor();
events.send(TestEvent { i: 0 });
events.send(TestEvent { i: 1 });
assert_eq!(reader.read(&events).count(), 2);
let mut old_events = Vec::from_iter(events.update_drain());
assert!(old_events.is_empty());
events.send(TestEvent { i: 2 });
assert_eq!(reader.read(&events).count(), 1);
old_events.extend(events.update_drain());
assert_eq!(old_events.len(), 2);
old_events.extend(events.update_drain());
assert_eq!(
old_events,
&[TestEvent { i: 0 }, TestEvent { i: 1 }, TestEvent { i: 2 }]
);
}
#[test]
fn test_events_empty() {
let mut events = Events::<TestEvent>::default();
assert!(events.is_empty());
events.send(TestEvent { i: 0 });
assert!(!events.is_empty());
events.update();
assert!(!events.is_empty());
// events are only empty after the second call to update
// due to double buffering.
events.update();
assert!(events.is_empty());
}
#[test]
fn test_events_extend_impl() {
let mut events = Events::<TestEvent>::default();
let mut reader = events.get_cursor();
events.extend(vec![TestEvent { i: 0 }, TestEvent { i: 1 }]);
assert!(reader
.read(&events)
.eq([TestEvent { i: 0 }, TestEvent { i: 1 }].iter()));
}
// Cursor
#[test]
fn test_event_cursor_read() {
let mut events = Events::<TestEvent>::default();
let mut cursor = events.get_cursor();
assert!(cursor.read(&events).next().is_none());
events.send(TestEvent { i: 0 });
let sent_event = cursor.read(&events).next().unwrap();
assert_eq!(sent_event, &TestEvent { i: 0 });
assert!(cursor.read(&events).next().is_none());
events.send(TestEvent { i: 2 });
let sent_event = cursor.read(&events).next().unwrap();
assert_eq!(sent_event, &TestEvent { i: 2 });
assert!(cursor.read(&events).next().is_none());
events.clear();
assert!(cursor.read(&events).next().is_none());
}
#[test]
fn test_event_cursor_read_mut() {
let mut events = Events::<TestEvent>::default();
let mut write_cursor = events.get_cursor();
let mut read_cursor = events.get_cursor();
assert!(write_cursor.read_mut(&mut events).next().is_none());
assert!(read_cursor.read(&events).next().is_none());
events.send(TestEvent { i: 0 });
let sent_event = write_cursor.read_mut(&mut events).next().unwrap();
assert_eq!(sent_event, &mut TestEvent { i: 0 });
*sent_event = TestEvent { i: 1 }; // Mutate whole event
assert_eq!(
read_cursor.read(&events).next().unwrap(),
&TestEvent { i: 1 }
);
assert!(read_cursor.read(&events).next().is_none());
events.send(TestEvent { i: 2 });
let sent_event = write_cursor.read_mut(&mut events).next().unwrap();
assert_eq!(sent_event, &mut TestEvent { i: 2 });
sent_event.i = 3; // Mutate sub value
assert_eq!(
read_cursor.read(&events).next().unwrap(),
&TestEvent { i: 3 }
);
assert!(read_cursor.read(&events).next().is_none());
events.clear();
assert!(write_cursor.read(&events).next().is_none());
assert!(read_cursor.read(&events).next().is_none());
}
#[test]
fn test_event_cursor_clear() {
let mut events = Events::<TestEvent>::default();
let mut reader = events.get_cursor();
events.send(TestEvent { i: 0 });
assert_eq!(reader.len(&events), 1);
reader.clear(&events);
assert_eq!(reader.len(&events), 0);
}
#[test]
fn test_event_cursor_len_update() {
let mut events = Events::<TestEvent>::default();
events.send(TestEvent { i: 0 });
events.send(TestEvent { i: 0 });
let reader = events.get_cursor();
assert_eq!(reader.len(&events), 2);
events.update();
events.send(TestEvent { i: 0 });
assert_eq!(reader.len(&events), 3);
events.update();
assert_eq!(reader.len(&events), 1);
events.update();
assert!(reader.is_empty(&events));
}
#[test]
fn test_event_cursor_len_current() {
let mut events = Events::<TestEvent>::default();
events.send(TestEvent { i: 0 });
let reader = events.get_cursor_current();
assert!(reader.is_empty(&events));
events.send(TestEvent { i: 0 });
assert_eq!(reader.len(&events), 1);
assert!(!reader.is_empty(&events));
}
#[test]
fn test_event_cursor_iter_len_updated() {
let mut events = Events::<TestEvent>::default();
events.send(TestEvent { i: 0 });
events.send(TestEvent { i: 1 });
events.send(TestEvent { i: 2 });
let mut reader = events.get_cursor();
let mut iter = reader.read(&events);
assert_eq!(iter.len(), 3);
iter.next();
assert_eq!(iter.len(), 2);
iter.next();
assert_eq!(iter.len(), 1);
iter.next();
assert_eq!(iter.len(), 0);
}
#[test]
fn test_event_cursor_len_empty() {
let events = Events::<TestEvent>::default();
assert_eq!(events.get_cursor().len(&events), 0);
assert!(events.get_cursor().is_empty(&events));
}
#[test]
fn test_event_cursor_len_filled() {
let mut events = Events::<TestEvent>::default();
events.send(TestEvent { i: 0 });
assert_eq!(events.get_cursor().len(&events), 1);
assert!(!events.get_cursor().is_empty(&events));
}
#[cfg(feature = "multi_threaded")]
#[test]
fn test_event_cursor_par_read() {
use crate::prelude::*;
use core::sync::atomic::{AtomicUsize, Ordering};
#[derive(Resource)]
struct Counter(AtomicUsize);
let mut world = World::new();
world.init_resource::<Events<TestEvent>>();
for _ in 0..100 {
world.send_event(TestEvent { i: 1 });
}
let mut schedule = Schedule::default();
schedule.add_systems(
|mut cursor: Local<EventCursor<TestEvent>>,
events: Res<Events<TestEvent>>,
counter: ResMut<Counter>| {
cursor.par_read(&events).for_each(|event| {
counter.0.fetch_add(event.i, Ordering::Relaxed);
});
},
);
world.insert_resource(Counter(AtomicUsize::new(0)));
schedule.run(&mut world);
let counter = world.remove_resource::<Counter>().unwrap();
assert_eq!(counter.0.into_inner(), 100);
world.insert_resource(Counter(AtomicUsize::new(0)));
schedule.run(&mut world);
let counter = world.remove_resource::<Counter>().unwrap();
assert_eq!(
counter.0.into_inner(),
0,
"par_read should have consumed events but didn't"
);
}
#[cfg(feature = "multi_threaded")]
#[test]
fn test_event_cursor_par_read_mut() {
use crate::prelude::*;
use core::sync::atomic::{AtomicUsize, Ordering};
#[derive(Resource)]
struct Counter(AtomicUsize);
let mut world = World::new();
world.init_resource::<Events<TestEvent>>();
for _ in 0..100 {
world.send_event(TestEvent { i: 1 });
}
let mut schedule = Schedule::default();
schedule.add_systems(
|mut cursor: Local<EventCursor<TestEvent>>,
mut events: ResMut<Events<TestEvent>>,
counter: ResMut<Counter>| {
cursor.par_read_mut(&mut events).for_each(|event| {
event.i += 1;
counter.0.fetch_add(event.i, Ordering::Relaxed);
});
},
);
world.insert_resource(Counter(AtomicUsize::new(0)));
schedule.run(&mut world);
let counter = world.remove_resource::<Counter>().unwrap();
assert_eq!(counter.0.into_inner(), 200, "Initial run failed");
world.insert_resource(Counter(AtomicUsize::new(0)));
schedule.run(&mut world);
let counter = world.remove_resource::<Counter>().unwrap();
assert_eq!(
counter.0.into_inner(),
0,
"par_read_mut should have consumed events but didn't"
);
}
// Reader & Mutator
#[test]
fn ensure_reader_readonly() {
fn reader_system(_: EventReader<EmptyTestEvent>) {}
assert_is_read_only_system(reader_system);
}
#[test]
fn test_event_reader_iter_last() {
use bevy_ecs::prelude::*;
let mut world = World::new();
world.init_resource::<Events<TestEvent>>();
let mut reader =
IntoSystem::into_system(|mut events: EventReader<TestEvent>| -> Option<TestEvent> {
events.read().last().copied()
});
reader.initialize(&mut world);
let last = reader.run((), &mut world);
assert!(last.is_none(), "EventReader should be empty");
world.send_event(TestEvent { i: 0 });
let last = reader.run((), &mut world);
assert_eq!(last, Some(TestEvent { i: 0 }));
world.send_event(TestEvent { i: 1 });
world.send_event(TestEvent { i: 2 });
world.send_event(TestEvent { i: 3 });
let last = reader.run((), &mut world);
assert_eq!(last, Some(TestEvent { i: 3 }));
let last = reader.run((), &mut world);
assert!(last.is_none(), "EventReader should be empty");
}
#[test]
fn test_event_mutator_iter_last() {
use bevy_ecs::prelude::*;
let mut world = World::new();
world.init_resource::<Events<TestEvent>>();
let mut mutator =
IntoSystem::into_system(|mut events: EventMutator<TestEvent>| -> Option<TestEvent> {
events.read().last().copied()
});
mutator.initialize(&mut world);
let last = mutator.run((), &mut world);
assert!(last.is_none(), "EventMutator should be empty");
world.send_event(TestEvent { i: 0 });
let last = mutator.run((), &mut world);
assert_eq!(last, Some(TestEvent { i: 0 }));
world.send_event(TestEvent { i: 1 });
world.send_event(TestEvent { i: 2 });
world.send_event(TestEvent { i: 3 });
let last = mutator.run((), &mut world);
assert_eq!(last, Some(TestEvent { i: 3 }));
let last = mutator.run((), &mut world);
assert!(last.is_none(), "EventMutator should be empty");
}
#[test]
fn test_event_reader_iter_nth() {
use bevy_ecs::prelude::*;
let mut world = World::new();
world.init_resource::<Events<TestEvent>>();
world.send_event(TestEvent { i: 0 });
world.send_event(TestEvent { i: 1 });
world.send_event(TestEvent { i: 2 });
world.send_event(TestEvent { i: 3 });
world.send_event(TestEvent { i: 4 });
let mut schedule = Schedule::default();
schedule.add_systems(|mut events: EventReader<TestEvent>| {
let mut iter = events.read();
assert_eq!(iter.next(), Some(&TestEvent { i: 0 }));
assert_eq!(iter.nth(2), Some(&TestEvent { i: 3 }));
assert_eq!(iter.nth(1), None);
assert!(events.is_empty());
});
schedule.run(&mut world);
}
#[test]
fn test_event_mutator_iter_nth() {
use bevy_ecs::prelude::*;
let mut world = World::new();
world.init_resource::<Events<TestEvent>>();
world.send_event(TestEvent { i: 0 });
world.send_event(TestEvent { i: 1 });
world.send_event(TestEvent { i: 2 });
world.send_event(TestEvent { i: 3 });
world.send_event(TestEvent { i: 4 });
let mut schedule = Schedule::default();
schedule.add_systems(|mut events: EventReader<TestEvent>| {
let mut iter = events.read();
assert_eq!(iter.next(), Some(&TestEvent { i: 0 }));
assert_eq!(iter.nth(2), Some(&TestEvent { i: 3 }));
assert_eq!(iter.nth(1), None);
assert!(events.is_empty());
});
schedule.run(&mut world);
}
}

View File

@@ -0,0 +1,284 @@
#[cfg(feature = "multi_threaded")]
use bevy_ecs::batching::BatchingStrategy;
use bevy_ecs::event::{Event, EventCursor, EventId, EventInstance, Events};
use core::{iter::Chain, slice::IterMut};
/// An iterator that yields any unread events from an [`EventMutator`] or [`EventCursor`].
///
/// [`EventMutator`]: super::EventMutator
#[derive(Debug)]
pub struct EventMutIterator<'a, E: Event> {
iter: EventMutIteratorWithId<'a, E>,
}
impl<'a, E: Event> Iterator for EventMutIterator<'a, E> {
type Item = &'a mut E;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|(event, _)| event)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
fn count(self) -> usize {
self.iter.count()
}
fn last(self) -> Option<Self::Item>
where
Self: Sized,
{
self.iter.last().map(|(event, _)| event)
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.iter.nth(n).map(|(event, _)| event)
}
}
impl<'a, E: Event> ExactSizeIterator for EventMutIterator<'a, E> {
fn len(&self) -> usize {
self.iter.len()
}
}
/// An iterator that yields any unread events (and their IDs) from an [`EventMutator`] or [`EventCursor`].
///
/// [`EventMutator`]: super::EventMutator
#[derive(Debug)]
pub struct EventMutIteratorWithId<'a, E: Event> {
mutator: &'a mut EventCursor<E>,
chain: Chain<IterMut<'a, EventInstance<E>>, IterMut<'a, EventInstance<E>>>,
unread: usize,
}
impl<'a, E: Event> EventMutIteratorWithId<'a, E> {
/// Creates a new iterator that yields any `events` that have not yet been seen by `mutator`.
pub fn new(mutator: &'a mut EventCursor<E>, events: &'a mut Events<E>) -> Self {
let a_index = mutator
.last_event_count
.saturating_sub(events.events_a.start_event_count);
let b_index = mutator
.last_event_count
.saturating_sub(events.events_b.start_event_count);
let a = events.events_a.get_mut(a_index..).unwrap_or_default();
let b = events.events_b.get_mut(b_index..).unwrap_or_default();
let unread_count = a.len() + b.len();
mutator.last_event_count = events.event_count - unread_count;
// Iterate the oldest first, then the newer events
let chain = a.iter_mut().chain(b.iter_mut());
Self {
mutator,
chain,
unread: unread_count,
}
}
/// Iterate over only the events.
pub fn without_id(self) -> EventMutIterator<'a, E> {
EventMutIterator { iter: self }
}
}
impl<'a, E: Event> Iterator for EventMutIteratorWithId<'a, E> {
type Item = (&'a mut E, EventId<E>);
fn next(&mut self) -> Option<Self::Item> {
match self
.chain
.next()
.map(|instance| (&mut instance.event, instance.event_id))
{
Some(item) => {
#[cfg(feature = "detailed_trace")]
tracing::trace!("EventMutator::iter() -> {}", item.1);
self.mutator.last_event_count += 1;
self.unread -= 1;
Some(item)
}
None => None,
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.chain.size_hint()
}
fn count(self) -> usize {
self.mutator.last_event_count += self.unread;
self.unread
}
fn last(self) -> Option<Self::Item>
where
Self: Sized,
{
let EventInstance { event_id, event } = self.chain.last()?;
self.mutator.last_event_count += self.unread;
Some((event, *event_id))
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
if let Some(EventInstance { event_id, event }) = self.chain.nth(n) {
self.mutator.last_event_count += n + 1;
self.unread -= n + 1;
Some((event, *event_id))
} else {
self.mutator.last_event_count += self.unread;
self.unread = 0;
None
}
}
}
impl<'a, E: Event> ExactSizeIterator for EventMutIteratorWithId<'a, E> {
fn len(&self) -> usize {
self.unread
}
}
/// A parallel iterator over `Event`s.
#[derive(Debug)]
#[cfg(feature = "multi_threaded")]
pub struct EventMutParIter<'a, E: Event> {
mutator: &'a mut EventCursor<E>,
slices: [&'a mut [EventInstance<E>]; 2],
batching_strategy: BatchingStrategy,
#[cfg(not(target_arch = "wasm32"))]
unread: usize,
}
#[cfg(feature = "multi_threaded")]
impl<'a, E: Event> EventMutParIter<'a, E> {
/// Creates a new parallel iterator over `events` that have not yet been seen by `mutator`.
pub fn new(mutator: &'a mut EventCursor<E>, events: &'a mut Events<E>) -> Self {
let a_index = mutator
.last_event_count
.saturating_sub(events.events_a.start_event_count);
let b_index = mutator
.last_event_count
.saturating_sub(events.events_b.start_event_count);
let a = events.events_a.get_mut(a_index..).unwrap_or_default();
let b = events.events_b.get_mut(b_index..).unwrap_or_default();
let unread_count = a.len() + b.len();
mutator.last_event_count = events.event_count - unread_count;
Self {
mutator,
slices: [a, b],
batching_strategy: BatchingStrategy::default(),
#[cfg(not(target_arch = "wasm32"))]
unread: unread_count,
}
}
/// Changes the batching strategy used when iterating.
///
/// For more information on how this affects the resultant iteration, see
/// [`BatchingStrategy`].
pub fn batching_strategy(mut self, strategy: BatchingStrategy) -> Self {
self.batching_strategy = strategy;
self
}
/// Runs the provided closure for each unread event in parallel.
///
/// Unlike normal iteration, the event order is not guaranteed in any form.
///
/// # Panics
/// If the [`ComputeTaskPool`] is not initialized. If using this from an event reader that is being
/// initialized and run from the ECS scheduler, this should never panic.
///
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
pub fn for_each<FN: Fn(&'a mut E) + Send + Sync + Clone>(self, func: FN) {
self.for_each_with_id(move |e, _| func(e));
}
/// Runs the provided closure for each unread event in parallel, like [`for_each`](Self::for_each),
/// but additionally provides the `EventId` to the closure.
///
/// Note that the order of iteration is not guaranteed, but `EventId`s are ordered by send order.
///
/// # Panics
/// If the [`ComputeTaskPool`] is not initialized. If using this from an event reader that is being
/// initialized and run from the ECS scheduler, this should never panic.
///
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
#[cfg_attr(
target_arch = "wasm32",
expect(unused_mut, reason = "not mutated on this target")
)]
pub fn for_each_with_id<FN: Fn(&'a mut E, EventId<E>) + Send + Sync + Clone>(
mut self,
func: FN,
) {
#[cfg(target_arch = "wasm32")]
{
self.into_iter().for_each(|(e, i)| func(e, i));
}
#[cfg(not(target_arch = "wasm32"))]
{
let pool = bevy_tasks::ComputeTaskPool::get();
let thread_count = pool.thread_num();
if thread_count <= 1 {
return self.into_iter().for_each(|(e, i)| func(e, i));
}
let batch_size = self
.batching_strategy
.calc_batch_size(|| self.len(), thread_count);
let chunks = self.slices.map(|s| s.chunks_mut(batch_size));
pool.scope(|scope| {
for batch in chunks.into_iter().flatten() {
let func = func.clone();
scope.spawn(async move {
for event in batch {
func(&mut event.event, event.event_id);
}
});
}
});
// Events are guaranteed to be read at this point.
self.mutator.last_event_count += self.unread;
self.unread = 0;
}
}
/// Returns the number of [`Event`]s to be iterated.
pub fn len(&self) -> usize {
self.slices.iter().map(|s| s.len()).sum()
}
/// Returns [`true`] if there are no events remaining in this iterator.
pub fn is_empty(&self) -> bool {
self.slices.iter().all(|x| x.is_empty())
}
}
#[cfg(feature = "multi_threaded")]
impl<'a, E: Event> IntoIterator for EventMutParIter<'a, E> {
type IntoIter = EventMutIteratorWithId<'a, E>;
type Item = <Self::IntoIter as Iterator>::Item;
fn into_iter(self) -> Self::IntoIter {
let EventMutParIter {
mutator: reader,
slices: [a, b],
..
} = self;
let unread = a.len() + b.len();
let chain = a.iter_mut().chain(b);
EventMutIteratorWithId {
mutator: reader,
chain,
unread,
}
}
}

143
vendor/bevy_ecs/src/event/mutator.rs vendored Normal file
View File

@@ -0,0 +1,143 @@
#[cfg(feature = "multi_threaded")]
use bevy_ecs::event::EventMutParIter;
use bevy_ecs::{
event::{Event, EventCursor, EventMutIterator, EventMutIteratorWithId, Events},
system::{Local, ResMut, SystemParam},
};
/// Mutably reads events of type `T` keeping track of which events have already been read
/// by each system allowing multiple systems to read the same events. Ideal for chains of systems
/// that all want to modify the same events.
///
/// # Usage
///
/// `EventMutators`s are usually declared as a [`SystemParam`].
/// ```
/// # use bevy_ecs::prelude::*;
///
/// #[derive(Event, Debug)]
/// pub struct MyEvent(pub u32); // Custom event type.
/// fn my_system(mut reader: EventMutator<MyEvent>) {
/// for event in reader.read() {
/// event.0 += 1;
/// println!("received event: {:?}", event);
/// }
/// }
/// ```
///
/// # Concurrency
///
/// Multiple systems with `EventMutator<T>` of the same event type can not run concurrently.
/// They also can not be executed in parallel with [`EventReader`] or [`EventWriter`].
///
/// # Clearing, Reading, and Peeking
///
/// Events are stored in a double buffered queue that switches each frame. This switch also clears the previous
/// frame's events. Events should be read each frame otherwise they may be lost. For manual control over this
/// behavior, see [`Events`].
///
/// Most of the time systems will want to use [`EventMutator::read()`]. This function creates an iterator over
/// all events that haven't been read yet by this system, marking the event as read in the process.
///
/// [`EventReader`]: super::EventReader
/// [`EventWriter`]: super::EventWriter
#[derive(SystemParam, Debug)]
pub struct EventMutator<'w, 's, E: Event> {
pub(super) reader: Local<'s, EventCursor<E>>,
#[system_param(validation_message = "Event not initialized")]
events: ResMut<'w, Events<E>>,
}
impl<'w, 's, E: Event> EventMutator<'w, 's, E> {
/// Iterates over the events this [`EventMutator`] has not seen yet. This updates the
/// [`EventMutator`]'s event counter, which means subsequent event reads will not include events
/// that happened before now.
pub fn read(&mut self) -> EventMutIterator<'_, E> {
self.reader.read_mut(&mut self.events)
}
/// Like [`read`](Self::read), except also returning the [`EventId`](super::EventId) of the events.
pub fn read_with_id(&mut self) -> EventMutIteratorWithId<'_, E> {
self.reader.read_mut_with_id(&mut self.events)
}
/// Returns a parallel iterator over the events this [`EventMutator`] has not seen yet.
/// See also [`for_each`](super::EventParIter::for_each).
///
/// # Example
/// ```
/// # use bevy_ecs::prelude::*;
/// # use std::sync::atomic::{AtomicUsize, Ordering};
///
/// #[derive(Event)]
/// struct MyEvent {
/// value: usize,
/// }
///
/// #[derive(Resource, Default)]
/// struct Counter(AtomicUsize);
///
/// // setup
/// let mut world = World::new();
/// world.init_resource::<Events<MyEvent>>();
/// world.insert_resource(Counter::default());
///
/// let mut schedule = Schedule::default();
/// schedule.add_systems(|mut events: EventMutator<MyEvent>, counter: Res<Counter>| {
/// events.par_read().for_each(|MyEvent { value }| {
/// counter.0.fetch_add(*value, Ordering::Relaxed);
/// });
/// });
/// for value in 0..100 {
/// world.send_event(MyEvent { value });
/// }
/// schedule.run(&mut world);
/// let Counter(counter) = world.remove_resource::<Counter>().unwrap();
/// // all events were processed
/// assert_eq!(counter.into_inner(), 4950);
/// ```
#[cfg(feature = "multi_threaded")]
pub fn par_read(&mut self) -> EventMutParIter<'_, E> {
self.reader.par_read_mut(&mut self.events)
}
/// Determines the number of events available to be read from this [`EventMutator`] without consuming any.
pub fn len(&self) -> usize {
self.reader.len(&self.events)
}
/// Returns `true` if there are no events available to read.
///
/// # Example
///
/// The following example shows a useful pattern where some behavior is triggered if new events are available.
/// [`EventMutator::clear()`] is used so the same events don't re-trigger the behavior the next time the system runs.
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// #[derive(Event)]
/// struct CollisionEvent;
///
/// fn play_collision_sound(mut events: EventMutator<CollisionEvent>) {
/// if !events.is_empty() {
/// events.clear();
/// // Play a sound
/// }
/// }
/// # bevy_ecs::system::assert_is_system(play_collision_sound);
/// ```
pub fn is_empty(&self) -> bool {
self.reader.is_empty(&self.events)
}
/// Consumes all available events.
///
/// This means these events will not appear in calls to [`EventMutator::read()`] or
/// [`EventMutator::read_with_id()`] and [`EventMutator::is_empty()`] will return `true`.
///
/// For usage, see [`EventMutator::is_empty()`].
pub fn clear(&mut self) {
self.reader.clear(&self.events);
}
}

115
vendor/bevy_ecs/src/event/reader.rs vendored Normal file
View File

@@ -0,0 +1,115 @@
#[cfg(feature = "multi_threaded")]
use bevy_ecs::event::EventParIter;
use bevy_ecs::{
event::{Event, EventCursor, EventIterator, EventIteratorWithId, Events},
system::{Local, Res, SystemParam},
};
/// Reads events of type `T` in order and tracks which events have already been read.
///
/// # Concurrency
///
/// Unlike [`EventWriter<T>`], systems with `EventReader<T>` param can be executed concurrently
/// (but not concurrently with `EventWriter<T>` or `EventMutator<T>` systems for the same event type).
///
/// [`EventWriter<T>`]: super::EventWriter
#[derive(SystemParam, Debug)]
pub struct EventReader<'w, 's, E: Event> {
pub(super) reader: Local<'s, EventCursor<E>>,
#[system_param(validation_message = "Event not initialized")]
events: Res<'w, Events<E>>,
}
impl<'w, 's, E: Event> EventReader<'w, 's, E> {
/// Iterates over the events this [`EventReader`] has not seen yet. This updates the
/// [`EventReader`]'s event counter, which means subsequent event reads will not include events
/// that happened before now.
pub fn read(&mut self) -> EventIterator<'_, E> {
self.reader.read(&self.events)
}
/// Like [`read`](Self::read), except also returning the [`EventId`](super::EventId) of the events.
pub fn read_with_id(&mut self) -> EventIteratorWithId<'_, E> {
self.reader.read_with_id(&self.events)
}
/// Returns a parallel iterator over the events this [`EventReader`] has not seen yet.
/// See also [`for_each`](EventParIter::for_each).
///
/// # Example
/// ```
/// # use bevy_ecs::prelude::*;
/// # use std::sync::atomic::{AtomicUsize, Ordering};
///
/// #[derive(Event)]
/// struct MyEvent {
/// value: usize,
/// }
///
/// #[derive(Resource, Default)]
/// struct Counter(AtomicUsize);
///
/// // setup
/// let mut world = World::new();
/// world.init_resource::<Events<MyEvent>>();
/// world.insert_resource(Counter::default());
///
/// let mut schedule = Schedule::default();
/// schedule.add_systems(|mut events: EventReader<MyEvent>, counter: Res<Counter>| {
/// events.par_read().for_each(|MyEvent { value }| {
/// counter.0.fetch_add(*value, Ordering::Relaxed);
/// });
/// });
/// for value in 0..100 {
/// world.send_event(MyEvent { value });
/// }
/// schedule.run(&mut world);
/// let Counter(counter) = world.remove_resource::<Counter>().unwrap();
/// // all events were processed
/// assert_eq!(counter.into_inner(), 4950);
/// ```
#[cfg(feature = "multi_threaded")]
pub fn par_read(&mut self) -> EventParIter<'_, E> {
self.reader.par_read(&self.events)
}
/// Determines the number of events available to be read from this [`EventReader`] without consuming any.
pub fn len(&self) -> usize {
self.reader.len(&self.events)
}
/// Returns `true` if there are no events available to read.
///
/// # Example
///
/// The following example shows a useful pattern where some behavior is triggered if new events are available.
/// [`EventReader::clear()`] is used so the same events don't re-trigger the behavior the next time the system runs.
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// #[derive(Event)]
/// struct CollisionEvent;
///
/// fn play_collision_sound(mut events: EventReader<CollisionEvent>) {
/// if !events.is_empty() {
/// events.clear();
/// // Play a sound
/// }
/// }
/// # bevy_ecs::system::assert_is_system(play_collision_sound);
/// ```
pub fn is_empty(&self) -> bool {
self.reader.is_empty(&self.events)
}
/// Consumes all available events.
///
/// This means these events will not appear in calls to [`EventReader::read()`] or
/// [`EventReader::read_with_id()`] and [`EventReader::is_empty()`] will return `true`.
///
/// For usage, see [`EventReader::is_empty()`].
pub fn clear(&mut self) {
self.reader.clear(&self.events);
}
}

93
vendor/bevy_ecs/src/event/registry.rs vendored Normal file
View File

@@ -0,0 +1,93 @@
use alloc::vec::Vec;
use bevy_ecs::{
change_detection::{DetectChangesMut, MutUntyped},
component::{ComponentId, Tick},
event::{Event, Events},
resource::Resource,
world::World,
};
#[doc(hidden)]
struct RegisteredEvent {
component_id: ComponentId,
// Required to flush the secondary buffer and drop events even if left unchanged.
previously_updated: bool,
// SAFETY: The component ID and the function must be used to fetch the Events<T> resource
// of the same type initialized in `register_event`, or improper type casts will occur.
update: unsafe fn(MutUntyped),
}
/// A registry of all of the [`Events`] in the [`World`], used by [`event_update_system`](crate::event::update::event_update_system)
/// to update all of the events.
#[derive(Resource, Default)]
pub struct EventRegistry {
/// Should the events be updated?
///
/// This field is generally automatically updated by the [`signal_event_update_system`](crate::event::update::signal_event_update_system).
pub should_update: ShouldUpdateEvents,
event_updates: Vec<RegisteredEvent>,
}
/// Controls whether or not the events in an [`EventRegistry`] should be updated.
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub enum ShouldUpdateEvents {
/// Without any fixed timestep, events should always be updated each frame.
#[default]
Always,
/// We need to wait until at least one pass of the fixed update schedules to update the events.
Waiting,
/// At least one pass of the fixed update schedules has occurred, and the events are ready to be updated.
Ready,
}
impl EventRegistry {
/// Registers an event type to be updated in a given [`World`]
///
/// If no instance of the [`EventRegistry`] exists in the world, this will add one - otherwise it will use
/// the existing instance.
pub fn register_event<T: Event>(world: &mut World) {
// By initializing the resource here, we can be sure that it is present,
// and receive the correct, up-to-date `ComponentId` even if it was previously removed.
let component_id = world.init_resource::<Events<T>>();
let mut registry = world.get_resource_or_init::<Self>();
registry.event_updates.push(RegisteredEvent {
component_id,
previously_updated: false,
update: |ptr| {
// SAFETY: The resource was initialized with the type Events<T>.
unsafe { ptr.with_type::<Events<T>>() }
.bypass_change_detection()
.update();
},
});
}
/// Updates all of the registered events in the World.
pub fn run_updates(&mut self, world: &mut World, last_change_tick: Tick) {
for registered_event in &mut self.event_updates {
// Bypass the type ID -> Component ID lookup with the cached component ID.
if let Some(events) = world.get_resource_mut_by_id(registered_event.component_id) {
let has_changed = events.has_changed_since(last_change_tick);
if registered_event.previously_updated || has_changed {
// SAFETY: The update function pointer is called with the resource
// fetched from the same component ID.
unsafe { (registered_event.update)(events) };
// Always set to true if the events have changed, otherwise disable running on the second invocation
// to wait for more changes.
registered_event.previously_updated =
has_changed || !registered_event.previously_updated;
}
}
}
}
/// Removes an event from the world and it's associated [`EventRegistry`].
pub fn deregister_events<T: Event>(world: &mut World) {
let component_id = world.init_resource::<Events<T>>();
let mut registry = world.get_resource_or_init::<Self>();
registry
.event_updates
.retain(|e| e.component_id != component_id);
world.remove_resource::<Events<T>>();
}
}

61
vendor/bevy_ecs/src/event/update.rs vendored Normal file
View File

@@ -0,0 +1,61 @@
use bevy_ecs::{
change_detection::Mut,
component::Tick,
event::EventRegistry,
system::{Local, Res, ResMut},
world::World,
};
use bevy_ecs_macros::SystemSet;
#[cfg(feature = "bevy_reflect")]
use core::hash::Hash;
use super::registry::ShouldUpdateEvents;
#[doc(hidden)]
#[derive(SystemSet, Clone, Debug, PartialEq, Eq, Hash)]
pub struct EventUpdates;
/// Signals the [`event_update_system`] to run after `FixedUpdate` systems.
///
/// This will change the behavior of the [`EventRegistry`] to only run after a fixed update cycle has passed.
/// Normally, this will simply run every frame.
pub fn signal_event_update_system(signal: Option<ResMut<EventRegistry>>) {
if let Some(mut registry) = signal {
registry.should_update = ShouldUpdateEvents::Ready;
}
}
/// A system that calls [`Events::update`](super::Events::update) on all registered [`Events`][super::Events] in the world.
pub fn event_update_system(world: &mut World, mut last_change_tick: Local<Tick>) {
if world.contains_resource::<EventRegistry>() {
world.resource_scope(|world, mut registry: Mut<EventRegistry>| {
registry.run_updates(world, *last_change_tick);
registry.should_update = match registry.should_update {
// If we're always updating, keep doing so.
ShouldUpdateEvents::Always => ShouldUpdateEvents::Always,
// Disable the system until signal_event_update_system runs again.
ShouldUpdateEvents::Waiting | ShouldUpdateEvents::Ready => {
ShouldUpdateEvents::Waiting
}
};
});
}
*last_change_tick = world.change_tick();
}
/// A run condition for [`event_update_system`].
///
/// If [`signal_event_update_system`] has been run at least once,
/// we will wait for it to be run again before updating the events.
///
/// Otherwise, we will always update the events.
pub fn event_update_condition(maybe_signal: Option<Res<EventRegistry>>) -> bool {
match maybe_signal {
Some(signal) => match signal.should_update {
ShouldUpdateEvents::Always | ShouldUpdateEvents::Ready => true,
ShouldUpdateEvents::Waiting => false,
},
None => true,
}
}

135
vendor/bevy_ecs/src/event/writer.rs vendored Normal file
View File

@@ -0,0 +1,135 @@
use bevy_ecs::{
event::{Event, EventId, Events, SendBatchIds},
system::{ResMut, SystemParam},
};
/// Sends events of type `T`.
///
/// # Usage
///
/// `EventWriter`s are usually declared as a [`SystemParam`].
/// ```
/// # use bevy_ecs::prelude::*;
///
/// #[derive(Event)]
/// pub struct MyEvent; // Custom event type.
/// fn my_system(mut writer: EventWriter<MyEvent>) {
/// writer.write(MyEvent);
/// }
///
/// # bevy_ecs::system::assert_is_system(my_system);
/// ```
/// # Observers
///
/// "Buffered" Events, such as those sent directly in [`Events`] or written using [`EventWriter`], do _not_ automatically
/// trigger any [`Observer`]s watching for that event, as each [`Event`] has different requirements regarding _if_ it will
/// be triggered, and if so, _when_ it will be triggered in the schedule.
///
/// # Concurrency
///
/// `EventWriter` param has [`ResMut<Events<T>>`](Events) inside. So two systems declaring `EventWriter<T>` params
/// for the same event type won't be executed concurrently.
///
/// # Untyped events
///
/// `EventWriter` can only write events of one specific type, which must be known at compile-time.
/// This is not a problem most of the time, but you may find a situation where you cannot know
/// ahead of time every kind of event you'll need to send. In this case, you can use the "type-erased event" pattern.
///
/// ```
/// # use bevy_ecs::{prelude::*, event::Events};
/// # #[derive(Event)]
/// # pub struct MyEvent;
/// fn send_untyped(mut commands: Commands) {
/// // Send an event of a specific type without having to declare that
/// // type as a SystemParam.
/// //
/// // Effectively, we're just moving the type parameter from the /type/ to the /method/,
/// // which allows one to do all kinds of clever things with type erasure, such as sending
/// // custom events to unknown 3rd party plugins (modding API).
/// //
/// // NOTE: the event won't actually be sent until commands get applied during
/// // apply_deferred.
/// commands.queue(|w: &mut World| {
/// w.send_event(MyEvent);
/// });
/// }
/// ```
/// Note that this is considered *non-idiomatic*, and should only be used when `EventWriter` will not work.
///
/// [`Observer`]: crate::observer::Observer
#[derive(SystemParam)]
pub struct EventWriter<'w, E: Event> {
#[system_param(validation_message = "Event not initialized")]
events: ResMut<'w, Events<E>>,
}
impl<'w, E: Event> EventWriter<'w, E> {
/// Writes an `event`, which can later be read by [`EventReader`](super::EventReader)s.
/// This method returns the [ID](`EventId`) of the written `event`.
///
/// See [`Events`] for details.
#[doc(alias = "send")]
#[track_caller]
pub fn write(&mut self, event: E) -> EventId<E> {
self.events.send(event)
}
/// Sends a list of `events` all at once, which can later be read by [`EventReader`](super::EventReader)s.
/// This is more efficient than sending each event individually.
/// This method returns the [IDs](`EventId`) of the written `events`.
///
/// See [`Events`] for details.
#[doc(alias = "send_batch")]
#[track_caller]
pub fn write_batch(&mut self, events: impl IntoIterator<Item = E>) -> SendBatchIds<E> {
self.events.send_batch(events)
}
/// Writes the default value of the event. Useful when the event is an empty struct.
/// This method returns the [ID](`EventId`) of the written `event`.
///
/// See [`Events`] for details.
#[doc(alias = "send_default")]
#[track_caller]
pub fn write_default(&mut self) -> EventId<E>
where
E: Default,
{
self.events.send_default()
}
/// Sends an `event`, which can later be read by [`EventReader`](super::EventReader)s.
/// This method returns the [ID](`EventId`) of the sent `event`.
///
/// See [`Events`] for details.
#[deprecated(since = "0.16.0", note = "Use `EventWriter::write` instead.")]
#[track_caller]
pub fn send(&mut self, event: E) -> EventId<E> {
self.write(event)
}
/// Sends a list of `events` all at once, which can later be read by [`EventReader`](super::EventReader)s.
/// This is more efficient than sending each event individually.
/// This method returns the [IDs](`EventId`) of the sent `events`.
///
/// See [`Events`] for details.
#[deprecated(since = "0.16.0", note = "Use `EventWriter::write_batch` instead.")]
#[track_caller]
pub fn send_batch(&mut self, events: impl IntoIterator<Item = E>) -> SendBatchIds<E> {
self.write_batch(events)
}
/// Sends the default value of the event. Useful when the event is an empty struct.
/// This method returns the [ID](`EventId`) of the sent `event`.
///
/// See [`Events`] for details.
#[deprecated(since = "0.16.0", note = "Use `EventWriter::write_default` instead.")]
#[track_caller]
pub fn send_default(&mut self) -> EventId<E>
where
E: Default,
{
self.write_default()
}
}

1073
vendor/bevy_ecs/src/hierarchy.rs vendored Normal file

File diff suppressed because it is too large Load Diff

29
vendor/bevy_ecs/src/identifier/error.rs vendored Normal file
View File

@@ -0,0 +1,29 @@
//! Error types for [`super::Identifier`] conversions. An ID can be converted
//! to various kinds, but these can fail if they are not valid forms of those
//! kinds. The error type in this module encapsulates the various failure modes.
use core::fmt;
/// An Error type for [`super::Identifier`], mostly for providing error
/// handling for conversions of an ID to a type abstracting over the ID bits.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[non_exhaustive]
pub enum IdentifierError {
/// A given ID has an invalid value for initializing to a [`crate::identifier::Identifier`].
InvalidIdentifier,
/// A given ID has an invalid configuration of bits for converting to an [`crate::entity::Entity`].
InvalidEntityId(u64),
}
impl fmt::Display for IdentifierError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidIdentifier => write!(
f,
"The given id contains a zero value high component, which is invalid"
),
Self::InvalidEntityId(_) => write!(f, "The given id is not a valid entity."),
}
}
}
impl core::error::Error for IdentifierError {}

11
vendor/bevy_ecs/src/identifier/kinds.rs vendored Normal file
View File

@@ -0,0 +1,11 @@
/// The kinds of ID that [`super::Identifier`] can represent. Each
/// variant imposes different usages of the low/high segments
/// of the ID.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum IdKind {
/// An ID variant that is compatible with [`crate::entity::Entity`].
Entity = 0,
/// A future ID variant.
Placeholder = 0b1000_0000,
}

233
vendor/bevy_ecs/src/identifier/masks.rs vendored Normal file
View File

@@ -0,0 +1,233 @@
use core::num::NonZero;
use super::kinds::IdKind;
/// Mask for extracting the value portion of a 32-bit high segment. This
/// yields 31-bits of total value, as the final bit (the most significant)
/// is reserved as a flag bit. Can be negated to extract the flag bit.
pub(crate) const HIGH_MASK: u32 = 0x7FFF_FFFF;
/// Abstraction over masks needed to extract values/components of an [`super::Identifier`].
pub(crate) struct IdentifierMask;
impl IdentifierMask {
/// Returns the low component from a `u64` value
#[inline(always)]
pub(crate) const fn get_low(value: u64) -> u32 {
// This will truncate to the lowest 32 bits
value as u32
}
/// Returns the high component from a `u64` value
#[inline(always)]
pub(crate) const fn get_high(value: u64) -> u32 {
// This will discard the lowest 32 bits
(value >> u32::BITS) as u32
}
/// Pack a low and high `u32` values into a single `u64` value.
#[inline(always)]
pub(crate) const fn pack_into_u64(low: u32, high: u32) -> u64 {
((high as u64) << u32::BITS) | (low as u64)
}
/// Pack the [`IdKind`] bits into a high segment.
#[inline(always)]
pub(crate) const fn pack_kind_into_high(value: u32, kind: IdKind) -> u32 {
value | ((kind as u32) << 24)
}
/// Extract the value component from a high segment of an [`super::Identifier`].
#[inline(always)]
pub(crate) const fn extract_value_from_high(value: u32) -> u32 {
value & HIGH_MASK
}
/// Extract the ID kind component from a high segment of an [`super::Identifier`].
#[inline(always)]
pub(crate) const fn extract_kind_from_high(value: u32) -> IdKind {
// The negated HIGH_MASK will extract just the bit we need for kind.
let kind_mask = !HIGH_MASK;
let bit = value & kind_mask;
if bit == kind_mask {
IdKind::Placeholder
} else {
IdKind::Entity
}
}
/// Offsets a masked generation value by the specified amount, wrapping to 1 instead of 0.
/// Will never be greater than [`HIGH_MASK`] or less than `1`, and increments are masked to
/// never be greater than [`HIGH_MASK`].
#[inline(always)]
pub(crate) const fn inc_masked_high_by(lhs: NonZero<u32>, rhs: u32) -> NonZero<u32> {
let lo = (lhs.get() & HIGH_MASK).wrapping_add(rhs & HIGH_MASK);
// Checks high 32 bit for whether we have overflowed 31 bits.
let overflowed = lo >> 31;
// SAFETY:
// - Adding the overflow flag will offset overflows to start at 1 instead of 0
// - The sum of `0x7FFF_FFFF` + `u32::MAX` + 1 (overflow) == `0x7FFF_FFFF`
// - If the operation doesn't overflow at 31 bits, no offsetting takes place
unsafe { NonZero::<u32>::new_unchecked(lo.wrapping_add(overflowed) & HIGH_MASK) }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn get_u64_parts() {
// Two distinct bit patterns per low/high component
let value: u64 = 0x7FFF_FFFF_0000_000C;
assert_eq!(IdentifierMask::get_low(value), 0x0000_000C);
assert_eq!(IdentifierMask::get_high(value), 0x7FFF_FFFF);
}
#[test]
fn extract_kind() {
// All bits are ones.
let high: u32 = 0xFFFF_FFFF;
assert_eq!(
IdentifierMask::extract_kind_from_high(high),
IdKind::Placeholder
);
// Second and second to last bits are ones.
let high: u32 = 0x4000_0002;
assert_eq!(IdentifierMask::extract_kind_from_high(high), IdKind::Entity);
}
#[test]
fn extract_high_value() {
// All bits are ones.
let high: u32 = 0xFFFF_FFFF;
// Excludes the most significant bit as that is a flag bit.
assert_eq!(IdentifierMask::extract_value_from_high(high), 0x7FFF_FFFF);
// Start bit and end bit are ones.
let high: u32 = 0x8000_0001;
assert_eq!(IdentifierMask::extract_value_from_high(high), 0x0000_0001);
// Classic bit pattern.
let high: u32 = 0xDEAD_BEEF;
assert_eq!(IdentifierMask::extract_value_from_high(high), 0x5EAD_BEEF);
}
#[test]
fn pack_kind_bits() {
// All bits are ones expect the most significant bit, which is zero
let high: u32 = 0x7FFF_FFFF;
assert_eq!(
IdentifierMask::pack_kind_into_high(high, IdKind::Placeholder),
0xFFFF_FFFF
);
// Arbitrary bit pattern
let high: u32 = 0x00FF_FF00;
assert_eq!(
IdentifierMask::pack_kind_into_high(high, IdKind::Entity),
// Remains unchanged as before
0x00FF_FF00
);
// Bit pattern that almost spells a word
let high: u32 = 0x40FF_EEEE;
assert_eq!(
IdentifierMask::pack_kind_into_high(high, IdKind::Placeholder),
0xC0FF_EEEE // Milk and no sugar, please.
);
}
#[test]
fn pack_into_u64() {
let high: u32 = 0x7FFF_FFFF;
let low: u32 = 0x0000_00CC;
assert_eq!(
IdentifierMask::pack_into_u64(low, high),
0x7FFF_FFFF_0000_00CC
);
}
#[test]
fn incrementing_masked_nonzero_high_is_safe() {
// Adding from lowest value with lowest to highest increment
// No result should ever be greater than 0x7FFF_FFFF or HIGH_MASK
assert_eq!(
NonZero::<u32>::MIN,
IdentifierMask::inc_masked_high_by(NonZero::<u32>::MIN, 0)
);
assert_eq!(
NonZero::<u32>::new(2).unwrap(),
IdentifierMask::inc_masked_high_by(NonZero::<u32>::MIN, 1)
);
assert_eq!(
NonZero::<u32>::new(3).unwrap(),
IdentifierMask::inc_masked_high_by(NonZero::<u32>::MIN, 2)
);
assert_eq!(
NonZero::<u32>::MIN,
IdentifierMask::inc_masked_high_by(NonZero::<u32>::MIN, HIGH_MASK)
);
assert_eq!(
NonZero::<u32>::MIN,
IdentifierMask::inc_masked_high_by(NonZero::<u32>::MIN, u32::MAX)
);
// Adding from absolute highest value with lowest to highest increment
// No result should ever be greater than 0x7FFF_FFFF or HIGH_MASK
assert_eq!(
NonZero::<u32>::new(HIGH_MASK).unwrap(),
IdentifierMask::inc_masked_high_by(NonZero::<u32>::MAX, 0)
);
assert_eq!(
NonZero::<u32>::MIN,
IdentifierMask::inc_masked_high_by(NonZero::<u32>::MAX, 1)
);
assert_eq!(
NonZero::<u32>::new(2).unwrap(),
IdentifierMask::inc_masked_high_by(NonZero::<u32>::MAX, 2)
);
assert_eq!(
NonZero::<u32>::new(HIGH_MASK).unwrap(),
IdentifierMask::inc_masked_high_by(NonZero::<u32>::MAX, HIGH_MASK)
);
assert_eq!(
NonZero::<u32>::new(HIGH_MASK).unwrap(),
IdentifierMask::inc_masked_high_by(NonZero::<u32>::MAX, u32::MAX)
);
// Adding from actual highest value with lowest to highest increment
// No result should ever be greater than 0x7FFF_FFFF or HIGH_MASK
assert_eq!(
NonZero::<u32>::new(HIGH_MASK).unwrap(),
IdentifierMask::inc_masked_high_by(NonZero::<u32>::new(HIGH_MASK).unwrap(), 0)
);
assert_eq!(
NonZero::<u32>::MIN,
IdentifierMask::inc_masked_high_by(NonZero::<u32>::new(HIGH_MASK).unwrap(), 1)
);
assert_eq!(
NonZero::<u32>::new(2).unwrap(),
IdentifierMask::inc_masked_high_by(NonZero::<u32>::new(HIGH_MASK).unwrap(), 2)
);
assert_eq!(
NonZero::<u32>::new(HIGH_MASK).unwrap(),
IdentifierMask::inc_masked_high_by(NonZero::<u32>::new(HIGH_MASK).unwrap(), HIGH_MASK)
);
assert_eq!(
NonZero::<u32>::new(HIGH_MASK).unwrap(),
IdentifierMask::inc_masked_high_by(NonZero::<u32>::new(HIGH_MASK).unwrap(), u32::MAX)
);
}
}

249
vendor/bevy_ecs/src/identifier/mod.rs vendored Normal file
View File

@@ -0,0 +1,249 @@
//! A module for the unified [`Identifier`] ID struct, for use as a representation
//! of multiple types of IDs in a single, packed type. Allows for describing an [`crate::entity::Entity`],
//! or other IDs that can be packed and expressed within a `u64` sized type.
//! [`Identifier`]s cannot be created directly, only able to be converted from other
//! compatible IDs.
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::Reflect;
use self::{error::IdentifierError, kinds::IdKind, masks::IdentifierMask};
use core::{hash::Hash, num::NonZero};
pub mod error;
pub(crate) mod kinds;
pub(crate) mod masks;
/// A unified identifier for all entity and similar IDs.
///
/// Has the same size as a `u64` integer, but the layout is split between a 32-bit low
/// segment, a 31-bit high segment, and the significant bit reserved as type flags to denote
/// entity kinds.
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "bevy_reflect", reflect(opaque))]
#[cfg_attr(feature = "bevy_reflect", reflect(Debug, Hash, PartialEq, Clone))]
// Alignment repr necessary to allow LLVM to better output
// optimized codegen for `to_bits`, `PartialEq` and `Ord`.
#[repr(C, align(8))]
pub struct Identifier {
// Do not reorder the fields here. The ordering is explicitly used by repr(C)
// to make this struct equivalent to a u64.
#[cfg(target_endian = "little")]
low: u32,
high: NonZero<u32>,
#[cfg(target_endian = "big")]
low: u32,
}
impl Identifier {
/// Construct a new [`Identifier`]. The `high` parameter is masked with the
/// `kind` so to pack the high value and bit flags into the same field.
#[inline(always)]
pub const fn new(low: u32, high: u32, kind: IdKind) -> Result<Self, IdentifierError> {
// the high bits are masked to cut off the most significant bit
// as these are used for the type flags. This means that the high
// portion is only 31 bits, but this still provides 2^31
// values/kinds/ids that can be stored in this segment.
let masked_value = IdentifierMask::extract_value_from_high(high);
let packed_high = IdentifierMask::pack_kind_into_high(masked_value, kind);
// If the packed high component ends up being zero, that means that we tried
// to initialize an Identifier into an invalid state.
if packed_high == 0 {
Err(IdentifierError::InvalidIdentifier)
} else {
// SAFETY: The high value has been checked to ensure it is never
// zero.
unsafe {
Ok(Self {
low,
high: NonZero::<u32>::new_unchecked(packed_high),
})
}
}
}
/// Returns the value of the low segment of the [`Identifier`].
#[inline(always)]
pub const fn low(self) -> u32 {
self.low
}
/// Returns the value of the high segment of the [`Identifier`]. This
/// does not apply any masking.
#[inline(always)]
pub const fn high(self) -> NonZero<u32> {
self.high
}
/// Returns the masked value of the high segment of the [`Identifier`].
/// Does not include the flag bits.
#[inline(always)]
pub const fn masked_high(self) -> u32 {
IdentifierMask::extract_value_from_high(self.high.get())
}
/// Returns the kind of [`Identifier`] from the high segment.
#[inline(always)]
pub const fn kind(self) -> IdKind {
IdentifierMask::extract_kind_from_high(self.high.get())
}
/// Convert the [`Identifier`] into a `u64`.
#[inline(always)]
pub const fn to_bits(self) -> u64 {
IdentifierMask::pack_into_u64(self.low, self.high.get())
}
/// Convert a `u64` into an [`Identifier`].
///
/// # Panics
///
/// This method will likely panic if given `u64` values that did not come from [`Identifier::to_bits`].
#[inline(always)]
pub const fn from_bits(value: u64) -> Self {
let id = Self::try_from_bits(value);
match id {
Ok(id) => id,
Err(_) => panic!("Attempted to initialize invalid bits as an id"),
}
}
/// Convert a `u64` into an [`Identifier`].
///
/// This method is the fallible counterpart to [`Identifier::from_bits`].
#[inline(always)]
pub const fn try_from_bits(value: u64) -> Result<Self, IdentifierError> {
let high = NonZero::<u32>::new(IdentifierMask::get_high(value));
match high {
Some(high) => Ok(Self {
low: IdentifierMask::get_low(value),
high,
}),
None => Err(IdentifierError::InvalidIdentifier),
}
}
}
// By not short-circuiting in comparisons, we get better codegen.
// See <https://github.com/rust-lang/rust/issues/117800>
impl PartialEq for Identifier {
#[inline]
fn eq(&self, other: &Self) -> bool {
// By using `to_bits`, the codegen can be optimized out even
// further potentially. Relies on the correct alignment/field
// order of `Entity`.
self.to_bits() == other.to_bits()
}
}
impl Eq for Identifier {}
// The derive macro codegen output is not optimal and can't be optimized as well
// by the compiler. This impl resolves the issue of non-optimal codegen by relying
// on comparing against the bit representation of `Entity` instead of comparing
// the fields. The result is then LLVM is able to optimize the codegen for Entity
// far beyond what the derive macro can.
// See <https://github.com/rust-lang/rust/issues/106107>
impl PartialOrd for Identifier {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
// Make use of our `Ord` impl to ensure optimal codegen output
Some(self.cmp(other))
}
}
// The derive macro codegen output is not optimal and can't be optimized as well
// by the compiler. This impl resolves the issue of non-optimal codegen by relying
// on comparing against the bit representation of `Entity` instead of comparing
// the fields. The result is then LLVM is able to optimize the codegen for Entity
// far beyond what the derive macro can.
// See <https://github.com/rust-lang/rust/issues/106107>
impl Ord for Identifier {
#[inline]
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
// This will result in better codegen for ordering comparisons, plus
// avoids pitfalls with regards to macro codegen relying on property
// position when we want to compare against the bit representation.
self.to_bits().cmp(&other.to_bits())
}
}
impl Hash for Identifier {
#[inline]
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.to_bits().hash(state);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn id_construction() {
let id = Identifier::new(12, 55, IdKind::Entity).unwrap();
assert_eq!(id.low(), 12);
assert_eq!(id.high().get(), 55);
assert_eq!(
IdentifierMask::extract_kind_from_high(id.high().get()),
IdKind::Entity
);
}
#[test]
fn from_bits() {
// This high value should correspond to the max high() value
// and also Entity flag.
let high = 0x7FFFFFFF;
let low = 0xC;
let bits: u64 = (high << u32::BITS) | low;
let id = Identifier::try_from_bits(bits).unwrap();
assert_eq!(id.to_bits(), 0x7FFFFFFF0000000C);
assert_eq!(id.low(), low as u32);
assert_eq!(id.high().get(), 0x7FFFFFFF);
assert_eq!(
IdentifierMask::extract_kind_from_high(id.high().get()),
IdKind::Entity
);
}
#[rustfmt::skip]
#[test]
#[expect(
clippy::nonminimal_bool,
reason = "This intentionally tests all possible comparison operators as separate functions; thus, we don't want to rewrite these comparisons to use different operators."
)]
fn id_comparison() {
assert!(Identifier::new(123, 456, IdKind::Entity).unwrap() == Identifier::new(123, 456, IdKind::Entity).unwrap());
assert!(Identifier::new(123, 456, IdKind::Placeholder).unwrap() == Identifier::new(123, 456, IdKind::Placeholder).unwrap());
assert!(Identifier::new(123, 789, IdKind::Entity).unwrap() != Identifier::new(123, 456, IdKind::Entity).unwrap());
assert!(Identifier::new(123, 456, IdKind::Entity).unwrap() != Identifier::new(123, 789, IdKind::Entity).unwrap());
assert!(Identifier::new(123, 456, IdKind::Entity).unwrap() != Identifier::new(456, 123, IdKind::Entity).unwrap());
assert!(Identifier::new(123, 456, IdKind::Entity).unwrap() != Identifier::new(123, 456, IdKind::Placeholder).unwrap());
// ordering is by flag then high then by low
assert!(Identifier::new(123, 456, IdKind::Entity).unwrap() >= Identifier::new(123, 456, IdKind::Entity).unwrap());
assert!(Identifier::new(123, 456, IdKind::Entity).unwrap() <= Identifier::new(123, 456, IdKind::Entity).unwrap());
assert!(!(Identifier::new(123, 456, IdKind::Entity).unwrap() < Identifier::new(123, 456, IdKind::Entity).unwrap()));
assert!(!(Identifier::new(123, 456, IdKind::Entity).unwrap() > Identifier::new(123, 456, IdKind::Entity).unwrap()));
assert!(Identifier::new(9, 1, IdKind::Entity).unwrap() < Identifier::new(1, 9, IdKind::Entity).unwrap());
assert!(Identifier::new(1, 9, IdKind::Entity).unwrap() > Identifier::new(9, 1, IdKind::Entity).unwrap());
assert!(Identifier::new(9, 1, IdKind::Entity).unwrap() < Identifier::new(9, 1, IdKind::Placeholder).unwrap());
assert!(Identifier::new(1, 9, IdKind::Placeholder).unwrap() > Identifier::new(1, 9, IdKind::Entity).unwrap());
assert!(Identifier::new(1, 1, IdKind::Entity).unwrap() < Identifier::new(2, 1, IdKind::Entity).unwrap());
assert!(Identifier::new(1, 1, IdKind::Entity).unwrap() <= Identifier::new(2, 1, IdKind::Entity).unwrap());
assert!(Identifier::new(2, 2, IdKind::Entity).unwrap() > Identifier::new(1, 2, IdKind::Entity).unwrap());
assert!(Identifier::new(2, 2, IdKind::Entity).unwrap() >= Identifier::new(1, 2, IdKind::Entity).unwrap());
}
}

280
vendor/bevy_ecs/src/intern.rs vendored Normal file
View File

@@ -0,0 +1,280 @@
//! Provides types used to statically intern immutable values.
//!
//! Interning is a pattern used to save memory by deduplicating identical values,
//! speed up code by shrinking the stack size of large types,
//! and make comparisons for any type as fast as integers.
use alloc::{borrow::ToOwned, boxed::Box};
use bevy_platform::{
collections::HashSet,
hash::FixedHasher,
sync::{PoisonError, RwLock},
};
use core::{fmt::Debug, hash::Hash, ops::Deref};
/// An interned value. Will stay valid until the end of the program and will not drop.
///
/// For details on interning, see [the module level docs](self).
///
/// # Comparisons
///
/// Interned values use reference equality, meaning they implement [`Eq`]
/// and [`Hash`] regardless of whether `T` implements these traits.
/// Two interned values are only guaranteed to compare equal if they were interned using
/// the same [`Interner`] instance.
// NOTE: This type must NEVER implement Borrow since it does not obey that trait's invariants.
/// ```
/// # use bevy_ecs::intern::*;
/// #[derive(PartialEq, Eq, Hash, Debug)]
/// struct Value(i32);
/// impl Internable for Value {
/// // ...
/// # fn leak(&self) -> &'static Self { Box::leak(Box::new(Value(self.0))) }
/// # fn ref_eq(&self, other: &Self) -> bool { std::ptr::eq(self, other ) }
/// # fn ref_hash<H: std::hash::Hasher>(&self, state: &mut H) { std::ptr::hash(self, state); }
/// }
/// let interner_1 = Interner::new();
/// let interner_2 = Interner::new();
/// // Even though both values are identical, their interned forms do not
/// // compare equal as they use different interner instances.
/// assert_ne!(interner_1.intern(&Value(42)), interner_2.intern(&Value(42)));
/// ```
pub struct Interned<T: ?Sized + 'static>(pub &'static T);
impl<T: ?Sized> Deref for Interned<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.0
}
}
impl<T: ?Sized> Clone for Interned<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized> Copy for Interned<T> {}
// Two Interned<T> should only be equal if they are clones from the same instance.
// Therefore, we only use the pointer to determine equality.
impl<T: ?Sized + Internable> PartialEq for Interned<T> {
fn eq(&self, other: &Self) -> bool {
self.0.ref_eq(other.0)
}
}
impl<T: ?Sized + Internable> Eq for Interned<T> {}
// Important: This must be kept in sync with the PartialEq/Eq implementation
impl<T: ?Sized + Internable> Hash for Interned<T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.0.ref_hash(state);
}
}
impl<T: ?Sized + Debug> Debug for Interned<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.0.fmt(f)
}
}
impl<T> From<&Interned<T>> for Interned<T> {
fn from(value: &Interned<T>) -> Self {
*value
}
}
/// A trait for internable values.
///
/// This is used by [`Interner<T>`] to create static references for values that are interned.
pub trait Internable: Hash + Eq {
/// Creates a static reference to `self`, possibly leaking memory.
fn leak(&self) -> &'static Self;
/// Returns `true` if the two references point to the same value.
fn ref_eq(&self, other: &Self) -> bool;
/// Feeds the reference to the hasher.
fn ref_hash<H: core::hash::Hasher>(&self, state: &mut H);
}
impl Internable for str {
fn leak(&self) -> &'static Self {
let str = self.to_owned().into_boxed_str();
Box::leak(str)
}
fn ref_eq(&self, other: &Self) -> bool {
self.as_ptr() == other.as_ptr() && self.len() == other.len()
}
fn ref_hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.len().hash(state);
self.as_ptr().hash(state);
}
}
/// A thread-safe interner which can be used to create [`Interned<T>`] from `&T`
///
/// For details on interning, see [the module level docs](self).
///
/// The implementation ensures that two equal values return two equal [`Interned<T>`] values.
///
/// To use an [`Interner<T>`], `T` must implement [`Internable`].
pub struct Interner<T: ?Sized + 'static>(RwLock<HashSet<&'static T>>);
impl<T: ?Sized> Interner<T> {
/// Creates a new empty interner
pub const fn new() -> Self {
Self(RwLock::new(HashSet::with_hasher(FixedHasher)))
}
}
impl<T: Internable + ?Sized> Interner<T> {
/// Return the [`Interned<T>`] corresponding to `value`.
///
/// If it is called the first time for `value`, it will possibly leak the value and return an
/// [`Interned<T>`] using the obtained static reference. Subsequent calls for the same `value`
/// will return [`Interned<T>`] using the same static reference.
pub fn intern(&self, value: &T) -> Interned<T> {
{
let set = self.0.read().unwrap_or_else(PoisonError::into_inner);
if let Some(value) = set.get(value) {
return Interned(*value);
}
}
{
let mut set = self.0.write().unwrap_or_else(PoisonError::into_inner);
if let Some(value) = set.get(value) {
Interned(*value)
} else {
let leaked = value.leak();
set.insert(leaked);
Interned(leaked)
}
}
}
}
impl<T: ?Sized> Default for Interner<T> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use alloc::{boxed::Box, string::ToString};
use bevy_platform::hash::FixedHasher;
use core::hash::{BuildHasher, Hash, Hasher};
use crate::intern::{Internable, Interned, Interner};
#[test]
fn zero_sized_type() {
#[derive(PartialEq, Eq, Hash, Debug)]
pub struct A;
impl Internable for A {
fn leak(&self) -> &'static Self {
&A
}
fn ref_eq(&self, other: &Self) -> bool {
core::ptr::eq(self, other)
}
fn ref_hash<H: Hasher>(&self, state: &mut H) {
core::ptr::hash(self, state);
}
}
let interner = Interner::default();
let x = interner.intern(&A);
let y = interner.intern(&A);
assert_eq!(x, y);
}
#[test]
fn fieldless_enum() {
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
pub enum A {
X,
Y,
}
impl Internable for A {
fn leak(&self) -> &'static Self {
match self {
A::X => &A::X,
A::Y => &A::Y,
}
}
fn ref_eq(&self, other: &Self) -> bool {
core::ptr::eq(self, other)
}
fn ref_hash<H: Hasher>(&self, state: &mut H) {
core::ptr::hash(self, state);
}
}
let interner = Interner::default();
let x = interner.intern(&A::X);
let y = interner.intern(&A::Y);
assert_ne!(x, y);
}
#[test]
fn static_sub_strings() {
let str = "ABC ABC";
let a = &str[0..3];
let b = &str[4..7];
// Same contents
assert_eq!(a, b);
let x = Interned(a);
let y = Interned(b);
// Different pointers
assert_ne!(x, y);
let interner = Interner::default();
let x = interner.intern(a);
let y = interner.intern(b);
// Same pointers returned by interner
assert_eq!(x, y);
}
#[test]
fn same_interned_instance() {
let a = Interned("A");
let b = a;
assert_eq!(a, b);
let hash_a = FixedHasher.hash_one(a);
let hash_b = FixedHasher.hash_one(b);
assert_eq!(hash_a, hash_b);
}
#[test]
fn same_interned_content() {
let a = Interned::<str>(Box::leak(Box::new("A".to_string())));
let b = Interned::<str>(Box::leak(Box::new("A".to_string())));
assert_ne!(a, b);
}
#[test]
fn different_interned_content() {
let a = Interned::<str>("A");
let b = Interned::<str>("B");
assert_ne!(a, b);
}
}

210
vendor/bevy_ecs/src/label.rs vendored Normal file
View File

@@ -0,0 +1,210 @@
//! Traits used by label implementations
use core::{
any::Any,
hash::{Hash, Hasher},
};
// Re-exported for use within `define_label!`
#[doc(hidden)]
pub use alloc::boxed::Box;
/// An object safe version of [`Eq`]. This trait is automatically implemented
/// for any `'static` type that implements `Eq`.
pub trait DynEq: Any {
/// Casts the type to `dyn Any`.
fn as_any(&self) -> &dyn Any;
/// This method tests for `self` and `other` values to be equal.
///
/// Implementers should avoid returning `true` when the underlying types are
/// not the same.
fn dyn_eq(&self, other: &dyn DynEq) -> bool;
}
// Tests that this trait is dyn-compatible
const _: Option<Box<dyn DynEq>> = None;
impl<T> DynEq for T
where
T: Any + Eq,
{
fn as_any(&self) -> &dyn Any {
self
}
fn dyn_eq(&self, other: &dyn DynEq) -> bool {
if let Some(other) = other.as_any().downcast_ref::<T>() {
return self == other;
}
false
}
}
/// An object safe version of [`Hash`]. This trait is automatically implemented
/// for any `'static` type that implements `Hash`.
pub trait DynHash: DynEq {
/// Casts the type to `dyn Any`.
fn as_dyn_eq(&self) -> &dyn DynEq;
/// Feeds this value into the given [`Hasher`].
fn dyn_hash(&self, state: &mut dyn Hasher);
}
// Tests that this trait is dyn-compatible
const _: Option<Box<dyn DynHash>> = None;
impl<T> DynHash for T
where
T: DynEq + Hash,
{
fn as_dyn_eq(&self) -> &dyn DynEq {
self
}
fn dyn_hash(&self, mut state: &mut dyn Hasher) {
T::hash(self, &mut state);
self.type_id().hash(&mut state);
}
}
/// Macro to define a new label trait
///
/// # Example
///
/// ```
/// # use bevy_ecs::define_label;
/// define_label!(
/// /// Documentation of label trait
/// MyNewLabelTrait,
/// MY_NEW_LABEL_TRAIT_INTERNER
/// );
///
/// define_label!(
/// /// Documentation of another label trait
/// MyNewExtendedLabelTrait,
/// MY_NEW_EXTENDED_LABEL_TRAIT_INTERNER,
/// extra_methods: {
/// // Extra methods for the trait can be defined here
/// fn additional_method(&self) -> i32;
/// },
/// extra_methods_impl: {
/// // Implementation of the extra methods for Interned<dyn MyNewExtendedLabelTrait>
/// fn additional_method(&self) -> i32 {
/// 0
/// }
/// }
/// );
/// ```
#[macro_export]
macro_rules! define_label {
(
$(#[$label_attr:meta])*
$label_trait_name:ident,
$interner_name:ident
) => {
$crate::define_label!(
$(#[$label_attr])*
$label_trait_name,
$interner_name,
extra_methods: {},
extra_methods_impl: {}
);
};
(
$(#[$label_attr:meta])*
$label_trait_name:ident,
$interner_name:ident,
extra_methods: { $($trait_extra_methods:tt)* },
extra_methods_impl: { $($interned_extra_methods_impl:tt)* }
) => {
$(#[$label_attr])*
pub trait $label_trait_name: 'static + Send + Sync + ::core::fmt::Debug {
$($trait_extra_methods)*
/// Clones this `
#[doc = stringify!($label_trait_name)]
///`.
fn dyn_clone(&self) -> $crate::label::Box<dyn $label_trait_name>;
/// Casts this value to a form where it can be compared with other type-erased values.
fn as_dyn_eq(&self) -> &dyn $crate::label::DynEq;
/// Feeds this value into the given [`Hasher`].
fn dyn_hash(&self, state: &mut dyn ::core::hash::Hasher);
/// Returns an [`Interned`] value corresponding to `self`.
fn intern(&self) -> $crate::intern::Interned<dyn $label_trait_name>
where Self: Sized {
$interner_name.intern(self)
}
}
#[diagnostic::do_not_recommend]
impl $label_trait_name for $crate::intern::Interned<dyn $label_trait_name> {
$($interned_extra_methods_impl)*
fn dyn_clone(&self) -> $crate::label::Box<dyn $label_trait_name> {
(**self).dyn_clone()
}
/// Casts this value to a form where it can be compared with other type-erased values.
fn as_dyn_eq(&self) -> &dyn $crate::label::DynEq {
(**self).as_dyn_eq()
}
fn dyn_hash(&self, state: &mut dyn ::core::hash::Hasher) {
(**self).dyn_hash(state);
}
fn intern(&self) -> Self {
*self
}
}
impl PartialEq for dyn $label_trait_name {
fn eq(&self, other: &Self) -> bool {
self.as_dyn_eq().dyn_eq(other.as_dyn_eq())
}
}
impl Eq for dyn $label_trait_name {}
impl ::core::hash::Hash for dyn $label_trait_name {
fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
self.dyn_hash(state);
}
}
impl $crate::intern::Internable for dyn $label_trait_name {
fn leak(&self) -> &'static Self {
$crate::label::Box::leak(self.dyn_clone())
}
fn ref_eq(&self, other: &Self) -> bool {
use ::core::ptr;
// Test that both the type id and pointer address are equivalent.
self.as_dyn_eq().type_id() == other.as_dyn_eq().type_id()
&& ptr::addr_eq(ptr::from_ref::<Self>(self), ptr::from_ref::<Self>(other))
}
fn ref_hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
use ::core::{hash::Hash, ptr};
// Hash the type id...
self.as_dyn_eq().type_id().hash(state);
// ...and the pointer address.
// Cast to a unit `()` first to discard any pointer metadata.
ptr::from_ref::<Self>(self).cast::<()>().hash(state);
}
}
static $interner_name: $crate::intern::Interner<dyn $label_trait_name> =
$crate::intern::Interner::new();
};
}

2846
vendor/bevy_ecs/src/lib.rs vendored Normal file

File diff suppressed because it is too large Load Diff

296
vendor/bevy_ecs/src/name.rs vendored Normal file
View File

@@ -0,0 +1,296 @@
//! Provides the [`Name`] [`Component`], used for identifying an [`Entity`].
use crate::{component::Component, entity::Entity, query::QueryData};
use alloc::{
borrow::{Cow, ToOwned},
string::String,
};
use bevy_platform::hash::FixedHasher;
use core::{
hash::{BuildHasher, Hash, Hasher},
ops::Deref,
};
#[cfg(feature = "serialize")]
use {
alloc::string::ToString,
serde::{
de::{Error, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
},
};
#[cfg(feature = "bevy_reflect")]
use {
crate::reflect::ReflectComponent,
bevy_reflect::{std_traits::ReflectDefault, Reflect},
};
#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
/// Component used to identify an entity. Stores a hash for faster comparisons.
///
/// The hash is eagerly re-computed upon each update to the name.
///
/// [`Name`] should not be treated as a globally unique identifier for entities,
/// as multiple entities can have the same name. [`Entity`] should be
/// used instead as the default unique identifier.
#[derive(Component, Clone)]
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect),
reflect(Component, Default, Debug, Clone, Hash, PartialEq)
)]
#[cfg_attr(
all(feature = "serialize", feature = "bevy_reflect"),
reflect(Deserialize, Serialize)
)]
pub struct Name {
hash: u64, // Won't be serialized
name: Cow<'static, str>,
}
impl Default for Name {
fn default() -> Self {
Name::new("")
}
}
impl Name {
/// Creates a new [`Name`] from any string-like type.
///
/// The internal hash will be computed immediately.
pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
let name = name.into();
let mut name = Name { name, hash: 0 };
name.update_hash();
name
}
/// Sets the entity's name.
///
/// The internal hash will be re-computed.
#[inline(always)]
pub fn set(&mut self, name: impl Into<Cow<'static, str>>) {
*self = Name::new(name);
}
/// Updates the name of the entity in place.
///
/// This will allocate a new string if the name was previously
/// created from a borrow.
#[inline(always)]
pub fn mutate<F: FnOnce(&mut String)>(&mut self, f: F) {
f(self.name.to_mut());
self.update_hash();
}
/// Gets the name of the entity as a `&str`.
#[inline(always)]
pub fn as_str(&self) -> &str {
&self.name
}
fn update_hash(&mut self) {
self.hash = FixedHasher.hash_one(&self.name);
}
}
impl core::fmt::Display for Name {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
core::fmt::Display::fmt(&self.name, f)
}
}
impl core::fmt::Debug for Name {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
core::fmt::Debug::fmt(&self.name, f)
}
}
/// Convenient query for giving a human friendly name to an entity.
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # #[derive(Component)] pub struct Score(f32);
/// fn increment_score(mut scores: Query<(NameOrEntity, &mut Score)>) {
/// for (name, mut score) in &mut scores {
/// score.0 += 1.0;
/// if score.0.is_nan() {
/// log::error!("Score for {name} is invalid");
/// }
/// }
/// }
/// # bevy_ecs::system::assert_is_system(increment_score);
/// ```
///
/// # Implementation
///
/// The `Display` impl for `NameOrEntity` returns the `Name` where there is one
/// or {index}v{generation} for entities without one.
#[derive(QueryData)]
#[query_data(derive(Debug))]
pub struct NameOrEntity {
/// A [`Name`] that the entity might have that is displayed if available.
pub name: Option<&'static Name>,
/// The unique identifier of the entity as a fallback.
pub entity: Entity,
}
impl<'a> core::fmt::Display for NameOrEntityItem<'a> {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self.name {
Some(name) => core::fmt::Display::fmt(name, f),
None => core::fmt::Display::fmt(&self.entity, f),
}
}
}
// Conversions from strings
impl From<&str> for Name {
#[inline(always)]
fn from(name: &str) -> Self {
Name::new(name.to_owned())
}
}
impl From<String> for Name {
#[inline(always)]
fn from(name: String) -> Self {
Name::new(name)
}
}
// Conversions to strings
impl AsRef<str> for Name {
#[inline(always)]
fn as_ref(&self) -> &str {
&self.name
}
}
impl From<&Name> for String {
#[inline(always)]
fn from(val: &Name) -> String {
val.as_str().to_owned()
}
}
impl From<Name> for String {
#[inline(always)]
fn from(val: Name) -> String {
val.name.into_owned()
}
}
impl Hash for Name {
fn hash<H: Hasher>(&self, state: &mut H) {
self.name.hash(state);
}
}
impl PartialEq for Name {
fn eq(&self, other: &Self) -> bool {
if self.hash != other.hash {
// Makes the common case of two strings not been equal very fast
return false;
}
self.name.eq(&other.name)
}
}
impl Eq for Name {}
impl PartialOrd for Name {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Name {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.name.cmp(&other.name)
}
}
impl Deref for Name {
type Target = str;
fn deref(&self) -> &Self::Target {
self.name.as_ref()
}
}
#[cfg(feature = "serialize")]
impl Serialize for Name {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(self.as_str())
}
}
#[cfg(feature = "serialize")]
impl<'de> Deserialize<'de> for Name {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
deserializer.deserialize_str(NameVisitor)
}
}
#[cfg(feature = "serialize")]
struct NameVisitor;
#[cfg(feature = "serialize")]
impl<'de> Visitor<'de> for NameVisitor {
type Value = Name;
fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
formatter.write_str(core::any::type_name::<Name>())
}
fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
Ok(Name::new(v.to_string()))
}
fn visit_string<E: Error>(self, v: String) -> Result<Self::Value, E> {
Ok(Name::new(v))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::world::World;
use alloc::string::ToString;
#[test]
fn test_display_of_debug_name() {
let mut world = World::new();
let e1 = world.spawn_empty().id();
let name = Name::new("MyName");
let e2 = world.spawn(name.clone()).id();
let mut query = world.query::<NameOrEntity>();
let d1 = query.get(&world, e1).unwrap();
let d2 = query.get(&world, e2).unwrap();
// NameOrEntity Display for entities without a Name should be {index}v{generation}
assert_eq!(d1.to_string(), "0v1");
// NameOrEntity Display for entities with a Name should be the Name
assert_eq!(d2.to_string(), "MyName");
}
}
#[cfg(all(test, feature = "serialize"))]
mod serde_tests {
use super::Name;
use serde_test::{assert_tokens, Token};
#[test]
fn test_serde_name() {
let name = Name::new("MyComponent");
assert_tokens(&name, &[Token::String("MyComponent")]);
}
}

39
vendor/bevy_ecs/src/never.rs vendored Normal file
View File

@@ -0,0 +1,39 @@
//! A workaround for the `!` type in stable Rust.
//!
//! This approach is taken from the [`never_say_never`] crate,
//! reimplemented here to avoid adding a new dependency.
//!
//! This module exists due to a change in [never type fallback inference] in the Rust 2024 edition.
//! This caused failures in `bevy_ecs`'s traits which are implemented for functions
//! (like [`System`](crate::system::System)) when working with panicking closures.
//!
//! Note that using this hack is not recommended in general;
//! by doing so you are knowingly opting out of rustc's stability guarantees.
//! Code that compiles due to this hack may break in future versions of Rust.
//!
//! Please read [issue #18778](https://github.com/bevyengine/bevy/issues/18778) for an explanation of why
//! Bevy has chosen to use this workaround.
//!
//! [`never_say_never`]: https://crates.io/crates/never_say_never
//! [never type fallback inference]: https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html
mod fn_ret {
/// A helper trait for naming the ! type.
#[doc(hidden)]
pub trait FnRet {
/// The return type of the function.
type Output;
}
/// This blanket implementation allows us to name the never type,
/// by using the associated type of this trait for `fn() -> !`.
impl<R> FnRet for fn() -> R {
type Output = R;
}
}
/// A hacky type alias for the `!` (never) type.
///
/// This knowingly opts out of rustc's stability guarantees.
/// Read the module documentation carefully before using this!
pub type Never = <fn() -> ! as fn_ret::FnRet>::Output;

View File

@@ -0,0 +1,144 @@
use crate::{
component::{
Component, ComponentCloneBehavior, ComponentHook, HookContext, Mutable, StorageType,
},
entity::{ComponentCloneCtx, Entity, EntityClonerBuilder, EntityMapper, SourceComponent},
observer::ObserverState,
world::World,
};
use alloc::vec::Vec;
/// Tracks a list of entity observers for the [`Entity`] [`ObservedBy`] is added to.
#[derive(Default)]
pub struct ObservedBy(pub(crate) Vec<Entity>);
impl Component for ObservedBy {
const STORAGE_TYPE: StorageType = StorageType::SparseSet;
type Mutability = Mutable;
fn on_remove() -> Option<ComponentHook> {
Some(|mut world, HookContext { entity, .. }| {
let observed_by = {
let mut component = world.get_mut::<ObservedBy>(entity).unwrap();
core::mem::take(&mut component.0)
};
for e in observed_by {
let (total_entities, despawned_watched_entities) = {
let Ok(mut entity_mut) = world.get_entity_mut(e) else {
continue;
};
let Some(mut state) = entity_mut.get_mut::<ObserverState>() else {
continue;
};
state.despawned_watched_entities += 1;
(
state.descriptor.entities.len(),
state.despawned_watched_entities as usize,
)
};
// Despawn Observer if it has no more active sources.
if total_entities == despawned_watched_entities {
world.commands().entity(e).despawn();
}
}
})
}
fn clone_behavior() -> ComponentCloneBehavior {
ComponentCloneBehavior::Ignore
}
}
impl EntityClonerBuilder<'_> {
/// Sets the option to automatically add cloned entities to the observers targeting source entity.
pub fn add_observers(&mut self, add_observers: bool) -> &mut Self {
if add_observers {
self.override_clone_behavior::<ObservedBy>(ComponentCloneBehavior::Custom(
component_clone_observed_by,
))
} else {
self.remove_clone_behavior_override::<ObservedBy>()
}
}
}
fn component_clone_observed_by(_source: &SourceComponent, ctx: &mut ComponentCloneCtx) {
let target = ctx.target();
let source = ctx.source();
ctx.queue_deferred(move |world: &mut World, _mapper: &mut dyn EntityMapper| {
let observed_by = world
.get::<ObservedBy>(source)
.map(|observed_by| observed_by.0.clone())
.expect("Source entity must have ObservedBy");
world
.entity_mut(target)
.insert(ObservedBy(observed_by.clone()));
for observer in &observed_by {
let mut observer_state = world
.get_mut::<ObserverState>(*observer)
.expect("Source observer entity must have ObserverState");
observer_state.descriptor.entities.push(target);
let event_types = observer_state.descriptor.events.clone();
let components = observer_state.descriptor.components.clone();
for event_type in event_types {
let observers = world.observers.get_observers(event_type);
if components.is_empty() {
if let Some(map) = observers.entity_observers.get(&source).cloned() {
observers.entity_observers.insert(target, map);
}
} else {
for component in &components {
let Some(observers) = observers.component_observers.get_mut(component)
else {
continue;
};
if let Some(map) = observers.entity_map.get(&source).cloned() {
observers.entity_map.insert(target, map);
}
}
}
}
}
});
}
#[cfg(test)]
mod tests {
use crate::{
entity::EntityCloner, event::Event, observer::Trigger, resource::Resource, system::ResMut,
world::World,
};
#[derive(Resource, Default)]
struct Num(usize);
#[derive(Event)]
struct E;
#[test]
fn clone_entity_with_observer() {
let mut world = World::default();
world.init_resource::<Num>();
let e = world
.spawn_empty()
.observe(|_: Trigger<E>, mut res: ResMut<Num>| res.0 += 1)
.id();
world.flush();
world.trigger_targets(E, e);
let e_clone = world.spawn_empty().id();
EntityCloner::build(&mut world)
.add_observers(true)
.clone_entity(e, e_clone);
world.trigger_targets(E, [e, e_clone]);
assert_eq!(world.resource::<Num>().0, 3);
}
}

1789
vendor/bevy_ecs/src/observer/mod.rs vendored Normal file

File diff suppressed because it is too large Load Diff

532
vendor/bevy_ecs/src/observer/runner.rs vendored Normal file
View File

@@ -0,0 +1,532 @@
use alloc::{boxed::Box, vec, vec::Vec};
use core::any::Any;
use crate::{
component::{ComponentHook, ComponentId, HookContext, Mutable, StorageType},
error::{default_error_handler, ErrorContext},
observer::{ObserverDescriptor, ObserverTrigger},
prelude::*,
query::DebugCheckedUnwrap,
system::{IntoObserverSystem, ObserverSystem},
world::DeferredWorld,
};
use bevy_ptr::PtrMut;
/// Contains [`Observer`] information. This defines how a given observer behaves. It is the
/// "source of truth" for a given observer entity's behavior.
pub struct ObserverState {
pub(crate) descriptor: ObserverDescriptor,
pub(crate) runner: ObserverRunner,
pub(crate) last_trigger_id: u32,
pub(crate) despawned_watched_entities: u32,
}
impl Default for ObserverState {
fn default() -> Self {
Self {
runner: |_, _, _, _| {},
last_trigger_id: 0,
despawned_watched_entities: 0,
descriptor: Default::default(),
}
}
}
impl ObserverState {
/// Observe the given `event`. This will cause the [`Observer`] to run whenever an event with the given [`ComponentId`]
/// is triggered.
pub fn with_event(mut self, event: ComponentId) -> Self {
self.descriptor.events.push(event);
self
}
/// Observe the given event list. This will cause the [`Observer`] to run whenever an event with any of the given [`ComponentId`]s
/// is triggered.
pub fn with_events(mut self, events: impl IntoIterator<Item = ComponentId>) -> Self {
self.descriptor.events.extend(events);
self
}
/// Observe the given [`Entity`] list. This will cause the [`Observer`] to run whenever the [`Event`] is triggered
/// for any [`Entity`] target in the list.
pub fn with_entities(mut self, entities: impl IntoIterator<Item = Entity>) -> Self {
self.descriptor.entities.extend(entities);
self
}
/// Observe the given [`ComponentId`] list. This will cause the [`Observer`] to run whenever the [`Event`] is triggered
/// for any [`ComponentId`] target in the list.
pub fn with_components(mut self, components: impl IntoIterator<Item = ComponentId>) -> Self {
self.descriptor.components.extend(components);
self
}
}
impl Component for ObserverState {
const STORAGE_TYPE: StorageType = StorageType::SparseSet;
type Mutability = Mutable;
fn on_add() -> Option<ComponentHook> {
Some(|mut world, HookContext { entity, .. }| {
world.commands().queue(move |world: &mut World| {
world.register_observer(entity);
});
})
}
fn on_remove() -> Option<ComponentHook> {
Some(|mut world, HookContext { entity, .. }| {
let descriptor = core::mem::take(
&mut world
.entity_mut(entity)
.get_mut::<ObserverState>()
.unwrap()
.as_mut()
.descriptor,
);
world.commands().queue(move |world: &mut World| {
world.unregister_observer(entity, descriptor);
});
})
}
}
/// Type for function that is run when an observer is triggered.
///
/// Typically refers to the default runner that runs the system stored in the associated [`Observer`] component,
/// but can be overridden for custom behavior.
pub type ObserverRunner = fn(DeferredWorld, ObserverTrigger, PtrMut, propagate: &mut bool);
/// An [`Observer`] system. Add this [`Component`] to an [`Entity`] to turn it into an "observer".
///
/// Observers listen for a "trigger" of a specific [`Event`]. Events are triggered by calling [`World::trigger`] or [`World::trigger_targets`].
///
/// Note that "buffered" events sent using [`EventReader`] and [`EventWriter`] are _not_ automatically triggered. They must be triggered at a specific
/// point in the schedule.
///
/// # Usage
///
/// The simplest usage
/// of the observer pattern looks like this:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # let mut world = World::default();
/// #[derive(Event)]
/// struct Speak {
/// message: String,
/// }
///
/// world.add_observer(|trigger: Trigger<Speak>| {
/// println!("{}", trigger.event().message);
/// });
///
/// // Observers currently require a flush() to be registered. In the context of schedules,
/// // this will generally be done for you.
/// world.flush();
///
/// world.trigger(Speak {
/// message: "Hello!".into(),
/// });
/// ```
///
/// Notice that we used [`World::add_observer`]. This is just a shorthand for spawning an [`Observer`] manually:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # let mut world = World::default();
/// # #[derive(Event)]
/// # struct Speak;
/// // These are functionally the same:
/// world.add_observer(|trigger: Trigger<Speak>| {});
/// world.spawn(Observer::new(|trigger: Trigger<Speak>| {}));
/// ```
///
/// Observers are systems. They can access arbitrary [`World`] data by adding [`SystemParam`]s:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # let mut world = World::default();
/// # #[derive(Event)]
/// # struct PrintNames;
/// # #[derive(Component, Debug)]
/// # struct Name;
/// world.add_observer(|trigger: Trigger<PrintNames>, names: Query<&Name>| {
/// for name in &names {
/// println!("{name:?}");
/// }
/// });
/// ```
///
/// Note that [`Trigger`] must always be the first parameter.
///
/// You can also add [`Commands`], which means you can spawn new entities, insert new components, etc:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # let mut world = World::default();
/// # #[derive(Event)]
/// # struct SpawnThing;
/// # #[derive(Component, Debug)]
/// # struct Thing;
/// world.add_observer(|trigger: Trigger<SpawnThing>, mut commands: Commands| {
/// commands.spawn(Thing);
/// });
/// ```
///
/// Observers can also trigger new events:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # let mut world = World::default();
/// # #[derive(Event)]
/// # struct A;
/// # #[derive(Event)]
/// # struct B;
/// world.add_observer(|trigger: Trigger<A>, mut commands: Commands| {
/// commands.trigger(B);
/// });
/// ```
///
/// When the commands are flushed (including these "nested triggers") they will be
/// recursively evaluated until there are no commands left, meaning nested triggers all
/// evaluate at the same time!
///
/// Events can be triggered for entities, which will be passed to the [`Observer`]:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # let mut world = World::default();
/// # let entity = world.spawn_empty().id();
/// #[derive(Event)]
/// struct Explode;
///
/// world.add_observer(|trigger: Trigger<Explode>, mut commands: Commands| {
/// println!("Entity {} goes BOOM!", trigger.target());
/// commands.entity(trigger.target()).despawn();
/// });
///
/// world.flush();
///
/// world.trigger_targets(Explode, entity);
/// ```
///
/// You can trigger multiple entities at once:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # let mut world = World::default();
/// # let e1 = world.spawn_empty().id();
/// # let e2 = world.spawn_empty().id();
/// # #[derive(Event)]
/// # struct Explode;
/// world.trigger_targets(Explode, [e1, e2]);
/// ```
///
/// Observers can also watch _specific_ entities, which enables you to assign entity-specific logic:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # #[derive(Component, Debug)]
/// # struct Name(String);
/// # let mut world = World::default();
/// # let e1 = world.spawn_empty().id();
/// # let e2 = world.spawn_empty().id();
/// # #[derive(Event)]
/// # struct Explode;
/// world.entity_mut(e1).observe(|trigger: Trigger<Explode>, mut commands: Commands| {
/// println!("Boom!");
/// commands.entity(trigger.target()).despawn();
/// });
///
/// world.entity_mut(e2).observe(|trigger: Trigger<Explode>, mut commands: Commands| {
/// println!("The explosion fizzles! This entity is immune!");
/// });
/// ```
///
/// If all entities watched by a given [`Observer`] are despawned, the [`Observer`] entity will also be despawned.
/// This protects against observer "garbage" building up over time.
///
/// The examples above calling [`EntityWorldMut::observe`] to add entity-specific observer logic are (once again)
/// just shorthand for spawning an [`Observer`] directly:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # let mut world = World::default();
/// # let entity = world.spawn_empty().id();
/// # #[derive(Event)]
/// # struct Explode;
/// let mut observer = Observer::new(|trigger: Trigger<Explode>| {});
/// observer.watch_entity(entity);
/// world.spawn(observer);
/// ```
///
/// Note that the [`Observer`] component is not added to the entity it is observing. Observers should always be their own entities!
///
/// You can call [`Observer::watch_entity`] more than once, which allows you to watch multiple entities with the same [`Observer`].
///
/// When first added, [`Observer`] will also create an [`ObserverState`] component, which registers the observer with the [`World`] and
/// serves as the "source of truth" of the observer.
///
/// [`SystemParam`]: crate::system::SystemParam
pub struct Observer {
system: Box<dyn Any + Send + Sync + 'static>,
descriptor: ObserverDescriptor,
hook_on_add: ComponentHook,
error_handler: Option<fn(BevyError, ErrorContext)>,
}
impl Observer {
/// Creates a new [`Observer`], which defaults to a "global" observer. This means it will run whenever the event `E` is triggered
/// for _any_ entity (or no entity).
pub fn new<E: Event, B: Bundle, M, I: IntoObserverSystem<E, B, M>>(system: I) -> Self {
Self {
system: Box::new(IntoObserverSystem::into_system(system)),
descriptor: Default::default(),
hook_on_add: hook_on_add::<E, B, I::System>,
error_handler: None,
}
}
/// Observe the given `entity`. This will cause the [`Observer`] to run whenever the [`Event`] is triggered
/// for the `entity`.
pub fn with_entity(mut self, entity: Entity) -> Self {
self.descriptor.entities.push(entity);
self
}
/// Observe the given `entity`. This will cause the [`Observer`] to run whenever the [`Event`] is triggered
/// for the `entity`.
/// Note that if this is called _after_ an [`Observer`] is spawned, it will produce no effects.
pub fn watch_entity(&mut self, entity: Entity) {
self.descriptor.entities.push(entity);
}
/// Observe the given `component`. This will cause the [`Observer`] to run whenever the [`Event`] is triggered
/// with the given component target.
pub fn with_component(mut self, component: ComponentId) -> Self {
self.descriptor.components.push(component);
self
}
/// Observe the given `event`. This will cause the [`Observer`] to run whenever an event with the given [`ComponentId`]
/// is triggered.
/// # Safety
/// The type of the `event` [`ComponentId`] _must_ match the actual value
/// of the event passed into the observer system.
pub unsafe fn with_event(mut self, event: ComponentId) -> Self {
self.descriptor.events.push(event);
self
}
/// Set the error handler to use for this observer.
///
/// See the [`error` module-level documentation](crate::error) for more information.
pub fn with_error_handler(mut self, error_handler: fn(BevyError, ErrorContext)) -> Self {
self.error_handler = Some(error_handler);
self
}
/// Returns the [`ObserverDescriptor`] for this [`Observer`].
pub fn descriptor(&self) -> &ObserverDescriptor {
&self.descriptor
}
}
impl Component for Observer {
const STORAGE_TYPE: StorageType = StorageType::SparseSet;
type Mutability = Mutable;
fn on_add() -> Option<ComponentHook> {
Some(|world, context| {
let Some(observe) = world.get::<Self>(context.entity) else {
return;
};
let hook = observe.hook_on_add;
hook(world, context);
})
}
}
fn observer_system_runner<E: Event, B: Bundle, S: ObserverSystem<E, B>>(
mut world: DeferredWorld,
observer_trigger: ObserverTrigger,
ptr: PtrMut,
propagate: &mut bool,
) {
let world = world.as_unsafe_world_cell();
// SAFETY: Observer was triggered so must still exist in world
let observer_cell = unsafe {
world
.get_entity(observer_trigger.observer)
.debug_checked_unwrap()
};
// SAFETY: Observer was triggered so must have an `ObserverState`
let mut state = unsafe {
observer_cell
.get_mut::<ObserverState>()
.debug_checked_unwrap()
};
// TODO: Move this check into the observer cache to avoid dynamic dispatch
let last_trigger = world.last_trigger_id();
if state.last_trigger_id == last_trigger {
return;
}
state.last_trigger_id = last_trigger;
// SAFETY: Observer was triggered so must have an `Observer` component.
let error_handler = unsafe {
observer_cell
.get::<Observer>()
.debug_checked_unwrap()
.error_handler
.debug_checked_unwrap()
};
let trigger: Trigger<E, B> = Trigger::new(
// SAFETY: Caller ensures `ptr` is castable to `&mut T`
unsafe { ptr.deref_mut() },
propagate,
observer_trigger,
);
// SAFETY:
// - observer was triggered so must have an `Observer` component.
// - observer cannot be dropped or mutated until after the system pointer is already dropped.
let system: *mut dyn ObserverSystem<E, B> = unsafe {
let mut observe = observer_cell.get_mut::<Observer>().debug_checked_unwrap();
let system = observe.system.downcast_mut::<S>().unwrap();
&mut *system
};
// SAFETY:
// - `update_archetype_component_access` is called first
// - there are no outstanding references to world except a private component
// - system is an `ObserverSystem` so won't mutate world beyond the access of a `DeferredWorld`
// and is never exclusive
// - system is the same type erased system from above
unsafe {
(*system).update_archetype_component_access(world);
match (*system).validate_param_unsafe(world) {
Ok(()) => {
if let Err(err) = (*system).run_unsafe(trigger, world) {
error_handler(
err,
ErrorContext::Observer {
name: (*system).name(),
last_run: (*system).get_last_run(),
},
);
};
(*system).queue_deferred(world.into_deferred());
}
Err(e) => {
if !e.skipped {
error_handler(
e.into(),
ErrorContext::Observer {
name: (*system).name(),
last_run: (*system).get_last_run(),
},
);
}
}
}
}
}
/// A [`ComponentHook`] used by [`Observer`] to handle its [`on-add`](`crate::component::ComponentHooks::on_add`).
///
/// This function exists separate from [`Observer`] to allow [`Observer`] to have its type parameters
/// erased.
///
/// The type parameters of this function _must_ match those used to create the [`Observer`].
/// As such, it is recommended to only use this function within the [`Observer::new`] method to
/// ensure type parameters match.
fn hook_on_add<E: Event, B: Bundle, S: ObserverSystem<E, B>>(
mut world: DeferredWorld<'_>,
HookContext { entity, .. }: HookContext,
) {
world.commands().queue(move |world: &mut World| {
let event_id = E::register_component_id(world);
let mut components = Vec::new();
B::component_ids(&mut world.components_registrator(), &mut |id| {
components.push(id);
});
let mut descriptor = ObserverDescriptor {
events: vec![event_id],
components,
..Default::default()
};
let error_handler = default_error_handler();
// Initialize System
let system: *mut dyn ObserverSystem<E, B> =
if let Some(mut observe) = world.get_mut::<Observer>(entity) {
descriptor.merge(&observe.descriptor);
if observe.error_handler.is_none() {
observe.error_handler = Some(error_handler);
}
let system = observe.system.downcast_mut::<S>().unwrap();
&mut *system
} else {
return;
};
// SAFETY: World reference is exclusive and initialize does not touch system, so references do not alias
unsafe {
(*system).initialize(world);
}
{
let mut entity = world.entity_mut(entity);
if let crate::world::Entry::Vacant(entry) = entity.entry::<ObserverState>() {
entry.insert(ObserverState {
descriptor,
runner: observer_system_runner::<E, B, S>,
..Default::default()
});
}
}
});
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{event::Event, observer::Trigger};
#[derive(Event)]
struct TriggerEvent;
#[test]
#[should_panic(expected = "I failed!")]
fn test_fallible_observer() {
fn system(_: Trigger<TriggerEvent>) -> Result {
Err("I failed!".into())
}
let mut world = World::default();
world.add_observer(system);
Schedule::default().run(&mut world);
world.trigger(TriggerEvent);
}
#[test]
fn test_fallible_observer_ignored_errors() {
#[derive(Resource, Default)]
struct Ran(bool);
fn system(_: Trigger<TriggerEvent>, mut ran: ResMut<Ran>) -> Result {
ran.0 = true;
Err("I failed!".into())
}
let mut world = World::default();
world.init_resource::<Ran>();
let observer = Observer::new(system).with_error_handler(crate::error::ignore);
world.spawn(observer);
Schedule::default().run(&mut world);
world.trigger(TriggerEvent);
assert!(world.resource::<Ran>().0);
}
}

1765
vendor/bevy_ecs/src/query/access.rs vendored Normal file

File diff suppressed because it is too large Load Diff

447
vendor/bevy_ecs/src/query/builder.rs vendored Normal file
View File

@@ -0,0 +1,447 @@
use core::marker::PhantomData;
use crate::{
component::{ComponentId, StorageType},
prelude::*,
};
use super::{FilteredAccess, QueryData, QueryFilter};
/// Builder struct to create [`QueryState`] instances at runtime.
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(Component)]
/// # struct A;
/// #
/// # #[derive(Component)]
/// # struct B;
/// #
/// # #[derive(Component)]
/// # struct C;
/// #
/// let mut world = World::new();
/// let entity_a = world.spawn((A, B)).id();
/// let entity_b = world.spawn((A, C)).id();
///
/// // Instantiate the builder using the type signature of the iterator you will consume
/// let mut query = QueryBuilder::<(Entity, &B)>::new(&mut world)
/// // Add additional terms through builder methods
/// .with::<A>()
/// .without::<C>()
/// .build();
///
/// // Consume the QueryState
/// let (entity, b) = query.single(&world).unwrap();
/// ```
pub struct QueryBuilder<'w, D: QueryData = (), F: QueryFilter = ()> {
access: FilteredAccess<ComponentId>,
world: &'w mut World,
or: bool,
first: bool,
_marker: PhantomData<(D, F)>,
}
impl<'w, D: QueryData, F: QueryFilter> QueryBuilder<'w, D, F> {
/// Creates a new builder with the accesses required for `Q` and `F`
pub fn new(world: &'w mut World) -> Self {
let fetch_state = D::init_state(world);
let filter_state = F::init_state(world);
let mut access = FilteredAccess::default();
D::update_component_access(&fetch_state, &mut access);
// Use a temporary empty FilteredAccess for filters. This prevents them from conflicting with the
// main Query's `fetch_state` access. Filters are allowed to conflict with the main query fetch
// because they are evaluated *before* a specific reference is constructed.
let mut filter_access = FilteredAccess::default();
F::update_component_access(&filter_state, &mut filter_access);
// Merge the temporary filter access with the main access. This ensures that filter access is
// properly considered in a global "cross-query" context (both within systems and across systems).
access.extend(&filter_access);
Self {
access,
world,
or: false,
first: false,
_marker: PhantomData,
}
}
pub(super) fn is_dense(&self) -> bool {
// Note: `component_id` comes from the user in safe code, so we cannot trust it to
// exist. If it doesn't exist we pessimistically assume it's sparse.
let is_dense = |component_id| {
self.world()
.components()
.get_info(component_id)
.is_some_and(|info| info.storage_type() == StorageType::Table)
};
let Ok(component_accesses) = self.access.access().try_iter_component_access() else {
// Access is unbounded, pessimistically assume it's sparse.
return false;
};
component_accesses
.map(|access| *access.index())
.all(is_dense)
&& !self.access.access().has_read_all_components()
&& self.access.with_filters().all(is_dense)
&& self.access.without_filters().all(is_dense)
}
/// Returns a reference to the world passed to [`Self::new`].
pub fn world(&self) -> &World {
self.world
}
/// Returns a mutable reference to the world passed to [`Self::new`].
pub fn world_mut(&mut self) -> &mut World {
self.world
}
/// Adds access to self's underlying [`FilteredAccess`] respecting [`Self::or`] and [`Self::and`]
pub fn extend_access(&mut self, mut access: FilteredAccess<ComponentId>) {
if self.or {
if self.first {
access.required.clear();
self.access.extend(&access);
self.first = false;
} else {
self.access.append_or(&access);
}
} else {
self.access.extend(&access);
}
}
/// Adds accesses required for `T` to self.
pub fn data<T: QueryData>(&mut self) -> &mut Self {
let state = T::init_state(self.world);
let mut access = FilteredAccess::default();
T::update_component_access(&state, &mut access);
self.extend_access(access);
self
}
/// Adds filter from `T` to self.
pub fn filter<T: QueryFilter>(&mut self) -> &mut Self {
let state = T::init_state(self.world);
let mut access = FilteredAccess::default();
T::update_component_access(&state, &mut access);
self.extend_access(access);
self
}
/// Adds [`With<T>`] to the [`FilteredAccess`] of self.
pub fn with<T: Component>(&mut self) -> &mut Self {
self.filter::<With<T>>();
self
}
/// Adds [`With<T>`] to the [`FilteredAccess`] of self from a runtime [`ComponentId`].
pub fn with_id(&mut self, id: ComponentId) -> &mut Self {
let mut access = FilteredAccess::default();
access.and_with(id);
self.extend_access(access);
self
}
/// Adds [`Without<T>`] to the [`FilteredAccess`] of self.
pub fn without<T: Component>(&mut self) -> &mut Self {
self.filter::<Without<T>>();
self
}
/// Adds [`Without<T>`] to the [`FilteredAccess`] of self from a runtime [`ComponentId`].
pub fn without_id(&mut self, id: ComponentId) -> &mut Self {
let mut access = FilteredAccess::default();
access.and_without(id);
self.extend_access(access);
self
}
/// Adds `&T` to the [`FilteredAccess`] of self.
pub fn ref_id(&mut self, id: ComponentId) -> &mut Self {
self.with_id(id);
self.access.add_component_read(id);
self
}
/// Adds `&mut T` to the [`FilteredAccess`] of self.
pub fn mut_id(&mut self, id: ComponentId) -> &mut Self {
self.with_id(id);
self.access.add_component_write(id);
self
}
/// Takes a function over mutable access to a [`QueryBuilder`], calls that function
/// on an empty builder and then adds all accesses from that builder to self as optional.
pub fn optional(&mut self, f: impl Fn(&mut QueryBuilder)) -> &mut Self {
let mut builder = QueryBuilder::new(self.world);
f(&mut builder);
self.access.extend_access(builder.access());
self
}
/// Takes a function over mutable access to a [`QueryBuilder`], calls that function
/// on an empty builder and then adds all accesses from that builder to self.
///
/// Primarily used when inside a [`Self::or`] closure to group several terms.
pub fn and(&mut self, f: impl Fn(&mut QueryBuilder)) -> &mut Self {
let mut builder = QueryBuilder::new(self.world);
f(&mut builder);
let access = builder.access().clone();
self.extend_access(access);
self
}
/// Takes a function over mutable access to a [`QueryBuilder`], calls that function
/// on an empty builder, all accesses added to that builder will become terms in an or expression.
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(Component)]
/// # struct A;
/// #
/// # #[derive(Component)]
/// # struct B;
/// #
/// # let mut world = World::new();
/// #
/// QueryBuilder::<Entity>::new(&mut world).or(|builder| {
/// builder.with::<A>();
/// builder.with::<B>();
/// });
/// // is equivalent to
/// QueryBuilder::<Entity>::new(&mut world).filter::<Or<(With<A>, With<B>)>>();
/// ```
pub fn or(&mut self, f: impl Fn(&mut QueryBuilder)) -> &mut Self {
let mut builder = QueryBuilder::new(self.world);
builder.or = true;
builder.first = true;
f(&mut builder);
self.access.extend(builder.access());
self
}
/// Returns a reference to the [`FilteredAccess`] that will be provided to the built [`Query`].
pub fn access(&self) -> &FilteredAccess<ComponentId> {
&self.access
}
/// Transmute the existing builder adding required accesses.
/// This will maintain all existing accesses.
///
/// If including a filter type see [`Self::transmute_filtered`]
pub fn transmute<NewD: QueryData>(&mut self) -> &mut QueryBuilder<'w, NewD> {
self.transmute_filtered::<NewD, ()>()
}
/// Transmute the existing builder adding required accesses.
/// This will maintain all existing accesses.
pub fn transmute_filtered<NewD: QueryData, NewF: QueryFilter>(
&mut self,
) -> &mut QueryBuilder<'w, NewD, NewF> {
let mut fetch_state = NewD::init_state(self.world);
let filter_state = NewF::init_state(self.world);
NewD::set_access(&mut fetch_state, &self.access);
let mut access = FilteredAccess::default();
NewD::update_component_access(&fetch_state, &mut access);
NewF::update_component_access(&filter_state, &mut access);
self.extend_access(access);
// SAFETY:
// - We have included all required accesses for NewQ and NewF
// - The layout of all QueryBuilder instances is the same
unsafe { core::mem::transmute(self) }
}
/// Create a [`QueryState`] with the accesses of the builder.
///
/// Takes `&mut self` to access the inner world reference while initializing
/// state for the new [`QueryState`]
pub fn build(&mut self) -> QueryState<D, F> {
QueryState::<D, F>::from_builder(self)
}
}
#[cfg(test)]
mod tests {
use crate::{prelude::*, world::FilteredEntityRef};
use std::dbg;
#[derive(Component, PartialEq, Debug)]
struct A(usize);
#[derive(Component, PartialEq, Debug)]
struct B(usize);
#[derive(Component, PartialEq, Debug)]
struct C(usize);
#[test]
fn builder_with_without_static() {
let mut world = World::new();
let entity_a = world.spawn((A(0), B(0))).id();
let entity_b = world.spawn((A(0), C(0))).id();
let mut query_a = QueryBuilder::<Entity>::new(&mut world)
.with::<A>()
.without::<C>()
.build();
assert_eq!(entity_a, query_a.single(&world).unwrap());
let mut query_b = QueryBuilder::<Entity>::new(&mut world)
.with::<A>()
.without::<B>()
.build();
assert_eq!(entity_b, query_b.single(&world).unwrap());
}
#[test]
fn builder_with_without_dynamic() {
let mut world = World::new();
let entity_a = world.spawn((A(0), B(0))).id();
let entity_b = world.spawn((A(0), C(0))).id();
let component_id_a = world.register_component::<A>();
let component_id_b = world.register_component::<B>();
let component_id_c = world.register_component::<C>();
let mut query_a = QueryBuilder::<Entity>::new(&mut world)
.with_id(component_id_a)
.without_id(component_id_c)
.build();
assert_eq!(entity_a, query_a.single(&world).unwrap());
let mut query_b = QueryBuilder::<Entity>::new(&mut world)
.with_id(component_id_a)
.without_id(component_id_b)
.build();
assert_eq!(entity_b, query_b.single(&world).unwrap());
}
#[test]
fn builder_or() {
let mut world = World::new();
world.spawn((A(0), B(0)));
world.spawn(B(0));
world.spawn(C(0));
let mut query_a = QueryBuilder::<Entity>::new(&mut world)
.or(|builder| {
builder.with::<A>();
builder.with::<B>();
})
.build();
assert_eq!(2, query_a.iter(&world).count());
let mut query_b = QueryBuilder::<Entity>::new(&mut world)
.or(|builder| {
builder.with::<A>();
builder.without::<B>();
})
.build();
dbg!(&query_b.component_access);
assert_eq!(2, query_b.iter(&world).count());
let mut query_c = QueryBuilder::<Entity>::new(&mut world)
.or(|builder| {
builder.with::<A>();
builder.with::<B>();
builder.with::<C>();
})
.build();
assert_eq!(3, query_c.iter(&world).count());
}
#[test]
fn builder_transmute() {
let mut world = World::new();
world.spawn(A(0));
world.spawn((A(1), B(0)));
let mut query = QueryBuilder::<()>::new(&mut world)
.with::<B>()
.transmute::<&A>()
.build();
query.iter(&world).for_each(|a| assert_eq!(a.0, 1));
}
#[test]
fn builder_static_components() {
let mut world = World::new();
let entity = world.spawn((A(0), B(1))).id();
let mut query = QueryBuilder::<FilteredEntityRef>::new(&mut world)
.data::<&A>()
.data::<&B>()
.build();
let entity_ref = query.single(&world).unwrap();
assert_eq!(entity, entity_ref.id());
let a = entity_ref.get::<A>().unwrap();
let b = entity_ref.get::<B>().unwrap();
assert_eq!(0, a.0);
assert_eq!(1, b.0);
}
#[test]
fn builder_dynamic_components() {
let mut world = World::new();
let entity = world.spawn((A(0), B(1))).id();
let component_id_a = world.register_component::<A>();
let component_id_b = world.register_component::<B>();
let mut query = QueryBuilder::<FilteredEntityRef>::new(&mut world)
.ref_id(component_id_a)
.ref_id(component_id_b)
.build();
let entity_ref = query.single(&world).unwrap();
assert_eq!(entity, entity_ref.id());
let a = entity_ref.get_by_id(component_id_a).unwrap();
let b = entity_ref.get_by_id(component_id_b).unwrap();
// SAFETY: We set these pointers to point to these components
unsafe {
assert_eq!(0, a.deref::<A>().0);
assert_eq!(1, b.deref::<B>().0);
}
}
/// Regression test for issue #14348
#[test]
fn builder_static_dense_dynamic_sparse() {
#[derive(Component)]
struct Dense;
#[derive(Component)]
#[component(storage = "SparseSet")]
struct Sparse;
let mut world = World::new();
world.spawn(Dense);
world.spawn((Dense, Sparse));
let mut query = QueryBuilder::<&Dense>::new(&mut world)
.with::<Sparse>()
.build();
let matched = query.iter(&world).count();
assert_eq!(matched, 1);
}
}

90
vendor/bevy_ecs/src/query/error.rs vendored Normal file
View File

@@ -0,0 +1,90 @@
use thiserror::Error;
use crate::{
archetype::ArchetypeId,
entity::{Entity, EntityDoesNotExistError},
};
/// An error that occurs when retrieving a specific [`Entity`]'s query result from [`Query`](crate::system::Query) or [`QueryState`](crate::query::QueryState).
// TODO: return the type_name as part of this error
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum QueryEntityError {
/// The given [`Entity`]'s components do not match the query.
///
/// Either it does not have a requested component, or it has a component which the query filters out.
QueryDoesNotMatch(Entity, ArchetypeId),
/// The given [`Entity`] does not exist.
EntityDoesNotExist(EntityDoesNotExistError),
/// The [`Entity`] was requested mutably more than once.
///
/// See [`Query::get_many_mut`](crate::system::Query::get_many_mut) for an example.
AliasedMutability(Entity),
}
impl From<EntityDoesNotExistError> for QueryEntityError {
fn from(error: EntityDoesNotExistError) -> Self {
QueryEntityError::EntityDoesNotExist(error)
}
}
impl core::error::Error for QueryEntityError {}
impl core::fmt::Display for QueryEntityError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match *self {
Self::QueryDoesNotMatch(entity, _) => {
write!(f, "The query does not match entity {entity}")
}
Self::EntityDoesNotExist(error) => {
write!(f, "{error}")
}
Self::AliasedMutability(entity) => {
write!(
f,
"The entity with ID {entity} was requested mutably more than once"
)
}
}
}
}
/// An error that occurs when evaluating a [`Query`](crate::system::Query) or [`QueryState`](crate::query::QueryState) as a single expected result via
/// [`single`](crate::system::Query::single) or [`single_mut`](crate::system::Query::single_mut).
#[derive(Debug, Error)]
pub enum QuerySingleError {
/// No entity fits the query.
#[error("No entities fit the query {0}")]
NoEntities(&'static str),
/// Multiple entities fit the query.
#[error("Multiple entities fit the query {0}")]
MultipleEntities(&'static str),
}
#[cfg(test)]
mod test {
use crate::{prelude::World, query::QueryEntityError};
use bevy_ecs_macros::Component;
#[test]
fn query_does_not_match() {
let mut world = World::new();
#[derive(Component)]
struct Present1;
#[derive(Component)]
struct Present2;
#[derive(Component, Debug, PartialEq)]
struct NotPresent;
let entity = world.spawn((Present1, Present2));
let (entity, archetype_id) = (entity.id(), entity.archetype().id());
let result = world.query::<&NotPresent>().get(&world, entity);
assert_eq!(
result,
Err(QueryEntityError::QueryDoesNotMatch(entity, archetype_id))
);
}
}

2593
vendor/bevy_ecs/src/query/fetch.rs vendored Normal file

File diff suppressed because it is too large Load Diff

1058
vendor/bevy_ecs/src/query/filter.rs vendored Normal file

File diff suppressed because it is too large Load Diff

2952
vendor/bevy_ecs/src/query/iter.rs vendored Normal file

File diff suppressed because it is too large Load Diff

931
vendor/bevy_ecs/src/query/mod.rs vendored Normal file
View File

@@ -0,0 +1,931 @@
//! Contains APIs for retrieving component data from the world.
mod access;
mod builder;
mod error;
mod fetch;
mod filter;
mod iter;
mod par_iter;
mod state;
mod world_query;
pub use access::*;
pub use bevy_ecs_macros::{QueryData, QueryFilter};
pub use builder::*;
pub use error::*;
pub use fetch::*;
pub use filter::*;
pub use iter::*;
pub use par_iter::*;
pub use state::*;
pub use world_query::*;
/// A debug checked version of [`Option::unwrap_unchecked`]. Will panic in
/// debug modes if unwrapping a `None` or `Err` value in debug mode, but is
/// equivalent to `Option::unwrap_unchecked` or `Result::unwrap_unchecked`
/// in release mode.
pub(crate) trait DebugCheckedUnwrap {
type Item;
/// # Panics
/// Panics if the value is `None` or `Err`, only in debug mode.
///
/// # Safety
/// This must never be called on a `None` or `Err` value. This can
/// only be called on `Some` or `Ok` values.
unsafe fn debug_checked_unwrap(self) -> Self::Item;
}
// These two impls are explicitly split to ensure that the unreachable! macro
// does not cause inlining to fail when compiling in release mode.
#[cfg(debug_assertions)]
impl<T> DebugCheckedUnwrap for Option<T> {
type Item = T;
#[inline(always)]
#[track_caller]
unsafe fn debug_checked_unwrap(self) -> Self::Item {
if let Some(inner) = self {
inner
} else {
unreachable!()
}
}
}
// These two impls are explicitly split to ensure that the unreachable! macro
// does not cause inlining to fail when compiling in release mode.
#[cfg(debug_assertions)]
impl<T, U> DebugCheckedUnwrap for Result<T, U> {
type Item = T;
#[inline(always)]
#[track_caller]
unsafe fn debug_checked_unwrap(self) -> Self::Item {
if let Ok(inner) = self {
inner
} else {
unreachable!()
}
}
}
// These two impls are explicitly split to ensure that the unreachable! macro
// does not cause inlining to fail when compiling in release mode.
#[cfg(not(debug_assertions))]
impl<T, U> DebugCheckedUnwrap for Result<T, U> {
type Item = T;
#[inline(always)]
#[track_caller]
unsafe fn debug_checked_unwrap(self) -> Self::Item {
if let Ok(inner) = self {
inner
} else {
core::hint::unreachable_unchecked()
}
}
}
#[cfg(not(debug_assertions))]
impl<T> DebugCheckedUnwrap for Option<T> {
type Item = T;
#[inline(always)]
unsafe fn debug_checked_unwrap(self) -> Self::Item {
if let Some(inner) = self {
inner
} else {
core::hint::unreachable_unchecked()
}
}
}
#[cfg(test)]
#[expect(clippy::print_stdout, reason = "Allowed in tests.")]
mod tests {
use crate::{
archetype::Archetype,
component::{Component, ComponentId, Components, Tick},
prelude::{AnyOf, Changed, Entity, Or, QueryState, Res, ResMut, Resource, With, Without},
query::{
ArchetypeFilter, FilteredAccess, Has, QueryCombinationIter, QueryData,
ReadOnlyQueryData, WorldQuery,
},
schedule::{IntoScheduleConfigs, Schedule},
storage::{Table, TableRow},
system::{assert_is_system, IntoSystem, Query, System, SystemState},
world::{unsafe_world_cell::UnsafeWorldCell, World},
};
use alloc::{vec, vec::Vec};
use bevy_ecs_macros::QueryFilter;
use core::{any::type_name, fmt::Debug, hash::Hash};
use std::{collections::HashSet, println};
#[derive(Component, Debug, Hash, Eq, PartialEq, Clone, Copy, PartialOrd, Ord)]
struct A(usize);
#[derive(Component, Debug, Hash, Eq, PartialEq, Clone, Copy)]
struct B(usize);
#[derive(Component, Debug, Eq, PartialEq, Clone, Copy)]
struct C(usize);
#[derive(Component, Debug, Eq, PartialEq, Clone, Copy)]
struct D(usize);
#[derive(Component, Debug, Hash, Eq, PartialEq, Clone, Copy, PartialOrd, Ord)]
#[component(storage = "SparseSet")]
struct Sparse(usize);
#[test]
fn query() {
let mut world = World::new();
world.spawn((A(1), B(1)));
world.spawn(A(2));
let values = world.query::<&A>().iter(&world).collect::<HashSet<&A>>();
assert!(values.contains(&A(1)));
assert!(values.contains(&A(2)));
for (_a, mut b) in world.query::<(&A, &mut B)>().iter_mut(&mut world) {
b.0 = 3;
}
let values = world.query::<&B>().iter(&world).collect::<Vec<&B>>();
assert_eq!(values, vec![&B(3)]);
}
#[test]
fn query_filtered_exactsizeiterator_len() {
fn choose(n: usize, k: usize) -> usize {
if n == 0 || k == 0 || n < k {
return 0;
}
let ks = 1..=k;
let ns = (n - k + 1..=n).rev();
ks.zip(ns).fold(1, |acc, (k, n)| acc * n / k)
}
fn assert_combination<D, F, const K: usize>(world: &mut World, expected_size: usize)
where
D: ReadOnlyQueryData,
F: ArchetypeFilter,
{
let mut query = world.query_filtered::<D, F>();
let query_type = type_name::<QueryCombinationIter<D, F, K>>();
let iter = query.iter_combinations::<K>(world);
assert_all_sizes_iterator_equal(iter, expected_size, 0, query_type);
let iter = query.iter_combinations::<K>(world);
assert_all_sizes_iterator_equal(iter, expected_size, 1, query_type);
let iter = query.iter_combinations::<K>(world);
assert_all_sizes_iterator_equal(iter, expected_size, 5, query_type);
}
fn assert_all_sizes_equal<D, F>(world: &mut World, expected_size: usize)
where
D: ReadOnlyQueryData,
F: ArchetypeFilter,
{
let mut query = world.query_filtered::<D, F>();
let query_type = type_name::<QueryState<D, F>>();
assert_all_exact_sizes_iterator_equal(query.iter(world), expected_size, 0, query_type);
assert_all_exact_sizes_iterator_equal(query.iter(world), expected_size, 1, query_type);
assert_all_exact_sizes_iterator_equal(query.iter(world), expected_size, 5, query_type);
let expected = expected_size;
assert_combination::<D, F, 1>(world, choose(expected, 1));
assert_combination::<D, F, 2>(world, choose(expected, 2));
assert_combination::<D, F, 5>(world, choose(expected, 5));
assert_combination::<D, F, 43>(world, choose(expected, 43));
assert_combination::<D, F, 64>(world, choose(expected, 64));
}
fn assert_all_exact_sizes_iterator_equal(
iterator: impl ExactSizeIterator,
expected_size: usize,
skip: usize,
query_type: &'static str,
) {
let len = iterator.len();
println!("len: {len}");
assert_all_sizes_iterator_equal(iterator, expected_size, skip, query_type);
assert_eq!(len, expected_size);
}
fn assert_all_sizes_iterator_equal(
mut iterator: impl Iterator,
expected_size: usize,
skip: usize,
query_type: &'static str,
) {
let expected_size = expected_size.saturating_sub(skip);
for _ in 0..skip {
iterator.next();
}
let size_hint_0 = iterator.size_hint().0;
let size_hint_1 = iterator.size_hint().1;
// `count` tests that not only it is the expected value, but also
// the value is accurate to what the query returns.
let count = iterator.count();
// This will show up when one of the asserts in this function fails
println!(
"query declared sizes: \n\
for query: {query_type} \n\
expected: {expected_size} \n\
size_hint().0: {size_hint_0} \n\
size_hint().1: {size_hint_1:?} \n\
count(): {count}"
);
assert_eq!(size_hint_0, expected_size);
assert_eq!(size_hint_1, Some(expected_size));
assert_eq!(count, expected_size);
}
let mut world = World::new();
world.spawn((A(1), B(1)));
world.spawn(A(2));
world.spawn(A(3));
assert_all_sizes_equal::<&A, With<B>>(&mut world, 1);
assert_all_sizes_equal::<&A, Without<B>>(&mut world, 2);
let mut world = World::new();
world.spawn((A(1), B(1), C(1)));
world.spawn((A(2), B(2)));
world.spawn((A(3), B(3)));
world.spawn((A(4), C(4)));
world.spawn((A(5), C(5)));
world.spawn((A(6), C(6)));
world.spawn(A(7));
world.spawn(A(8));
world.spawn(A(9));
world.spawn(A(10));
// With/Without for B and C
assert_all_sizes_equal::<&A, With<B>>(&mut world, 3);
assert_all_sizes_equal::<&A, With<C>>(&mut world, 4);
assert_all_sizes_equal::<&A, Without<B>>(&mut world, 7);
assert_all_sizes_equal::<&A, Without<C>>(&mut world, 6);
// With/Without (And) combinations
assert_all_sizes_equal::<&A, (With<B>, With<C>)>(&mut world, 1);
assert_all_sizes_equal::<&A, (With<B>, Without<C>)>(&mut world, 2);
assert_all_sizes_equal::<&A, (Without<B>, With<C>)>(&mut world, 3);
assert_all_sizes_equal::<&A, (Without<B>, Without<C>)>(&mut world, 4);
// With/Without Or<()> combinations
assert_all_sizes_equal::<&A, Or<(With<B>, With<C>)>>(&mut world, 6);
assert_all_sizes_equal::<&A, Or<(With<B>, Without<C>)>>(&mut world, 7);
assert_all_sizes_equal::<&A, Or<(Without<B>, With<C>)>>(&mut world, 8);
assert_all_sizes_equal::<&A, Or<(Without<B>, Without<C>)>>(&mut world, 9);
assert_all_sizes_equal::<&A, (Or<(With<B>,)>, Or<(With<C>,)>)>(&mut world, 1);
assert_all_sizes_equal::<&A, Or<(Or<(With<B>, With<C>)>, With<D>)>>(&mut world, 6);
for i in 11..14 {
world.spawn((A(i), D(i)));
}
assert_all_sizes_equal::<&A, Or<(Or<(With<B>, With<C>)>, With<D>)>>(&mut world, 9);
assert_all_sizes_equal::<&A, Or<(Or<(With<B>, With<C>)>, Without<D>)>>(&mut world, 10);
// a fair amount of entities
for i in 14..20 {
world.spawn((C(i), D(i)));
}
assert_all_sizes_equal::<Entity, (With<C>, With<D>)>(&mut world, 6);
}
// the order of the combinations is not guaranteed, but each unique combination is present
fn check_combinations<T: Ord + Hash + Debug, const K: usize>(
values: HashSet<[&T; K]>,
expected: HashSet<[&T; K]>,
) {
values.iter().for_each(|pair| {
let mut sorted = *pair;
sorted.sort();
assert!(expected.contains(&sorted),
"the results of iter_combinations should contain this combination {:?}. Expected: {:?}, got: {:?}",
&sorted, &expected, &values);
});
}
#[test]
fn query_iter_combinations() {
let mut world = World::new();
world.spawn((A(1), B(1)));
world.spawn(A(2));
world.spawn(A(3));
world.spawn(A(4));
let values: HashSet<[&A; 2]> = world.query::<&A>().iter_combinations(&world).collect();
check_combinations(
values,
HashSet::from([
[&A(1), &A(2)],
[&A(1), &A(3)],
[&A(1), &A(4)],
[&A(2), &A(3)],
[&A(2), &A(4)],
[&A(3), &A(4)],
]),
);
let mut a_query = world.query::<&A>();
let values: HashSet<[&A; 3]> = a_query.iter_combinations(&world).collect();
check_combinations(
values,
HashSet::from([
[&A(1), &A(2), &A(3)],
[&A(1), &A(2), &A(4)],
[&A(1), &A(3), &A(4)],
[&A(2), &A(3), &A(4)],
]),
);
let mut b_query = world.query::<&B>();
assert_eq!(
b_query.iter_combinations::<2>(&world).size_hint(),
(0, Some(0))
);
let values: Vec<[&B; 2]> = b_query.iter_combinations(&world).collect();
assert_eq!(values, Vec::<[&B; 2]>::new());
}
#[test]
fn query_filtered_iter_combinations() {
use bevy_ecs::query::{Added, Or, With, Without};
let mut world = World::new();
world.spawn((A(1), B(1)));
world.spawn(A(2));
world.spawn(A(3));
world.spawn(A(4));
let mut a_wout_b = world.query_filtered::<&A, Without<B>>();
let values: HashSet<[&A; 2]> = a_wout_b.iter_combinations(&world).collect();
check_combinations(
values,
HashSet::from([[&A(2), &A(3)], [&A(2), &A(4)], [&A(3), &A(4)]]),
);
let values: HashSet<[&A; 3]> = a_wout_b.iter_combinations(&world).collect();
check_combinations(values, HashSet::from([[&A(2), &A(3), &A(4)]]));
let mut query = world.query_filtered::<&A, Or<(With<A>, With<B>)>>();
let values: HashSet<[&A; 2]> = query.iter_combinations(&world).collect();
check_combinations(
values,
HashSet::from([
[&A(1), &A(2)],
[&A(1), &A(3)],
[&A(1), &A(4)],
[&A(2), &A(3)],
[&A(2), &A(4)],
[&A(3), &A(4)],
]),
);
let mut query = world.query_filtered::<&mut A, Without<B>>();
let mut combinations = query.iter_combinations_mut(&mut world);
while let Some([mut a, mut b, mut c]) = combinations.fetch_next() {
a.0 += 10;
b.0 += 100;
c.0 += 1000;
}
let values: HashSet<[&A; 3]> = a_wout_b.iter_combinations(&world).collect();
check_combinations(values, HashSet::from([[&A(12), &A(103), &A(1004)]]));
// Check if Added<T>, Changed<T> works
let mut world = World::new();
world.spawn((A(1), B(1)));
world.spawn((A(2), B(2)));
world.spawn((A(3), B(3)));
world.spawn((A(4), B(4)));
let mut query_added = world.query_filtered::<&A, Added<A>>();
world.clear_trackers();
world.spawn(A(5));
assert_eq!(query_added.iter_combinations::<2>(&world).count(), 0);
world.clear_trackers();
world.spawn(A(6));
world.spawn(A(7));
assert_eq!(query_added.iter_combinations::<2>(&world).count(), 1);
world.clear_trackers();
world.spawn(A(8));
world.spawn(A(9));
world.spawn(A(10));
assert_eq!(query_added.iter_combinations::<2>(&world).count(), 3);
}
#[test]
fn query_iter_combinations_sparse() {
let mut world = World::new();
world.spawn_batch((1..=4).map(Sparse));
let values: HashSet<[&Sparse; 3]> =
world.query::<&Sparse>().iter_combinations(&world).collect();
check_combinations(
values,
HashSet::from([
[&Sparse(1), &Sparse(2), &Sparse(3)],
[&Sparse(1), &Sparse(2), &Sparse(4)],
[&Sparse(1), &Sparse(3), &Sparse(4)],
[&Sparse(2), &Sparse(3), &Sparse(4)],
]),
);
}
#[test]
fn get_many_only_mut_checks_duplicates() {
let mut world = World::new();
let id = world.spawn(A(10)).id();
let mut query_state = world.query::<&mut A>();
let mut query = query_state.query_mut(&mut world);
let result = query.get_many([id, id]);
assert_eq!(result, Ok([&A(10), &A(10)]));
let mut_result = query.get_many_mut([id, id]);
assert!(mut_result.is_err());
}
#[test]
fn multi_storage_query() {
let mut world = World::new();
world.spawn((Sparse(1), B(2)));
world.spawn(Sparse(2));
let values = world
.query::<&Sparse>()
.iter(&world)
.collect::<HashSet<&Sparse>>();
assert!(values.contains(&Sparse(1)));
assert!(values.contains(&Sparse(2)));
for (_a, mut b) in world.query::<(&Sparse, &mut B)>().iter_mut(&mut world) {
b.0 = 3;
}
let values = world.query::<&B>().iter(&world).collect::<Vec<&B>>();
assert_eq!(values, vec![&B(3)]);
}
#[test]
fn any_query() {
let mut world = World::new();
world.spawn((A(1), B(2)));
world.spawn(A(2));
world.spawn(C(3));
let values: Vec<(Option<&A>, Option<&B>)> =
world.query::<AnyOf<(&A, &B)>>().iter(&world).collect();
assert_eq!(
values,
vec![(Some(&A(1)), Some(&B(2))), (Some(&A(2)), None),]
);
}
#[test]
fn has_query() {
let mut world = World::new();
world.spawn((A(1), B(1)));
world.spawn(A(2));
world.spawn((A(3), B(1)));
world.spawn(A(4));
let values: HashSet<(&A, bool)> = world.query::<(&A, Has<B>)>().iter(&world).collect();
assert!(values.contains(&(&A(1), true)));
assert!(values.contains(&(&A(2), false)));
assert!(values.contains(&(&A(3), true)));
assert!(values.contains(&(&A(4), false)));
}
#[test]
#[should_panic = "&mut bevy_ecs::query::tests::A conflicts with a previous access in this query."]
fn self_conflicting_worldquery() {
#[derive(QueryData)]
#[query_data(mutable)]
struct SelfConflicting {
a: &'static mut A,
b: &'static mut A,
}
let mut world = World::new();
world.query::<SelfConflicting>();
}
#[test]
fn derived_worldqueries() {
let mut world = World::new();
world.spawn((A(10), B(18), C(3), Sparse(4)));
world.spawn((A(101), B(148), C(13)));
world.spawn((A(51), B(46), Sparse(72)));
world.spawn((A(398), C(6), Sparse(9)));
world.spawn((B(11), C(28), Sparse(92)));
world.spawn((C(18348), Sparse(101)));
world.spawn((B(839), Sparse(5)));
world.spawn((B(6721), C(122)));
world.spawn((A(220), Sparse(63)));
world.spawn((A(1092), C(382)));
world.spawn((A(2058), B(3019)));
world.spawn((B(38), C(8), Sparse(100)));
world.spawn((A(111), C(52), Sparse(1)));
world.spawn((A(599), B(39), Sparse(13)));
world.spawn((A(55), B(66), C(77)));
world.spawn_empty();
{
#[derive(QueryData)]
struct CustomAB {
a: &'static A,
b: &'static B,
}
let custom_param_data = world
.query::<CustomAB>()
.iter(&world)
.map(|item| (*item.a, *item.b))
.collect::<Vec<_>>();
let normal_data = world
.query::<(&A, &B)>()
.iter(&world)
.map(|(a, b)| (*a, *b))
.collect::<Vec<_>>();
assert_eq!(custom_param_data, normal_data);
}
{
#[derive(QueryData)]
struct FancyParam {
e: Entity,
b: &'static B,
opt: Option<&'static Sparse>,
}
let custom_param_data = world
.query::<FancyParam>()
.iter(&world)
.map(|fancy| (fancy.e, *fancy.b, fancy.opt.copied()))
.collect::<Vec<_>>();
let normal_data = world
.query::<(Entity, &B, Option<&Sparse>)>()
.iter(&world)
.map(|(e, b, opt)| (e, *b, opt.copied()))
.collect::<Vec<_>>();
assert_eq!(custom_param_data, normal_data);
}
{
#[derive(QueryData)]
struct MaybeBSparse {
blah: Option<(&'static B, &'static Sparse)>,
}
#[derive(QueryData)]
struct MatchEverything {
abcs: AnyOf<(&'static A, &'static B, &'static C)>,
opt_bsparse: MaybeBSparse,
}
let custom_param_data = world
.query::<MatchEverything>()
.iter(&world)
.map(
|MatchEverythingItem {
abcs: (a, b, c),
opt_bsparse: MaybeBSparseItem { blah: bsparse },
}| {
(
(a.copied(), b.copied(), c.copied()),
bsparse.map(|(b, sparse)| (*b, *sparse)),
)
},
)
.collect::<Vec<_>>();
let normal_data = world
.query::<(AnyOf<(&A, &B, &C)>, Option<(&B, &Sparse)>)>()
.iter(&world)
.map(|((a, b, c), bsparse)| {
(
(a.copied(), b.copied(), c.copied()),
bsparse.map(|(b, sparse)| (*b, *sparse)),
)
})
.collect::<Vec<_>>();
assert_eq!(custom_param_data, normal_data);
}
{
#[derive(QueryFilter)]
struct AOrBFilter {
a: Or<(With<A>, With<B>)>,
}
#[derive(QueryFilter)]
struct NoSparseThatsSlow {
no: Without<Sparse>,
}
let custom_param_entities = world
.query_filtered::<Entity, (AOrBFilter, NoSparseThatsSlow)>()
.iter(&world)
.collect::<Vec<_>>();
let normal_entities = world
.query_filtered::<Entity, (Or<(With<A>, With<B>)>, Without<Sparse>)>()
.iter(&world)
.collect::<Vec<_>>();
assert_eq!(custom_param_entities, normal_entities);
}
{
#[derive(QueryFilter)]
struct CSparseFilter {
tuple_structs_pls: With<C>,
ugh: With<Sparse>,
}
let custom_param_entities = world
.query_filtered::<Entity, CSparseFilter>()
.iter(&world)
.collect::<Vec<_>>();
let normal_entities = world
.query_filtered::<Entity, (With<C>, With<Sparse>)>()
.iter(&world)
.collect::<Vec<_>>();
assert_eq!(custom_param_entities, normal_entities);
}
{
#[derive(QueryFilter)]
struct WithoutComps {
_1: Without<A>,
_2: Without<B>,
_3: Without<C>,
}
let custom_param_entities = world
.query_filtered::<Entity, WithoutComps>()
.iter(&world)
.collect::<Vec<_>>();
let normal_entities = world
.query_filtered::<Entity, (Without<A>, Without<B>, Without<C>)>()
.iter(&world)
.collect::<Vec<_>>();
assert_eq!(custom_param_entities, normal_entities);
}
{
#[derive(QueryData)]
struct IterCombAB {
a: &'static A,
b: &'static B,
}
let custom_param_data = world
.query::<IterCombAB>()
.iter_combinations::<2>(&world)
.map(|[item0, item1]| [(*item0.a, *item0.b), (*item1.a, *item1.b)])
.collect::<Vec<_>>();
let normal_data = world
.query::<(&A, &B)>()
.iter_combinations(&world)
.map(|[(a0, b0), (a1, b1)]| [(*a0, *b0), (*a1, *b1)])
.collect::<Vec<_>>();
assert_eq!(custom_param_data, normal_data);
}
}
#[test]
fn many_entities() {
let mut world = World::new();
world.spawn((A(0), B(0)));
world.spawn((A(0), B(0)));
world.spawn(A(0));
world.spawn(B(0));
{
fn system(has_a: Query<Entity, With<A>>, has_a_and_b: Query<(&A, &B)>) {
assert_eq!(has_a_and_b.iter_many(&has_a).count(), 2);
}
let mut system = IntoSystem::into_system(system);
system.initialize(&mut world);
system.run((), &mut world);
}
{
fn system(has_a: Query<Entity, With<A>>, mut b_query: Query<&mut B>) {
let mut iter = b_query.iter_many_mut(&has_a);
while let Some(mut b) = iter.fetch_next() {
b.0 = 1;
}
}
let mut system = IntoSystem::into_system(system);
system.initialize(&mut world);
system.run((), &mut world);
}
{
fn system(query: Query<(Option<&A>, &B)>) {
for (maybe_a, b) in &query {
match maybe_a {
Some(_) => assert_eq!(b.0, 1),
None => assert_eq!(b.0, 0),
}
}
}
let mut system = IntoSystem::into_system(system);
system.initialize(&mut world);
system.run((), &mut world);
}
}
#[test]
fn mut_to_immut_query_methods_have_immut_item() {
#[derive(Component)]
struct Foo;
let mut world = World::new();
let e = world.spawn(Foo).id();
// state
let mut q = world.query::<&mut Foo>();
let _: Option<&Foo> = q.iter(&world).next();
let _: Option<[&Foo; 2]> = q.iter_combinations::<2>(&world).next();
let _: Option<&Foo> = q.iter_manual(&world).next();
let _: Option<&Foo> = q.iter_many(&world, [e]).next();
q.iter(&world).for_each(|_: &Foo| ());
let _: Option<&Foo> = q.get(&world, e).ok();
let _: Option<&Foo> = q.get_manual(&world, e).ok();
let _: Option<[&Foo; 1]> = q.get_many(&world, [e]).ok();
let _: Option<&Foo> = q.single(&world).ok();
let _: &Foo = q.single(&world).unwrap();
// system param
let mut q = SystemState::<Query<&mut Foo>>::new(&mut world);
let q = q.get_mut(&mut world);
let _: Option<&Foo> = q.iter().next();
let _: Option<[&Foo; 2]> = q.iter_combinations::<2>().next();
let _: Option<&Foo> = q.iter_many([e]).next();
q.iter().for_each(|_: &Foo| ());
let _: Option<&Foo> = q.get(e).ok();
let _: Option<[&Foo; 1]> = q.get_many([e]).ok();
let _: Option<&Foo> = q.single().ok();
let _: &Foo = q.single().unwrap();
}
// regression test for https://github.com/bevyengine/bevy/pull/8029
#[test]
fn par_iter_mut_change_detection() {
let mut world = World::new();
world.spawn((A(1), B(1)));
fn propagate_system(mut query: Query<(&A, &mut B), Changed<A>>) {
query.par_iter_mut().for_each(|(a, mut b)| {
b.0 = a.0;
});
}
fn modify_system(mut query: Query<&mut A>) {
for mut a in &mut query {
a.0 = 2;
}
}
let mut schedule = Schedule::default();
schedule.add_systems((propagate_system, modify_system).chain());
schedule.run(&mut world);
world.clear_trackers();
schedule.run(&mut world);
world.clear_trackers();
let values = world.query::<&B>().iter(&world).collect::<Vec<&B>>();
assert_eq!(values, vec![&B(2)]);
}
#[derive(Resource)]
struct R;
/// `QueryData` that performs read access on R to test that resource access is tracked
struct ReadsRData;
/// SAFETY:
/// `update_component_access` adds resource read access for `R`.
/// `update_archetype_component_access` does nothing, as this accesses no components.
unsafe impl WorldQuery for ReadsRData {
type Fetch<'w> = ();
type State = ComponentId;
fn shrink_fetch<'wlong: 'wshort, 'wshort>(_: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {}
unsafe fn init_fetch<'w>(
_world: UnsafeWorldCell<'w>,
_state: &Self::State,
_last_run: Tick,
_this_run: Tick,
) -> Self::Fetch<'w> {
}
const IS_DENSE: bool = true;
#[inline]
unsafe fn set_archetype<'w>(
_fetch: &mut Self::Fetch<'w>,
_state: &Self::State,
_archetype: &'w Archetype,
_table: &Table,
) {
}
#[inline]
unsafe fn set_table<'w>(
_fetch: &mut Self::Fetch<'w>,
_state: &Self::State,
_table: &'w Table,
) {
}
fn update_component_access(
&component_id: &Self::State,
access: &mut FilteredAccess<ComponentId>,
) {
assert!(
!access.access().has_resource_write(component_id),
"ReadsRData conflicts with a previous access in this query. Shared access cannot coincide with exclusive access."
);
access.add_resource_read(component_id);
}
fn init_state(world: &mut World) -> Self::State {
world.components_registrator().register_resource::<R>()
}
fn get_state(components: &Components) -> Option<Self::State> {
components.resource_id::<R>()
}
fn matches_component_set(
_state: &Self::State,
_set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool {
true
}
}
/// SAFETY: `Self` is the same as `Self::ReadOnly`
unsafe impl QueryData for ReadsRData {
const IS_READ_ONLY: bool = true;
type ReadOnly = Self;
type Item<'w> = ();
fn shrink<'wlong: 'wshort, 'wshort>(_item: Self::Item<'wlong>) -> Self::Item<'wshort> {}
#[inline(always)]
unsafe fn fetch<'w>(
_fetch: &mut Self::Fetch<'w>,
_entity: Entity,
_table_row: TableRow,
) -> Self::Item<'w> {
}
}
/// SAFETY: access is read only
unsafe impl ReadOnlyQueryData for ReadsRData {}
#[test]
fn read_res_read_res_no_conflict() {
fn system(_q1: Query<ReadsRData, With<A>>, _q2: Query<ReadsRData, Without<A>>) {}
assert_is_system(system);
}
#[test]
fn read_res_sets_archetype_component_access() {
let mut world = World::new();
fn read_query(_q: Query<ReadsRData, With<A>>) {}
let mut read_query = IntoSystem::into_system(read_query);
read_query.initialize(&mut world);
fn read_res(_r: Res<R>) {}
let mut read_res = IntoSystem::into_system(read_res);
read_res.initialize(&mut world);
fn write_res(_r: ResMut<R>) {}
let mut write_res = IntoSystem::into_system(write_res);
write_res.initialize(&mut world);
assert!(read_query
.archetype_component_access()
.is_compatible(read_res.archetype_component_access()));
assert!(!read_query
.archetype_component_access()
.is_compatible(write_res.archetype_component_access()));
}
}

463
vendor/bevy_ecs/src/query/par_iter.rs vendored Normal file
View File

@@ -0,0 +1,463 @@
use crate::{
batching::BatchingStrategy,
component::Tick,
entity::{EntityEquivalent, UniqueEntityEquivalentVec},
world::unsafe_world_cell::UnsafeWorldCell,
};
use super::{QueryData, QueryFilter, QueryItem, QueryState, ReadOnlyQueryData};
use alloc::vec::Vec;
/// A parallel iterator over query results of a [`Query`](crate::system::Query).
///
/// This struct is created by the [`Query::par_iter`](crate::system::Query::par_iter) and
/// [`Query::par_iter_mut`](crate::system::Query::par_iter_mut) methods.
pub struct QueryParIter<'w, 's, D: QueryData, F: QueryFilter> {
pub(crate) world: UnsafeWorldCell<'w>,
pub(crate) state: &'s QueryState<D, F>,
pub(crate) last_run: Tick,
pub(crate) this_run: Tick,
pub(crate) batching_strategy: BatchingStrategy,
}
impl<'w, 's, D: QueryData, F: QueryFilter> QueryParIter<'w, 's, D, F> {
/// Changes the batching strategy used when iterating.
///
/// For more information on how this affects the resultant iteration, see
/// [`BatchingStrategy`].
pub fn batching_strategy(mut self, strategy: BatchingStrategy) -> Self {
self.batching_strategy = strategy;
self
}
/// Runs `func` on each query result in parallel.
///
/// # Panics
/// If the [`ComputeTaskPool`] is not initialized. If using this from a query that is being
/// initialized and run from the ECS scheduler, this should never panic.
///
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
#[inline]
pub fn for_each<FN: Fn(QueryItem<'w, D>) + Send + Sync + Clone>(self, func: FN) {
self.for_each_init(|| {}, |_, item| func(item));
}
/// Runs `func` on each query result in parallel on a value returned by `init`.
///
/// `init` may be called multiple times per thread, and the values returned may be discarded between tasks on any given thread.
/// Callers should avoid using this function as if it were a parallel version
/// of [`Iterator::fold`].
///
/// # Example
///
/// ```
/// use bevy_utils::Parallel;
/// use crate::{bevy_ecs::prelude::Component, bevy_ecs::system::Query};
/// #[derive(Component)]
/// struct T;
/// fn system(query: Query<&T>){
/// let mut queue: Parallel<usize> = Parallel::default();
/// // queue.borrow_local_mut() will get or create a thread_local queue for each task/thread;
/// query.par_iter().for_each_init(|| queue.borrow_local_mut(),|local_queue, item| {
/// **local_queue += 1;
/// });
///
/// // collect value from every thread
/// let entity_count: usize = queue.iter_mut().map(|v| *v).sum();
/// }
/// ```
///
/// # Panics
/// If the [`ComputeTaskPool`] is not initialized. If using this from a query that is being
/// initialized and run from the ECS scheduler, this should never panic.
///
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
#[inline]
pub fn for_each_init<FN, INIT, T>(self, init: INIT, func: FN)
where
FN: Fn(&mut T, QueryItem<'w, D>) + Send + Sync + Clone,
INIT: Fn() -> T + Sync + Send + Clone,
{
let func = |mut init, item| {
func(&mut init, item);
init
};
#[cfg(any(target_arch = "wasm32", not(feature = "multi_threaded")))]
{
let init = init();
// SAFETY:
// This method can only be called once per instance of QueryParIter,
// which ensures that mutable queries cannot be executed multiple times at once.
// Mutable instances of QueryParIter can only be created via an exclusive borrow of a
// Query or a World, which ensures that multiple aliasing QueryParIters cannot exist
// at the same time.
unsafe {
self.state
.query_unchecked_manual_with_ticks(self.world, self.last_run, self.this_run)
.into_iter()
.fold(init, func);
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))]
{
let thread_count = bevy_tasks::ComputeTaskPool::get().thread_num();
if thread_count <= 1 {
let init = init();
// SAFETY: See the safety comment above.
unsafe {
self.state
.query_unchecked_manual_with_ticks(self.world, self.last_run, self.this_run)
.into_iter()
.fold(init, func);
}
} else {
// Need a batch size of at least 1.
let batch_size = self.get_batch_size(thread_count).max(1);
// SAFETY: See the safety comment above.
unsafe {
self.state.par_fold_init_unchecked_manual(
init,
self.world,
batch_size,
func,
self.last_run,
self.this_run,
);
}
}
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))]
fn get_batch_size(&self, thread_count: usize) -> usize {
let max_items = || {
let id_iter = self.state.matched_storage_ids.iter();
if self.state.is_dense {
// SAFETY: We only access table metadata.
let tables = unsafe { &self.world.world_metadata().storages().tables };
id_iter
// SAFETY: The if check ensures that matched_storage_ids stores TableIds
.map(|id| unsafe { tables[id.table_id].entity_count() })
.max()
} else {
let archetypes = &self.world.archetypes();
id_iter
// SAFETY: The if check ensures that matched_storage_ids stores ArchetypeIds
.map(|id| unsafe { archetypes[id.archetype_id].len() })
.max()
}
.unwrap_or(0)
};
self.batching_strategy
.calc_batch_size(max_items, thread_count)
}
}
/// A parallel iterator over the unique query items generated from an [`Entity`] list.
///
/// This struct is created by the [`Query::par_iter_many`] method.
///
/// [`Entity`]: crate::entity::Entity
/// [`Query::par_iter_many`]: crate::system::Query::par_iter_many
pub struct QueryParManyIter<'w, 's, D: QueryData, F: QueryFilter, E: EntityEquivalent> {
pub(crate) world: UnsafeWorldCell<'w>,
pub(crate) state: &'s QueryState<D, F>,
pub(crate) entity_list: Vec<E>,
pub(crate) last_run: Tick,
pub(crate) this_run: Tick,
pub(crate) batching_strategy: BatchingStrategy,
}
impl<'w, 's, D: ReadOnlyQueryData, F: QueryFilter, E: EntityEquivalent + Sync>
QueryParManyIter<'w, 's, D, F, E>
{
/// Changes the batching strategy used when iterating.
///
/// For more information on how this affects the resultant iteration, see
/// [`BatchingStrategy`].
pub fn batching_strategy(mut self, strategy: BatchingStrategy) -> Self {
self.batching_strategy = strategy;
self
}
/// Runs `func` on each query result in parallel.
///
/// # Panics
/// If the [`ComputeTaskPool`] is not initialized. If using this from a query that is being
/// initialized and run from the ECS scheduler, this should never panic.
///
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
#[inline]
pub fn for_each<FN: Fn(QueryItem<'w, D>) + Send + Sync + Clone>(self, func: FN) {
self.for_each_init(|| {}, |_, item| func(item));
}
/// Runs `func` on each query result in parallel on a value returned by `init`.
///
/// `init` may be called multiple times per thread, and the values returned may be discarded between tasks on any given thread.
/// Callers should avoid using this function as if it were a parallel version
/// of [`Iterator::fold`].
///
/// # Example
///
/// ```
/// use bevy_utils::Parallel;
/// use crate::{bevy_ecs::prelude::{Component, Res, Resource, Entity}, bevy_ecs::system::Query};
/// # use core::slice;
/// use bevy_platform::prelude::Vec;
/// # fn some_expensive_operation(_item: &T) -> usize {
/// # 0
/// # }
///
/// #[derive(Component)]
/// struct T;
///
/// #[derive(Resource)]
/// struct V(Vec<Entity>);
///
/// impl<'a> IntoIterator for &'a V {
/// // ...
/// # type Item = &'a Entity;
/// # type IntoIter = slice::Iter<'a, Entity>;
/// #
/// # fn into_iter(self) -> Self::IntoIter {
/// # self.0.iter()
/// # }
/// }
///
/// fn system(query: Query<&T>, entities: Res<V>){
/// let mut queue: Parallel<usize> = Parallel::default();
/// // queue.borrow_local_mut() will get or create a thread_local queue for each task/thread;
/// query.par_iter_many(&entities).for_each_init(|| queue.borrow_local_mut(),|local_queue, item| {
/// **local_queue += some_expensive_operation(item);
/// });
///
/// // collect value from every thread
/// let final_value: usize = queue.iter_mut().map(|v| *v).sum();
/// }
/// ```
///
/// # Panics
/// If the [`ComputeTaskPool`] is not initialized. If using this from a query that is being
/// initialized and run from the ECS scheduler, this should never panic.
///
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
#[inline]
pub fn for_each_init<FN, INIT, T>(self, init: INIT, func: FN)
where
FN: Fn(&mut T, QueryItem<'w, D>) + Send + Sync + Clone,
INIT: Fn() -> T + Sync + Send + Clone,
{
let func = |mut init, item| {
func(&mut init, item);
init
};
#[cfg(any(target_arch = "wasm32", not(feature = "multi_threaded")))]
{
let init = init();
// SAFETY:
// This method can only be called once per instance of QueryParManyIter,
// which ensures that mutable queries cannot be executed multiple times at once.
// Mutable instances of QueryParManyUniqueIter can only be created via an exclusive borrow of a
// Query or a World, which ensures that multiple aliasing QueryParManyIters cannot exist
// at the same time.
unsafe {
self.state
.query_unchecked_manual_with_ticks(self.world, self.last_run, self.this_run)
.iter_many_inner(&self.entity_list)
.fold(init, func);
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))]
{
let thread_count = bevy_tasks::ComputeTaskPool::get().thread_num();
if thread_count <= 1 {
let init = init();
// SAFETY: See the safety comment above.
unsafe {
self.state
.query_unchecked_manual_with_ticks(self.world, self.last_run, self.this_run)
.iter_many_inner(&self.entity_list)
.fold(init, func);
}
} else {
// Need a batch size of at least 1.
let batch_size = self.get_batch_size(thread_count).max(1);
// SAFETY: See the safety comment above.
unsafe {
self.state.par_many_fold_init_unchecked_manual(
init,
self.world,
&self.entity_list,
batch_size,
func,
self.last_run,
self.this_run,
);
}
}
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))]
fn get_batch_size(&self, thread_count: usize) -> usize {
self.batching_strategy
.calc_batch_size(|| self.entity_list.len(), thread_count)
}
}
/// A parallel iterator over the unique query items generated from an [`EntitySet`].
///
/// This struct is created by the [`Query::par_iter_many_unique`] and [`Query::par_iter_many_unique_mut`] methods.
///
/// [`EntitySet`]: crate::entity::EntitySet
/// [`Query::par_iter_many_unique`]: crate::system::Query::par_iter_many_unique
/// [`Query::par_iter_many_unique_mut`]: crate::system::Query::par_iter_many_unique_mut
pub struct QueryParManyUniqueIter<'w, 's, D: QueryData, F: QueryFilter, E: EntityEquivalent + Sync>
{
pub(crate) world: UnsafeWorldCell<'w>,
pub(crate) state: &'s QueryState<D, F>,
pub(crate) entity_list: UniqueEntityEquivalentVec<E>,
pub(crate) last_run: Tick,
pub(crate) this_run: Tick,
pub(crate) batching_strategy: BatchingStrategy,
}
impl<'w, 's, D: QueryData, F: QueryFilter, E: EntityEquivalent + Sync>
QueryParManyUniqueIter<'w, 's, D, F, E>
{
/// Changes the batching strategy used when iterating.
///
/// For more information on how this affects the resultant iteration, see
/// [`BatchingStrategy`].
pub fn batching_strategy(mut self, strategy: BatchingStrategy) -> Self {
self.batching_strategy = strategy;
self
}
/// Runs `func` on each query result in parallel.
///
/// # Panics
/// If the [`ComputeTaskPool`] is not initialized. If using this from a query that is being
/// initialized and run from the ECS scheduler, this should never panic.
///
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
#[inline]
pub fn for_each<FN: Fn(QueryItem<'w, D>) + Send + Sync + Clone>(self, func: FN) {
self.for_each_init(|| {}, |_, item| func(item));
}
/// Runs `func` on each query result in parallel on a value returned by `init`.
///
/// `init` may be called multiple times per thread, and the values returned may be discarded between tasks on any given thread.
/// Callers should avoid using this function as if it were a parallel version
/// of [`Iterator::fold`].
///
/// # Example
///
/// ```
/// use bevy_utils::Parallel;
/// use crate::{bevy_ecs::{prelude::{Component, Res, Resource, Entity}, entity::UniqueEntityVec, system::Query}};
/// # use core::slice;
/// # use crate::bevy_ecs::entity::UniqueEntityIter;
/// # fn some_expensive_operation(_item: &T) -> usize {
/// # 0
/// # }
///
/// #[derive(Component)]
/// struct T;
///
/// #[derive(Resource)]
/// struct V(UniqueEntityVec);
///
/// impl<'a> IntoIterator for &'a V {
/// // ...
/// # type Item = &'a Entity;
/// # type IntoIter = UniqueEntityIter<slice::Iter<'a, Entity>>;
/// #
/// # fn into_iter(self) -> Self::IntoIter {
/// # self.0.iter()
/// # }
/// }
///
/// fn system(query: Query<&T>, entities: Res<V>){
/// let mut queue: Parallel<usize> = Parallel::default();
/// // queue.borrow_local_mut() will get or create a thread_local queue for each task/thread;
/// query.par_iter_many_unique(&entities).for_each_init(|| queue.borrow_local_mut(),|local_queue, item| {
/// **local_queue += some_expensive_operation(item);
/// });
///
/// // collect value from every thread
/// let final_value: usize = queue.iter_mut().map(|v| *v).sum();
/// }
/// ```
///
/// # Panics
/// If the [`ComputeTaskPool`] is not initialized. If using this from a query that is being
/// initialized and run from the ECS scheduler, this should never panic.
///
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
#[inline]
pub fn for_each_init<FN, INIT, T>(self, init: INIT, func: FN)
where
FN: Fn(&mut T, QueryItem<'w, D>) + Send + Sync + Clone,
INIT: Fn() -> T + Sync + Send + Clone,
{
let func = |mut init, item| {
func(&mut init, item);
init
};
#[cfg(any(target_arch = "wasm32", not(feature = "multi_threaded")))]
{
let init = init();
// SAFETY:
// This method can only be called once per instance of QueryParManyUniqueIter,
// which ensures that mutable queries cannot be executed multiple times at once.
// Mutable instances of QueryParManyUniqueIter can only be created via an exclusive borrow of a
// Query or a World, which ensures that multiple aliasing QueryParManyUniqueIters cannot exist
// at the same time.
unsafe {
self.state
.query_unchecked_manual_with_ticks(self.world, self.last_run, self.this_run)
.iter_many_unique_inner(self.entity_list)
.fold(init, func);
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))]
{
let thread_count = bevy_tasks::ComputeTaskPool::get().thread_num();
if thread_count <= 1 {
let init = init();
// SAFETY: See the safety comment above.
unsafe {
self.state
.query_unchecked_manual_with_ticks(self.world, self.last_run, self.this_run)
.iter_many_unique_inner(self.entity_list)
.fold(init, func);
}
} else {
// Need a batch size of at least 1.
let batch_size = self.get_batch_size(thread_count).max(1);
// SAFETY: See the safety comment above.
unsafe {
self.state.par_many_unique_fold_init_unchecked_manual(
init,
self.world,
&self.entity_list,
batch_size,
func,
self.last_run,
self.this_run,
);
}
}
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))]
fn get_batch_size(&self, thread_count: usize) -> usize {
self.batching_strategy
.calc_batch_size(|| self.entity_list.len(), thread_count)
}
}

2366
vendor/bevy_ecs/src/query/state.rs vendored Normal file

File diff suppressed because it is too large Load Diff

229
vendor/bevy_ecs/src/query/world_query.rs vendored Normal file
View File

@@ -0,0 +1,229 @@
use crate::{
archetype::Archetype,
component::{ComponentId, Components, Tick},
query::FilteredAccess,
storage::Table,
world::{unsafe_world_cell::UnsafeWorldCell, World},
};
use variadics_please::all_tuples;
/// Types that can be used as parameters in a [`Query`].
/// Types that implement this should also implement either [`QueryData`] or [`QueryFilter`]
///
/// # Safety
///
/// Implementor must ensure that
/// [`update_component_access`], [`matches_component_set`], [`QueryData::fetch`], [`QueryFilter::filter_fetch`] and [`init_fetch`]
/// obey the following:
///
/// - For each component mutably accessed by [`QueryData::fetch`], [`update_component_access`] should add write access unless read or write access has already been added, in which case it should panic.
/// - For each component readonly accessed by [`QueryData::fetch`] or [`QueryFilter::filter_fetch`], [`update_component_access`] should add read access unless write access has already been added, in which case it should panic.
/// - If `fetch` mutably accesses the same component twice, [`update_component_access`] should panic.
/// - [`update_component_access`] may not add a `Without` filter for a component unless [`matches_component_set`] always returns `false` when the component set contains that component.
/// - [`update_component_access`] may not add a `With` filter for a component unless [`matches_component_set`] always returns `false` when the component set doesn't contain that component.
/// - In cases where the query represents a disjunction (such as an `Or` filter) where each element is a valid [`WorldQuery`], the following rules must be obeyed:
/// - [`matches_component_set`] must be a disjunction of the element's implementations
/// - [`update_component_access`] must replace the filters with a disjunction of filters
/// - Each filter in that disjunction must be a conjunction of the corresponding element's filter with the previous `access`
/// - For each resource readonly accessed by [`init_fetch`], [`update_component_access`] should add read access.
/// - Mutable resource access is not allowed.
///
/// When implementing [`update_component_access`], note that `add_read` and `add_write` both also add a `With` filter, whereas `extend_access` does not change the filters.
///
/// [`QueryData::fetch`]: crate::query::QueryData::fetch
/// [`QueryFilter::filter_fetch`]: crate::query::QueryFilter::filter_fetch
/// [`init_fetch`]: Self::init_fetch
/// [`matches_component_set`]: Self::matches_component_set
/// [`Query`]: crate::system::Query
/// [`update_component_access`]: Self::update_component_access
/// [`QueryData`]: crate::query::QueryData
/// [`QueryFilter`]: crate::query::QueryFilter
pub unsafe trait WorldQuery {
/// Per archetype/table state retrieved by this [`WorldQuery`] to compute [`Self::Item`](crate::query::QueryData::Item) for each entity.
type Fetch<'a>: Clone;
/// State used to construct a [`Self::Fetch`](WorldQuery::Fetch). This will be cached inside [`QueryState`](crate::query::QueryState),
/// so it is best to move as much data / computation here as possible to reduce the cost of
/// constructing [`Self::Fetch`](WorldQuery::Fetch).
type State: Send + Sync + Sized;
/// This function manually implements subtyping for the query fetches.
fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort>;
/// Creates a new instance of [`Self::Fetch`](WorldQuery::Fetch),
/// by combining data from the [`World`] with the cached [`Self::State`](WorldQuery::State).
/// Readonly accesses resources registered in [`WorldQuery::update_component_access`].
///
/// # Safety
///
/// - `state` must have been initialized (via [`WorldQuery::init_state`]) using the same `world` passed
/// in to this function.
/// - `world` must have the **right** to access any access registered in `update_component_access`.
/// - There must not be simultaneous resource access conflicting with readonly resource access registered in [`WorldQuery::update_component_access`].
unsafe fn init_fetch<'w>(
world: UnsafeWorldCell<'w>,
state: &Self::State,
last_run: Tick,
this_run: Tick,
) -> Self::Fetch<'w>;
/// Returns true if (and only if) every table of every archetype matched by this fetch contains
/// all of the matched components.
///
/// This is used to select a more efficient "table iterator"
/// for "dense" queries. If this returns true, [`WorldQuery::set_table`] must be used before
/// [`QueryData::fetch`](crate::query::QueryData::fetch) can be called for iterators. If this returns false,
/// [`WorldQuery::set_archetype`] must be used before [`QueryData::fetch`](crate::query::QueryData::fetch) can be called for
/// iterators.
const IS_DENSE: bool;
/// Adjusts internal state to account for the next [`Archetype`]. This will always be called on
/// archetypes that match this [`WorldQuery`].
///
/// # Safety
///
/// - `archetype` and `tables` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.
/// - `table` must correspond to `archetype`.
/// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.
unsafe fn set_archetype<'w>(
fetch: &mut Self::Fetch<'w>,
state: &Self::State,
archetype: &'w Archetype,
table: &'w Table,
);
/// Adjusts internal state to account for the next [`Table`]. This will always be called on tables
/// that match this [`WorldQuery`].
///
/// # Safety
///
/// - `table` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.
/// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.
unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table);
/// Sets available accesses for implementors with dynamic access such as [`FilteredEntityRef`](crate::world::FilteredEntityRef)
/// or [`FilteredEntityMut`](crate::world::FilteredEntityMut).
///
/// Called when constructing a [`QueryLens`](crate::system::QueryLens) or calling [`QueryState::from_builder`](super::QueryState::from_builder)
fn set_access(_state: &mut Self::State, _access: &FilteredAccess<ComponentId>) {}
/// Adds any component accesses used by this [`WorldQuery`] to `access`.
///
/// Used to check which queries are disjoint and can run in parallel
// This does not have a default body of `{}` because 99% of cases need to add accesses
// and forgetting to do so would be unsound.
fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>);
/// Creates and initializes a [`State`](WorldQuery::State) for this [`WorldQuery`] type.
fn init_state(world: &mut World) -> Self::State;
/// Attempts to initialize a [`State`](WorldQuery::State) for this [`WorldQuery`] type using read-only
/// access to [`Components`].
fn get_state(components: &Components) -> Option<Self::State>;
/// Returns `true` if this query matches a set of components. Otherwise, returns `false`.
///
/// Used to check which [`Archetype`]s can be skipped by the query
/// (if none of the [`Component`](crate::component::Component)s match).
/// This is how archetypal query filters like `With` work.
fn matches_component_set(
state: &Self::State,
set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool;
}
macro_rules! impl_tuple_world_query {
($(#[$meta:meta])* $(($name: ident, $state: ident)),*) => {
#[expect(
clippy::allow_attributes,
reason = "This is a tuple-related macro; as such the lints below may not always apply."
)]
#[allow(
non_snake_case,
reason = "The names of some variables are provided by the macro's caller, not by us."
)]
#[allow(
unused_variables,
reason = "Zero-length tuples won't use any of the parameters."
)]
#[allow(
clippy::unused_unit,
reason = "Zero-length tuples will generate some function bodies equivalent to `()`; however, this macro is meant for all applicable tuples, and as such it makes no sense to rewrite it just for that case."
)]
$(#[$meta])*
/// SAFETY:
/// `fetch` accesses are the conjunction of the subqueries' accesses
/// This is sound because `update_component_access` adds accesses according to the implementations of all the subqueries.
/// `update_component_access` adds all `With` and `Without` filters from the subqueries.
/// This is sound because `matches_component_set` always returns `false` if any the subqueries' implementations return `false`.
unsafe impl<$($name: WorldQuery),*> WorldQuery for ($($name,)*) {
type Fetch<'w> = ($($name::Fetch<'w>,)*);
type State = ($($name::State,)*);
fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
let ($($name,)*) = fetch;
($(
$name::shrink_fetch($name),
)*)
}
#[inline]
unsafe fn init_fetch<'w>(world: UnsafeWorldCell<'w>, state: &Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
let ($($name,)*) = state;
// SAFETY: The invariants are upheld by the caller.
($(unsafe { $name::init_fetch(world, $name, last_run, this_run) },)*)
}
const IS_DENSE: bool = true $(&& $name::IS_DENSE)*;
#[inline]
unsafe fn set_archetype<'w>(
fetch: &mut Self::Fetch<'w>,
state: &Self::State,
archetype: &'w Archetype,
table: &'w Table
) {
let ($($name,)*) = fetch;
let ($($state,)*) = state;
// SAFETY: The invariants are upheld by the caller.
$(unsafe { $name::set_archetype($name, $state, archetype, table); })*
}
#[inline]
unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table) {
let ($($name,)*) = fetch;
let ($($state,)*) = state;
// SAFETY: The invariants are upheld by the caller.
$(unsafe { $name::set_table($name, $state, table); })*
}
fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>) {
let ($($name,)*) = state;
$($name::update_component_access($name, access);)*
}
fn init_state(world: &mut World) -> Self::State {
($($name::init_state(world),)*)
}
fn get_state(components: &Components) -> Option<Self::State> {
Some(($($name::get_state(components)?,)*))
}
fn matches_component_set(state: &Self::State, set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
let ($($name,)*) = state;
true $(&& $name::matches_component_set($name, set_contains_id))*
}
}
};
}
all_tuples!(
#[doc(fake_variadic)]
impl_tuple_world_query,
0,
15,
F,
S
);

299
vendor/bevy_ecs/src/reflect/bundle.rs vendored Normal file
View File

@@ -0,0 +1,299 @@
//! Definitions for [`Bundle`] reflection.
//! This allows inserting, updating and/or removing bundles whose type is only known at runtime.
//!
//! This module exports two types: [`ReflectBundleFns`] and [`ReflectBundle`].
//!
//! Same as [`super::component`], but for bundles.
use alloc::boxed::Box;
use core::any::{Any, TypeId};
use crate::{
bundle::BundleFromComponents,
entity::EntityMapper,
prelude::Bundle,
relationship::RelationshipHookMode,
world::{EntityMut, EntityWorldMut},
};
use bevy_reflect::{
FromReflect, FromType, PartialReflect, Reflect, ReflectRef, TypePath, TypeRegistry,
};
use super::{from_reflect_with_fallback, ReflectComponent};
/// A struct used to operate on reflected [`Bundle`] trait of a type.
///
/// A [`ReflectBundle`] for type `T` can be obtained via
/// [`bevy_reflect::TypeRegistration::data`].
#[derive(Clone)]
pub struct ReflectBundle(ReflectBundleFns);
/// The raw function pointers needed to make up a [`ReflectBundle`].
///
/// The also [`super::component::ReflectComponentFns`].
#[derive(Clone)]
pub struct ReflectBundleFns {
/// Function pointer implementing [`ReflectBundle::insert`].
pub insert: fn(&mut EntityWorldMut, &dyn PartialReflect, &TypeRegistry),
/// Function pointer implementing [`ReflectBundle::apply`].
pub apply: fn(EntityMut, &dyn PartialReflect, &TypeRegistry),
/// Function pointer implementing [`ReflectBundle::apply_or_insert_mapped`].
pub apply_or_insert_mapped: fn(
&mut EntityWorldMut,
&dyn PartialReflect,
&TypeRegistry,
&mut dyn EntityMapper,
RelationshipHookMode,
),
/// Function pointer implementing [`ReflectBundle::remove`].
pub remove: fn(&mut EntityWorldMut),
/// Function pointer implementing [`ReflectBundle::take`].
pub take: fn(&mut EntityWorldMut) -> Option<Box<dyn Reflect>>,
}
impl ReflectBundleFns {
/// Get the default set of [`ReflectBundleFns`] for a specific bundle type using its
/// [`FromType`] implementation.
///
/// This is useful if you want to start with the default implementation before overriding some
/// of the functions to create a custom implementation.
pub fn new<T: Bundle + FromReflect + TypePath + BundleFromComponents>() -> Self {
<ReflectBundle as FromType<T>>::from_type().0
}
}
impl ReflectBundle {
/// Insert a reflected [`Bundle`] into the entity like [`insert()`](EntityWorldMut::insert).
pub fn insert(
&self,
entity: &mut EntityWorldMut,
bundle: &dyn PartialReflect,
registry: &TypeRegistry,
) {
(self.0.insert)(entity, bundle, registry);
}
/// Uses reflection to set the value of this [`Bundle`] type in the entity to the given value.
///
/// # Panics
///
/// Panics if there is no [`Bundle`] of the given type.
pub fn apply<'a>(
&self,
entity: impl Into<EntityMut<'a>>,
bundle: &dyn PartialReflect,
registry: &TypeRegistry,
) {
(self.0.apply)(entity.into(), bundle, registry);
}
/// Uses reflection to set the value of this [`Bundle`] type in the entity to the given value or insert a new one if it does not exist.
pub fn apply_or_insert_mapped(
&self,
entity: &mut EntityWorldMut,
bundle: &dyn PartialReflect,
registry: &TypeRegistry,
mapper: &mut dyn EntityMapper,
relationship_hook_mode: RelationshipHookMode,
) {
(self.0.apply_or_insert_mapped)(entity, bundle, registry, mapper, relationship_hook_mode);
}
/// Removes this [`Bundle`] type from the entity. Does nothing if it doesn't exist.
pub fn remove(&self, entity: &mut EntityWorldMut) -> &ReflectBundle {
(self.0.remove)(entity);
self
}
/// Removes all components in the [`Bundle`] from the entity and returns their previous values.
///
/// **Note:** If the entity does not have every component in the bundle, this method will not remove any of them.
#[must_use]
pub fn take(&self, entity: &mut EntityWorldMut) -> Option<Box<dyn Reflect>> {
(self.0.take)(entity)
}
/// Create a custom implementation of [`ReflectBundle`].
///
/// This is an advanced feature,
/// useful for scripting implementations,
/// that should not be used by most users
/// unless you know what you are doing.
///
/// Usually you should derive [`Reflect`] and add the `#[reflect(Bundle)]` bundle
/// to generate a [`ReflectBundle`] implementation automatically.
///
/// See [`ReflectBundleFns`] for more information.
pub fn new(fns: ReflectBundleFns) -> Self {
Self(fns)
}
/// The underlying function pointers implementing methods on `ReflectBundle`.
///
/// This is useful when you want to keep track locally of an individual
/// function pointer.
///
/// Calling [`TypeRegistry::get`] followed by
/// [`TypeRegistration::data::<ReflectBundle>`] can be costly if done several
/// times per frame. Consider cloning [`ReflectBundle`] and keeping it
/// between frames, cloning a `ReflectBundle` is very cheap.
///
/// If you only need a subset of the methods on `ReflectBundle`,
/// use `fn_pointers` to get the underlying [`ReflectBundleFns`]
/// and copy the subset of function pointers you care about.
///
/// [`TypeRegistration::data::<ReflectBundle>`]: bevy_reflect::TypeRegistration::data
pub fn fn_pointers(&self) -> &ReflectBundleFns {
&self.0
}
}
impl<B: Bundle + Reflect + TypePath + BundleFromComponents> FromType<B> for ReflectBundle {
fn from_type() -> Self {
ReflectBundle(ReflectBundleFns {
insert: |entity, reflected_bundle, registry| {
let bundle = entity.world_scope(|world| {
from_reflect_with_fallback::<B>(reflected_bundle, world, registry)
});
entity.insert(bundle);
},
apply: |mut entity, reflected_bundle, registry| {
if let Some(reflect_component) =
registry.get_type_data::<ReflectComponent>(TypeId::of::<B>())
{
reflect_component.apply(entity, reflected_bundle);
} else {
match reflected_bundle.reflect_ref() {
ReflectRef::Struct(bundle) => bundle
.iter_fields()
.for_each(|field| apply_field(&mut entity, field, registry)),
ReflectRef::Tuple(bundle) => bundle
.iter_fields()
.for_each(|field| apply_field(&mut entity, field, registry)),
_ => panic!(
"expected bundle `{}` to be named struct or tuple",
// FIXME: once we have unique reflect, use `TypePath`.
core::any::type_name::<B>(),
),
}
}
},
apply_or_insert_mapped: |entity,
reflected_bundle,
registry,
mapper,
relationship_hook_mode| {
if let Some(reflect_component) =
registry.get_type_data::<ReflectComponent>(TypeId::of::<B>())
{
reflect_component.apply_or_insert_mapped(
entity,
reflected_bundle,
registry,
mapper,
relationship_hook_mode,
);
} else {
match reflected_bundle.reflect_ref() {
ReflectRef::Struct(bundle) => bundle.iter_fields().for_each(|field| {
apply_or_insert_field_mapped(
entity,
field,
registry,
mapper,
relationship_hook_mode,
);
}),
ReflectRef::Tuple(bundle) => bundle.iter_fields().for_each(|field| {
apply_or_insert_field_mapped(
entity,
field,
registry,
mapper,
relationship_hook_mode,
);
}),
_ => panic!(
"expected bundle `{}` to be a named struct or tuple",
// FIXME: once we have unique reflect, use `TypePath`.
core::any::type_name::<B>(),
),
}
}
},
remove: |entity| {
entity.remove::<B>();
},
take: |entity| {
entity
.take::<B>()
.map(|bundle| Box::new(bundle).into_reflect())
},
})
}
}
fn apply_field(entity: &mut EntityMut, field: &dyn PartialReflect, registry: &TypeRegistry) {
let Some(type_id) = field.try_as_reflect().map(Any::type_id) else {
panic!(
"`{}` did not implement `Reflect`",
field.reflect_type_path()
);
};
if let Some(reflect_component) = registry.get_type_data::<ReflectComponent>(type_id) {
reflect_component.apply(entity.reborrow(), field);
} else if let Some(reflect_bundle) = registry.get_type_data::<ReflectBundle>(type_id) {
reflect_bundle.apply(entity.reborrow(), field, registry);
} else {
panic!(
"no `ReflectComponent` nor `ReflectBundle` registration found for `{}`",
field.reflect_type_path()
);
}
}
fn apply_or_insert_field_mapped(
entity: &mut EntityWorldMut,
field: &dyn PartialReflect,
registry: &TypeRegistry,
mapper: &mut dyn EntityMapper,
relationship_hook_mode: RelationshipHookMode,
) {
let Some(type_id) = field.try_as_reflect().map(Any::type_id) else {
panic!(
"`{}` did not implement `Reflect`",
field.reflect_type_path()
);
};
if let Some(reflect_component) = registry.get_type_data::<ReflectComponent>(type_id) {
reflect_component.apply_or_insert_mapped(
entity,
field,
registry,
mapper,
relationship_hook_mode,
);
} else if let Some(reflect_bundle) = registry.get_type_data::<ReflectBundle>(type_id) {
reflect_bundle.apply_or_insert_mapped(
entity,
field,
registry,
mapper,
relationship_hook_mode,
);
} else {
let is_component = entity.world().components().get_id(type_id).is_some();
if is_component {
panic!(
"no `ReflectComponent` registration found for `{}`",
field.reflect_type_path(),
);
} else {
panic!(
"no `ReflectBundle` registration found for `{}`",
field.reflect_type_path(),
)
}
}
}

392
vendor/bevy_ecs/src/reflect/component.rs vendored Normal file
View File

@@ -0,0 +1,392 @@
//! Definitions for [`Component`] reflection.
//! This allows inserting, updating, removing and generally interacting with components
//! whose types are only known at runtime.
//!
//! This module exports two types: [`ReflectComponentFns`] and [`ReflectComponent`].
//!
//! # Architecture
//!
//! [`ReflectComponent`] wraps a [`ReflectComponentFns`]. In fact, each method on
//! [`ReflectComponent`] wraps a call to a function pointer field in `ReflectComponentFns`.
//!
//! ## Who creates `ReflectComponent`s?
//!
//! When a user adds the `#[reflect(Component)]` attribute to their `#[derive(Reflect)]`
//! type, it tells the derive macro for `Reflect` to add the following single line to its
//! [`get_type_registration`] method (see the relevant code[^1]).
//!
//! ```
//! # use bevy_reflect::{FromType, Reflect};
//! # use bevy_ecs::prelude::{ReflectComponent, Component};
//! # #[derive(Default, Reflect, Component)]
//! # struct A;
//! # impl A {
//! # fn foo() {
//! # let mut registration = bevy_reflect::TypeRegistration::of::<A>();
//! registration.insert::<ReflectComponent>(FromType::<Self>::from_type());
//! # }
//! # }
//! ```
//!
//! This line adds a `ReflectComponent` to the registration data for the type in question.
//! The user can access the `ReflectComponent` for type `T` through the type registry,
//! as per the `trait_reflection.rs` example.
//!
//! The `FromType::<Self>::from_type()` in the previous line calls the `FromType<C>`
//! implementation of `ReflectComponent`.
//!
//! The `FromType<C>` impl creates a function per field of [`ReflectComponentFns`].
//! In those functions, we call generic methods on [`World`] and [`EntityWorldMut`].
//!
//! The result is a `ReflectComponent` completely independent of `C`, yet capable
//! of using generic ECS methods such as `entity.get::<C>()` to get `&dyn Reflect`
//! with underlying type `C`, without the `C` appearing in the type signature.
//!
//! ## A note on code generation
//!
//! A downside of this approach is that monomorphized code (ie: concrete code
//! for generics) is generated **unconditionally**, regardless of whether it ends
//! up used or not.
//!
//! Adding `N` fields on `ReflectComponentFns` will generate `N × M` additional
//! functions, where `M` is how many types derive `#[reflect(Component)]`.
//!
//! Those functions will increase the size of the final app binary.
//!
//! [^1]: `crates/bevy_reflect/bevy_reflect_derive/src/registration.rs`
//!
//! [`get_type_registration`]: bevy_reflect::GetTypeRegistration::get_type_registration
use super::from_reflect_with_fallback;
use crate::{
change_detection::Mut,
component::{ComponentId, ComponentMutability},
entity::{Entity, EntityMapper},
prelude::Component,
relationship::RelationshipHookMode,
world::{
unsafe_world_cell::UnsafeEntityCell, EntityMut, EntityWorldMut, FilteredEntityMut,
FilteredEntityRef, World,
},
};
use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypePath, TypeRegistry};
use disqualified::ShortName;
/// A struct used to operate on reflected [`Component`] trait of a type.
///
/// A [`ReflectComponent`] for type `T` can be obtained via
/// [`bevy_reflect::TypeRegistration::data`].
#[derive(Clone)]
pub struct ReflectComponent(ReflectComponentFns);
/// The raw function pointers needed to make up a [`ReflectComponent`].
///
/// This is used when creating custom implementations of [`ReflectComponent`] with
/// [`ReflectComponent::new()`].
///
/// > **Note:**
/// > Creating custom implementations of [`ReflectComponent`] is an advanced feature that most users
/// > will not need.
/// > Usually a [`ReflectComponent`] is created for a type by deriving [`Reflect`]
/// > and adding the `#[reflect(Component)]` attribute.
/// > After adding the component to the [`TypeRegistry`],
/// > its [`ReflectComponent`] can then be retrieved when needed.
///
/// Creating a custom [`ReflectComponent`] may be useful if you need to create new component types
/// at runtime, for example, for scripting implementations.
///
/// By creating a custom [`ReflectComponent`] and inserting it into a type's
/// [`TypeRegistration`][bevy_reflect::TypeRegistration],
/// you can modify the way that reflected components of that type will be inserted into the Bevy
/// world.
#[derive(Clone)]
pub struct ReflectComponentFns {
/// Function pointer implementing [`ReflectComponent::insert()`].
pub insert: fn(&mut EntityWorldMut, &dyn PartialReflect, &TypeRegistry),
/// Function pointer implementing [`ReflectComponent::apply()`].
pub apply: fn(EntityMut, &dyn PartialReflect),
/// Function pointer implementing [`ReflectComponent::apply_or_insert_mapped()`].
pub apply_or_insert_mapped: fn(
&mut EntityWorldMut,
&dyn PartialReflect,
&TypeRegistry,
&mut dyn EntityMapper,
RelationshipHookMode,
),
/// Function pointer implementing [`ReflectComponent::remove()`].
pub remove: fn(&mut EntityWorldMut),
/// Function pointer implementing [`ReflectComponent::contains()`].
pub contains: fn(FilteredEntityRef) -> bool,
/// Function pointer implementing [`ReflectComponent::reflect()`].
pub reflect: fn(FilteredEntityRef) -> Option<&dyn Reflect>,
/// Function pointer implementing [`ReflectComponent::reflect_mut()`].
pub reflect_mut: fn(FilteredEntityMut) -> Option<Mut<dyn Reflect>>,
/// Function pointer implementing [`ReflectComponent::map_entities()`].
pub map_entities: fn(&mut dyn Reflect, &mut dyn EntityMapper),
/// Function pointer implementing [`ReflectComponent::reflect_unchecked_mut()`].
///
/// # Safety
/// The function may only be called with an [`UnsafeEntityCell`] that can be used to mutably access the relevant component on the given entity.
pub reflect_unchecked_mut: unsafe fn(UnsafeEntityCell<'_>) -> Option<Mut<'_, dyn Reflect>>,
/// Function pointer implementing [`ReflectComponent::copy()`].
pub copy: fn(&World, &mut World, Entity, Entity, &TypeRegistry),
/// Function pointer implementing [`ReflectComponent::register_component()`].
pub register_component: fn(&mut World) -> ComponentId,
}
impl ReflectComponentFns {
/// Get the default set of [`ReflectComponentFns`] for a specific component type using its
/// [`FromType`] implementation.
///
/// This is useful if you want to start with the default implementation before overriding some
/// of the functions to create a custom implementation.
pub fn new<T: Component + FromReflect + TypePath>() -> Self {
<ReflectComponent as FromType<T>>::from_type().0
}
}
impl ReflectComponent {
/// Insert a reflected [`Component`] into the entity like [`insert()`](EntityWorldMut::insert).
pub fn insert(
&self,
entity: &mut EntityWorldMut,
component: &dyn PartialReflect,
registry: &TypeRegistry,
) {
(self.0.insert)(entity, component, registry);
}
/// Uses reflection to set the value of this [`Component`] type in the entity to the given value.
///
/// # Panics
///
/// Panics if there is no [`Component`] of the given type.
///
/// Will also panic if [`Component`] is immutable.
pub fn apply<'a>(&self, entity: impl Into<EntityMut<'a>>, component: &dyn PartialReflect) {
(self.0.apply)(entity.into(), component);
}
/// Uses reflection to set the value of this [`Component`] type in the entity to the given value or insert a new one if it does not exist.
///
/// # Panics
///
/// Panics if [`Component`] is immutable.
pub fn apply_or_insert_mapped(
&self,
entity: &mut EntityWorldMut,
component: &dyn PartialReflect,
registry: &TypeRegistry,
map: &mut dyn EntityMapper,
relationship_hook_mode: RelationshipHookMode,
) {
(self.0.apply_or_insert_mapped)(entity, component, registry, map, relationship_hook_mode);
}
/// Removes this [`Component`] type from the entity. Does nothing if it doesn't exist.
pub fn remove(&self, entity: &mut EntityWorldMut) {
(self.0.remove)(entity);
}
/// Returns whether entity contains this [`Component`]
pub fn contains<'a>(&self, entity: impl Into<FilteredEntityRef<'a>>) -> bool {
(self.0.contains)(entity.into())
}
/// Gets the value of this [`Component`] type from the entity as a reflected reference.
pub fn reflect<'a>(&self, entity: impl Into<FilteredEntityRef<'a>>) -> Option<&'a dyn Reflect> {
(self.0.reflect)(entity.into())
}
/// Gets the value of this [`Component`] type from the entity as a mutable reflected reference.
///
/// # Panics
///
/// Panics if [`Component`] is immutable.
pub fn reflect_mut<'a>(
&self,
entity: impl Into<FilteredEntityMut<'a>>,
) -> Option<Mut<'a, dyn Reflect>> {
(self.0.reflect_mut)(entity.into())
}
/// # Safety
/// This method does not prevent you from having two mutable pointers to the same data,
/// violating Rust's aliasing rules. To avoid this:
/// * Only call this method with a [`UnsafeEntityCell`] that may be used to mutably access the component on the entity `entity`
/// * Don't call this method more than once in the same scope for a given [`Component`].
///
/// # Panics
///
/// Panics if [`Component`] is immutable.
pub unsafe fn reflect_unchecked_mut<'a>(
&self,
entity: UnsafeEntityCell<'a>,
) -> Option<Mut<'a, dyn Reflect>> {
// SAFETY: safety requirements deferred to caller
unsafe { (self.0.reflect_unchecked_mut)(entity) }
}
/// Gets the value of this [`Component`] type from entity from `source_world` and [applies](Self::apply()) it to the value of this [`Component`] type in entity in `destination_world`.
///
/// # Panics
///
/// Panics if there is no [`Component`] of the given type or either entity does not exist.
pub fn copy(
&self,
source_world: &World,
destination_world: &mut World,
source_entity: Entity,
destination_entity: Entity,
registry: &TypeRegistry,
) {
(self.0.copy)(
source_world,
destination_world,
source_entity,
destination_entity,
registry,
);
}
/// Register the type of this [`Component`] in [`World`], returning its [`ComponentId`].
pub fn register_component(&self, world: &mut World) -> ComponentId {
(self.0.register_component)(world)
}
/// Create a custom implementation of [`ReflectComponent`].
///
/// This is an advanced feature,
/// useful for scripting implementations,
/// that should not be used by most users
/// unless you know what you are doing.
///
/// Usually you should derive [`Reflect`] and add the `#[reflect(Component)]` component
/// to generate a [`ReflectComponent`] implementation automatically.
///
/// See [`ReflectComponentFns`] for more information.
pub fn new(fns: ReflectComponentFns) -> Self {
Self(fns)
}
/// The underlying function pointers implementing methods on `ReflectComponent`.
///
/// This is useful when you want to keep track locally of an individual
/// function pointer.
///
/// Calling [`TypeRegistry::get`] followed by
/// [`TypeRegistration::data::<ReflectComponent>`] can be costly if done several
/// times per frame. Consider cloning [`ReflectComponent`] and keeping it
/// between frames, cloning a `ReflectComponent` is very cheap.
///
/// If you only need a subset of the methods on `ReflectComponent`,
/// use `fn_pointers` to get the underlying [`ReflectComponentFns`]
/// and copy the subset of function pointers you care about.
///
/// [`TypeRegistration::data::<ReflectComponent>`]: bevy_reflect::TypeRegistration::data
/// [`TypeRegistry::get`]: bevy_reflect::TypeRegistry::get
pub fn fn_pointers(&self) -> &ReflectComponentFns {
&self.0
}
/// Calls a dynamic version of [`Component::map_entities`].
pub fn map_entities(&self, component: &mut dyn Reflect, func: &mut dyn EntityMapper) {
(self.0.map_entities)(component, func);
}
}
impl<C: Component + Reflect + TypePath> FromType<C> for ReflectComponent {
fn from_type() -> Self {
// TODO: Currently we panic if a component is immutable and you use
// reflection to mutate it. Perhaps the mutation methods should be fallible?
ReflectComponent(ReflectComponentFns {
insert: |entity, reflected_component, registry| {
let component = entity.world_scope(|world| {
from_reflect_with_fallback::<C>(reflected_component, world, registry)
});
entity.insert(component);
},
apply: |mut entity, reflected_component| {
if !C::Mutability::MUTABLE {
let name = ShortName::of::<C>();
panic!("Cannot call `ReflectComponent::apply` on component {name}. It is immutable, and cannot modified through reflection");
}
// SAFETY: guard ensures `C` is a mutable component
let mut component = unsafe { entity.get_mut_assume_mutable::<C>() }.unwrap();
component.apply(reflected_component);
},
apply_or_insert_mapped: |entity,
reflected_component,
registry,
mut mapper,
relationship_hook_mode| {
if C::Mutability::MUTABLE {
// SAFETY: guard ensures `C` is a mutable component
if let Some(mut component) = unsafe { entity.get_mut_assume_mutable::<C>() } {
component.apply(reflected_component.as_partial_reflect());
C::map_entities(&mut component, &mut mapper);
} else {
let mut component = entity.world_scope(|world| {
from_reflect_with_fallback::<C>(reflected_component, world, registry)
});
C::map_entities(&mut component, &mut mapper);
entity
.insert_with_relationship_hook_mode(component, relationship_hook_mode);
}
} else {
let mut component = entity.world_scope(|world| {
from_reflect_with_fallback::<C>(reflected_component, world, registry)
});
C::map_entities(&mut component, &mut mapper);
entity.insert_with_relationship_hook_mode(component, relationship_hook_mode);
}
},
remove: |entity| {
entity.remove::<C>();
},
contains: |entity| entity.contains::<C>(),
copy: |source_world, destination_world, source_entity, destination_entity, registry| {
let source_component = source_world.get::<C>(source_entity).unwrap();
let destination_component =
from_reflect_with_fallback::<C>(source_component, destination_world, registry);
destination_world
.entity_mut(destination_entity)
.insert(destination_component);
},
reflect: |entity| entity.get::<C>().map(|c| c as &dyn Reflect),
reflect_mut: |entity| {
if !C::Mutability::MUTABLE {
let name = ShortName::of::<C>();
panic!("Cannot call `ReflectComponent::reflect_mut` on component {name}. It is immutable, and cannot modified through reflection");
}
// SAFETY: guard ensures `C` is a mutable component
unsafe {
entity
.into_mut_assume_mutable::<C>()
.map(|c| c.map_unchanged(|value| value as &mut dyn Reflect))
}
},
reflect_unchecked_mut: |entity| {
if !C::Mutability::MUTABLE {
let name = ShortName::of::<C>();
panic!("Cannot call `ReflectComponent::reflect_unchecked_mut` on component {name}. It is immutable, and cannot modified through reflection");
}
// SAFETY: reflect_unchecked_mut is an unsafe function pointer used by
// `reflect_unchecked_mut` which must be called with an UnsafeEntityCell with access to the component `C` on the `entity`
// guard ensures `C` is a mutable component
let c = unsafe { entity.get_mut_assume_mutable::<C>() };
c.map(|c| c.map_unchanged(|value| value as &mut dyn Reflect))
},
register_component: |world: &mut World| -> ComponentId {
world.register_component::<C>()
},
map_entities: |reflect: &mut dyn Reflect, mut mapper: &mut dyn EntityMapper| {
let component = reflect.downcast_mut::<C>().unwrap();
Component::map_entities(component, &mut mapper);
},
})
}
}

View File

@@ -0,0 +1,697 @@
use crate::{
entity::Entity,
prelude::Mut,
reflect::{AppTypeRegistry, ReflectBundle, ReflectComponent},
resource::Resource,
system::EntityCommands,
world::{EntityWorldMut, World},
};
use alloc::{borrow::Cow, boxed::Box};
use bevy_reflect::{PartialReflect, TypeRegistry};
/// An extension trait for [`EntityCommands`] for reflection related functions
pub trait ReflectCommandExt {
/// Adds the given boxed reflect component or bundle to the entity using the reflection data in
/// [`AppTypeRegistry`].
///
/// This will overwrite any previous component(s) of the same type.
///
/// # Panics
///
/// - If the entity doesn't exist.
/// - If [`AppTypeRegistry`] does not have the reflection data for the given
/// [`Component`](crate::component::Component) or [`Bundle`](crate::bundle::Bundle).
/// - If the component or bundle data is invalid. See [`PartialReflect::apply`] for further details.
/// - If [`AppTypeRegistry`] is not present in the [`World`].
///
/// # Note
///
/// Prefer to use the typed [`EntityCommands::insert`] if possible. Adding a reflected component
/// is much slower.
///
/// # Example
///
/// ```
/// // Note that you need to register the component type in the AppTypeRegistry prior to using
/// // reflection. You can use the helpers on the App with `app.register_type::<ComponentA>()`
/// // or write to the TypeRegistry directly to register all your components
///
/// # use bevy_ecs::prelude::*;
/// # use bevy_ecs::reflect::{ReflectCommandExt, ReflectBundle};
/// # use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry};
/// // A resource that can hold any component that implements reflect as a boxed reflect component
/// #[derive(Resource)]
/// struct Prefab {
/// data: Box<dyn Reflect>,
/// }
/// #[derive(Component, Reflect, Default)]
/// #[reflect(Component)]
/// struct ComponentA(u32);
///
/// #[derive(Component, Reflect, Default)]
/// #[reflect(Component)]
/// struct ComponentB(String);
///
/// #[derive(Bundle, Reflect, Default)]
/// #[reflect(Bundle)]
/// struct BundleA {
/// a: ComponentA,
/// b: ComponentB,
/// }
///
/// fn insert_reflect_component(
/// mut commands: Commands,
/// mut prefab: ResMut<Prefab>
/// ) {
/// // Create a set of new boxed reflect components to use
/// let boxed_reflect_component_a: Box<dyn Reflect> = Box::new(ComponentA(916));
/// let boxed_reflect_component_b: Box<dyn Reflect> = Box::new(ComponentB("NineSixteen".to_string()));
/// let boxed_reflect_bundle_a: Box<dyn Reflect> = Box::new(BundleA {
/// a: ComponentA(24),
/// b: ComponentB("Twenty-Four".to_string()),
/// });
///
/// // You can overwrite the component in the resource with either ComponentA or ComponentB
/// prefab.data = boxed_reflect_component_a;
/// prefab.data = boxed_reflect_component_b;
///
/// // Or even with BundleA
/// prefab.data = boxed_reflect_bundle_a;
///
/// // No matter which component or bundle is in the resource and without knowing the exact type, you can
/// // use the insert_reflect entity command to insert that component/bundle into an entity.
/// commands
/// .spawn_empty()
/// .insert_reflect(prefab.data.reflect_clone().unwrap().into_partial_reflect());
/// }
/// ```
fn insert_reflect(&mut self, component: Box<dyn PartialReflect>) -> &mut Self;
/// Same as [`insert_reflect`](ReflectCommandExt::insert_reflect), but using the `T` resource as type registry instead of
/// `AppTypeRegistry`.
///
/// # Panics
///
/// - If the given [`Resource`] is not present in the [`World`].
///
/// # Note
///
/// - The given [`Resource`] is removed from the [`World`] before the command is applied.
fn insert_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
&mut self,
component: Box<dyn PartialReflect>,
) -> &mut Self;
/// Removes from the entity the component or bundle with the given type name registered in [`AppTypeRegistry`].
///
/// If the type is a bundle, it will remove any components in that bundle regardless if the entity
/// contains all the components.
///
/// Does nothing if the type is a component and the entity does not have a component of the same type,
/// if the type is a bundle and the entity does not contain any of the components in the bundle,
/// if [`AppTypeRegistry`] does not contain the reflection data for the given component,
/// or if the entity does not exist.
///
/// # Note
///
/// Prefer to use the typed [`EntityCommands::remove`] if possible. Removing a reflected component
/// is much slower.
///
/// # Example
///
/// ```
/// // Note that you need to register the component/bundle type in the AppTypeRegistry prior to using
/// // reflection. You can use the helpers on the App with `app.register_type::<ComponentA>()`
/// // or write to the TypeRegistry directly to register all your components and bundles
///
/// # use bevy_ecs::prelude::*;
/// # use bevy_ecs::reflect::{ReflectCommandExt, ReflectBundle};
/// # use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry};
///
/// // A resource that can hold any component or bundle that implements reflect as a boxed reflect
/// #[derive(Resource)]
/// struct Prefab{
/// entity: Entity,
/// data: Box<dyn Reflect>,
/// }
/// #[derive(Component, Reflect, Default)]
/// #[reflect(Component)]
/// struct ComponentA(u32);
/// #[derive(Component, Reflect, Default)]
/// #[reflect(Component)]
/// struct ComponentB(String);
/// #[derive(Bundle, Reflect, Default)]
/// #[reflect(Bundle)]
/// struct BundleA {
/// a: ComponentA,
/// b: ComponentB,
/// }
///
/// fn remove_reflect_component(
/// mut commands: Commands,
/// prefab: Res<Prefab>
/// ) {
/// // Prefab can hold any boxed reflect component or bundle. In this case either
/// // ComponentA, ComponentB, or BundleA. No matter which component or bundle is in the resource though,
/// // we can attempt to remove any component (or set of components in the case of a bundle)
/// // of that same type from an entity.
/// commands.entity(prefab.entity)
/// .remove_reflect(prefab.data.reflect_type_path().to_owned());
/// }
/// ```
fn remove_reflect(&mut self, component_type_name: impl Into<Cow<'static, str>>) -> &mut Self;
/// Same as [`remove_reflect`](ReflectCommandExt::remove_reflect), but using the `T` resource as type registry instead of
/// `AppTypeRegistry`.
fn remove_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
&mut self,
component_type_name: impl Into<Cow<'static, str>>,
) -> &mut Self;
}
impl ReflectCommandExt for EntityCommands<'_> {
fn insert_reflect(&mut self, component: Box<dyn PartialReflect>) -> &mut Self {
self.queue(move |mut entity: EntityWorldMut| {
entity.insert_reflect(component);
})
}
fn insert_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
&mut self,
component: Box<dyn PartialReflect>,
) -> &mut Self {
self.queue(move |mut entity: EntityWorldMut| {
entity.insert_reflect_with_registry::<T>(component);
})
}
fn remove_reflect(&mut self, component_type_path: impl Into<Cow<'static, str>>) -> &mut Self {
let component_type_path: Cow<'static, str> = component_type_path.into();
self.queue(move |mut entity: EntityWorldMut| {
entity.remove_reflect(component_type_path);
})
}
fn remove_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
&mut self,
component_type_path: impl Into<Cow<'static, str>>,
) -> &mut Self {
let component_type_path: Cow<'static, str> = component_type_path.into();
self.queue(move |mut entity: EntityWorldMut| {
entity.remove_reflect_with_registry::<T>(component_type_path);
})
}
}
impl<'w> EntityWorldMut<'w> {
/// Adds the given boxed reflect component or bundle to the entity using the reflection data in
/// [`AppTypeRegistry`].
///
/// This will overwrite any previous component(s) of the same type.
///
/// # Panics
///
/// - If the entity has been despawned while this `EntityWorldMut` is still alive.
/// - If [`AppTypeRegistry`] does not have the reflection data for the given
/// [`Component`](crate::component::Component) or [`Bundle`](crate::bundle::Bundle).
/// - If the component or bundle data is invalid. See [`PartialReflect::apply`] for further details.
/// - If [`AppTypeRegistry`] is not present in the [`World`].
///
/// # Note
///
/// Prefer to use the typed [`EntityWorldMut::insert`] if possible. Adding a reflected component
/// is much slower.
pub fn insert_reflect(&mut self, component: Box<dyn PartialReflect>) -> &mut Self {
self.assert_not_despawned();
let entity_id = self.id();
self.world_scope(|world| {
world.resource_scope(|world, registry: Mut<AppTypeRegistry>| {
let type_registry = &registry.as_ref().read();
insert_reflect_with_registry_ref(world, entity_id, type_registry, component);
});
world.flush();
});
self.update_location();
self
}
/// Same as [`insert_reflect`](EntityWorldMut::insert_reflect), but using
/// the `T` resource as type registry instead of [`AppTypeRegistry`].
///
/// This will overwrite any previous component(s) of the same type.
///
/// # Panics
///
/// - If the entity has been despawned while this `EntityWorldMut` is still alive.
/// - If the given [`Resource`] does not have the reflection data for the given
/// [`Component`](crate::component::Component) or [`Bundle`](crate::bundle::Bundle).
/// - If the component or bundle data is invalid. See [`PartialReflect::apply`] for further details.
/// - If the given [`Resource`] is not present in the [`World`].
pub fn insert_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
&mut self,
component: Box<dyn PartialReflect>,
) -> &mut Self {
self.assert_not_despawned();
let entity_id = self.id();
self.world_scope(|world| {
world.resource_scope(|world, registry: Mut<T>| {
let type_registry = registry.as_ref().as_ref();
insert_reflect_with_registry_ref(world, entity_id, type_registry, component);
});
world.flush();
});
self.update_location();
self
}
/// Removes from the entity the component or bundle with the given type name registered in [`AppTypeRegistry`].
///
/// If the type is a bundle, it will remove any components in that bundle regardless if the entity
/// contains all the components.
///
/// Does nothing if the type is a component and the entity does not have a component of the same type,
/// if the type is a bundle and the entity does not contain any of the components in the bundle,
/// or if [`AppTypeRegistry`] does not contain the reflection data for the given component.
///
/// # Panics
///
/// - If the entity has been despawned while this `EntityWorldMut` is still alive.
/// - If [`AppTypeRegistry`] is not present in the [`World`].
///
/// # Note
///
/// Prefer to use the typed [`EntityCommands::remove`] if possible. Removing a reflected component
/// is much slower.
pub fn remove_reflect(&mut self, component_type_path: Cow<'static, str>) -> &mut Self {
self.assert_not_despawned();
let entity_id = self.id();
self.world_scope(|world| {
world.resource_scope(|world, registry: Mut<AppTypeRegistry>| {
let type_registry = &registry.as_ref().read();
remove_reflect_with_registry_ref(
world,
entity_id,
type_registry,
component_type_path,
);
});
world.flush();
});
self.update_location();
self
}
/// Same as [`remove_reflect`](EntityWorldMut::remove_reflect), but using
/// the `T` resource as type registry instead of `AppTypeRegistry`.
///
/// If the given type is a bundle, it will remove any components in that bundle regardless if the entity
/// contains all the components.
///
/// Does nothing if the type is a component and the entity does not have a component of the same type,
/// if the type is a bundle and the entity does not contain any of the components in the bundle,
/// or if [`AppTypeRegistry`] does not contain the reflection data for the given component.
///
/// # Panics
///
/// - If the entity has been despawned while this `EntityWorldMut` is still alive.
/// - If [`AppTypeRegistry`] is not present in the [`World`].
pub fn remove_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
&mut self,
component_type_path: Cow<'static, str>,
) -> &mut Self {
self.assert_not_despawned();
let entity_id = self.id();
self.world_scope(|world| {
world.resource_scope(|world, registry: Mut<T>| {
let type_registry = registry.as_ref().as_ref();
remove_reflect_with_registry_ref(
world,
entity_id,
type_registry,
component_type_path,
);
});
world.flush();
});
self.update_location();
self
}
}
/// Helper function to add a reflect component or bundle to a given entity
fn insert_reflect_with_registry_ref(
world: &mut World,
entity: Entity,
type_registry: &TypeRegistry,
component: Box<dyn PartialReflect>,
) {
let type_info = component
.get_represented_type_info()
.expect("component should represent a type.");
let type_path = type_info.type_path();
let Ok(mut entity) = world.get_entity_mut(entity) else {
panic!("error[B0003]: Could not insert a reflected component (of type {type_path}) for entity {entity}, which {}. See: https://bevyengine.org/learn/errors/b0003",
world.entities().entity_does_not_exist_error_details(entity));
};
let Some(type_registration) = type_registry.get(type_info.type_id()) else {
panic!("`{type_path}` should be registered in type registry via `App::register_type<{type_path}>`");
};
if let Some(reflect_component) = type_registration.data::<ReflectComponent>() {
reflect_component.insert(&mut entity, component.as_partial_reflect(), type_registry);
} else if let Some(reflect_bundle) = type_registration.data::<ReflectBundle>() {
reflect_bundle.insert(&mut entity, component.as_partial_reflect(), type_registry);
} else {
panic!("`{type_path}` should have #[reflect(Component)] or #[reflect(Bundle)]");
}
}
/// Helper function to remove a reflect component or bundle from a given entity
fn remove_reflect_with_registry_ref(
world: &mut World,
entity: Entity,
type_registry: &TypeRegistry,
component_type_path: Cow<'static, str>,
) {
let Ok(mut entity) = world.get_entity_mut(entity) else {
return;
};
let Some(type_registration) = type_registry.get_with_type_path(&component_type_path) else {
return;
};
if let Some(reflect_component) = type_registration.data::<ReflectComponent>() {
reflect_component.remove(&mut entity);
} else if let Some(reflect_bundle) = type_registration.data::<ReflectBundle>() {
reflect_bundle.remove(&mut entity);
}
}
#[cfg(test)]
mod tests {
use crate::{
bundle::Bundle,
component::Component,
prelude::{AppTypeRegistry, ReflectComponent},
reflect::{ReflectBundle, ReflectCommandExt},
system::{Commands, SystemState},
world::World,
};
use alloc::{borrow::ToOwned, boxed::Box};
use bevy_ecs_macros::Resource;
use bevy_reflect::{PartialReflect, Reflect, TypeRegistry};
#[derive(Resource)]
struct TypeRegistryResource {
type_registry: TypeRegistry,
}
impl AsRef<TypeRegistry> for TypeRegistryResource {
fn as_ref(&self) -> &TypeRegistry {
&self.type_registry
}
}
#[derive(Component, Reflect, Default, PartialEq, Eq, Debug)]
#[reflect(Component)]
struct ComponentA(u32);
#[derive(Component, Reflect, Default, PartialEq, Eq, Debug)]
#[reflect(Component)]
struct ComponentB(u32);
#[derive(Bundle, Reflect, Default, Debug, PartialEq)]
#[reflect(Bundle)]
struct BundleA {
a: ComponentA,
b: ComponentB,
}
#[test]
fn insert_reflected() {
let mut world = World::new();
let type_registry = AppTypeRegistry::default();
{
let mut registry = type_registry.write();
registry.register::<ComponentA>();
registry.register_type_data::<ComponentA, ReflectComponent>();
}
world.insert_resource(type_registry);
let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
let mut commands = system_state.get_mut(&mut world);
let entity = commands.spawn_empty().id();
let entity2 = commands.spawn_empty().id();
let entity3 = commands.spawn_empty().id();
let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn PartialReflect>;
let boxed_reflect_component_a_clone = boxed_reflect_component_a.reflect_clone().unwrap();
let boxed_reflect_component_a_dynamic = boxed_reflect_component_a.to_dynamic();
commands
.entity(entity)
.insert_reflect(boxed_reflect_component_a);
commands
.entity(entity2)
.insert_reflect(boxed_reflect_component_a_clone.into_partial_reflect());
commands
.entity(entity3)
.insert_reflect(boxed_reflect_component_a_dynamic);
system_state.apply(&mut world);
assert_eq!(
world.entity(entity).get::<ComponentA>(),
world.entity(entity2).get::<ComponentA>(),
);
assert_eq!(
world.entity(entity).get::<ComponentA>(),
world.entity(entity3).get::<ComponentA>(),
);
}
#[test]
fn insert_reflected_with_registry() {
let mut world = World::new();
let mut type_registry = TypeRegistryResource {
type_registry: TypeRegistry::new(),
};
type_registry.type_registry.register::<ComponentA>();
type_registry
.type_registry
.register_type_data::<ComponentA, ReflectComponent>();
world.insert_resource(type_registry);
let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
let mut commands = system_state.get_mut(&mut world);
let entity = commands.spawn_empty().id();
let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn PartialReflect>;
commands
.entity(entity)
.insert_reflect_with_registry::<TypeRegistryResource>(boxed_reflect_component_a);
system_state.apply(&mut world);
assert_eq!(
world.entity(entity).get::<ComponentA>(),
Some(&ComponentA(916))
);
}
#[test]
fn remove_reflected() {
let mut world = World::new();
let type_registry = AppTypeRegistry::default();
{
let mut registry = type_registry.write();
registry.register::<ComponentA>();
registry.register_type_data::<ComponentA, ReflectComponent>();
}
world.insert_resource(type_registry);
let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
let mut commands = system_state.get_mut(&mut world);
let entity = commands.spawn(ComponentA(0)).id();
let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn Reflect>;
commands
.entity(entity)
.remove_reflect(boxed_reflect_component_a.reflect_type_path().to_owned());
system_state.apply(&mut world);
assert_eq!(world.entity(entity).get::<ComponentA>(), None);
}
#[test]
fn remove_reflected_with_registry() {
let mut world = World::new();
let mut type_registry = TypeRegistryResource {
type_registry: TypeRegistry::new(),
};
type_registry.type_registry.register::<ComponentA>();
type_registry
.type_registry
.register_type_data::<ComponentA, ReflectComponent>();
world.insert_resource(type_registry);
let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
let mut commands = system_state.get_mut(&mut world);
let entity = commands.spawn(ComponentA(0)).id();
let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn Reflect>;
commands
.entity(entity)
.remove_reflect_with_registry::<TypeRegistryResource>(
boxed_reflect_component_a.reflect_type_path().to_owned(),
);
system_state.apply(&mut world);
assert_eq!(world.entity(entity).get::<ComponentA>(), None);
}
#[test]
fn insert_reflect_bundle() {
let mut world = World::new();
let type_registry = AppTypeRegistry::default();
{
let mut registry = type_registry.write();
registry.register::<BundleA>();
registry.register_type_data::<BundleA, ReflectBundle>();
}
world.insert_resource(type_registry);
let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
let mut commands = system_state.get_mut(&mut world);
let entity = commands.spawn_empty().id();
let bundle = Box::new(BundleA {
a: ComponentA(31),
b: ComponentB(20),
}) as Box<dyn PartialReflect>;
commands.entity(entity).insert_reflect(bundle);
system_state.apply(&mut world);
assert_eq!(world.get::<ComponentA>(entity), Some(&ComponentA(31)));
assert_eq!(world.get::<ComponentB>(entity), Some(&ComponentB(20)));
}
#[test]
fn insert_reflect_bundle_with_registry() {
let mut world = World::new();
let mut type_registry = TypeRegistryResource {
type_registry: TypeRegistry::new(),
};
type_registry.type_registry.register::<BundleA>();
type_registry
.type_registry
.register_type_data::<BundleA, ReflectBundle>();
world.insert_resource(type_registry);
let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
let mut commands = system_state.get_mut(&mut world);
let entity = commands.spawn_empty().id();
let bundle = Box::new(BundleA {
a: ComponentA(31),
b: ComponentB(20),
}) as Box<dyn PartialReflect>;
commands
.entity(entity)
.insert_reflect_with_registry::<TypeRegistryResource>(bundle);
system_state.apply(&mut world);
assert_eq!(world.get::<ComponentA>(entity), Some(&ComponentA(31)));
assert_eq!(world.get::<ComponentB>(entity), Some(&ComponentB(20)));
}
#[test]
fn remove_reflected_bundle() {
let mut world = World::new();
let type_registry = AppTypeRegistry::default();
{
let mut registry = type_registry.write();
registry.register::<BundleA>();
registry.register_type_data::<BundleA, ReflectBundle>();
}
world.insert_resource(type_registry);
let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
let mut commands = system_state.get_mut(&mut world);
let entity = commands
.spawn(BundleA {
a: ComponentA(31),
b: ComponentB(20),
})
.id();
let boxed_reflect_bundle_a = Box::new(BundleA {
a: ComponentA(1),
b: ComponentB(23),
}) as Box<dyn Reflect>;
commands
.entity(entity)
.remove_reflect(boxed_reflect_bundle_a.reflect_type_path().to_owned());
system_state.apply(&mut world);
assert_eq!(world.entity(entity).get::<ComponentA>(), None);
assert_eq!(world.entity(entity).get::<ComponentB>(), None);
}
#[test]
fn remove_reflected_bundle_with_registry() {
let mut world = World::new();
let mut type_registry = TypeRegistryResource {
type_registry: TypeRegistry::new(),
};
type_registry.type_registry.register::<BundleA>();
type_registry
.type_registry
.register_type_data::<BundleA, ReflectBundle>();
world.insert_resource(type_registry);
let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
let mut commands = system_state.get_mut(&mut world);
let entity = commands
.spawn(BundleA {
a: ComponentA(31),
b: ComponentB(20),
})
.id();
let boxed_reflect_bundle_a = Box::new(BundleA {
a: ComponentA(1),
b: ComponentB(23),
}) as Box<dyn Reflect>;
commands
.entity(entity)
.remove_reflect_with_registry::<TypeRegistryResource>(
boxed_reflect_bundle_a.reflect_type_path().to_owned(),
);
system_state.apply(&mut world);
assert_eq!(world.entity(entity).get::<ComponentA>(), None);
assert_eq!(world.entity(entity).get::<ComponentB>(), None);
}
}

View File

@@ -0,0 +1,87 @@
//! Definitions for [`FromWorld`] reflection.
//! This allows creating instances of types that are known only at runtime and
//! require an `&mut World` to be initialized.
//!
//! This module exports two types: [`ReflectFromWorldFns`] and [`ReflectFromWorld`].
//!
//! Same as [`super::component`], but for [`FromWorld`].
use alloc::boxed::Box;
use bevy_reflect::{FromType, Reflect};
use crate::world::{FromWorld, World};
/// A struct used to operate on the reflected [`FromWorld`] trait of a type.
///
/// A [`ReflectFromWorld`] for type `T` can be obtained via
/// [`bevy_reflect::TypeRegistration::data`].
#[derive(Clone)]
pub struct ReflectFromWorld(ReflectFromWorldFns);
/// The raw function pointers needed to make up a [`ReflectFromWorld`].
#[derive(Clone)]
pub struct ReflectFromWorldFns {
/// Function pointer implementing [`ReflectFromWorld::from_world()`].
pub from_world: fn(&mut World) -> Box<dyn Reflect>,
}
impl ReflectFromWorldFns {
/// Get the default set of [`ReflectFromWorldFns`] for a specific type using its
/// [`FromType`] implementation.
///
/// This is useful if you want to start with the default implementation before overriding some
/// of the functions to create a custom implementation.
pub fn new<T: Reflect + FromWorld>() -> Self {
<ReflectFromWorld as FromType<T>>::from_type().0
}
}
impl ReflectFromWorld {
/// Constructs default reflected [`FromWorld`] from world using [`from_world()`](FromWorld::from_world).
pub fn from_world(&self, world: &mut World) -> Box<dyn Reflect> {
(self.0.from_world)(world)
}
/// Create a custom implementation of [`ReflectFromWorld`].
///
/// This is an advanced feature,
/// useful for scripting implementations,
/// that should not be used by most users
/// unless you know what you are doing.
///
/// Usually you should derive [`Reflect`] and add the `#[reflect(FromWorld)]` bundle
/// to generate a [`ReflectFromWorld`] implementation automatically.
///
/// See [`ReflectFromWorldFns`] for more information.
pub fn new(fns: ReflectFromWorldFns) -> Self {
Self(fns)
}
/// The underlying function pointers implementing methods on `ReflectFromWorld`.
///
/// This is useful when you want to keep track locally of an individual
/// function pointer.
///
/// Calling [`TypeRegistry::get`] followed by
/// [`TypeRegistration::data::<ReflectFromWorld>`] can be costly if done several
/// times per frame. Consider cloning [`ReflectFromWorld`] and keeping it
/// between frames, cloning a `ReflectFromWorld` is very cheap.
///
/// If you only need a subset of the methods on `ReflectFromWorld`,
/// use `fn_pointers` to get the underlying [`ReflectFromWorldFns`]
/// and copy the subset of function pointers you care about.
///
/// [`TypeRegistration::data::<ReflectFromWorld>`]: bevy_reflect::TypeRegistration::data
/// [`TypeRegistry::get`]: bevy_reflect::TypeRegistry::get
pub fn fn_pointers(&self) -> &ReflectFromWorldFns {
&self.0
}
}
impl<B: Reflect + FromWorld> FromType<B> for ReflectFromWorld {
fn from_type() -> Self {
ReflectFromWorld(ReflectFromWorldFns {
from_world: |world| Box::new(B::from_world(world)),
})
}
}

View File

@@ -0,0 +1,38 @@
use crate::entity::{EntityMapper, MapEntities};
use bevy_reflect::{FromReflect, FromType, PartialReflect};
/// For a specific type of value, this maps any fields with values of type [`Entity`] to a new world.
///
/// Since a given `Entity` ID is only valid for the world it came from, when performing deserialization
/// any stored IDs need to be re-allocated in the destination world.
///
/// See [`EntityMapper`] and [`MapEntities`] for more information.
///
/// [`Entity`]: crate::entity::Entity
/// [`EntityMapper`]: crate::entity::EntityMapper
#[derive(Clone)]
pub struct ReflectMapEntities {
map_entities: fn(&mut dyn PartialReflect, &mut dyn EntityMapper),
}
impl ReflectMapEntities {
/// A general method for remapping entities in a reflected value via an [`EntityMapper`].
///
/// # Panics
/// Panics if the type of the reflected value doesn't match.
pub fn map_entities(&self, reflected: &mut dyn PartialReflect, mapper: &mut dyn EntityMapper) {
(self.map_entities)(reflected, mapper);
}
}
impl<C: FromReflect + MapEntities> FromType<C> for ReflectMapEntities {
fn from_type() -> Self {
ReflectMapEntities {
map_entities: |reflected, mut mapper| {
let mut concrete = C::from_reflect(reflected).expect("reflected type should match");
concrete.map_entities(&mut mapper);
reflected.apply(&concrete);
},
}
}
}

145
vendor/bevy_ecs/src/reflect/mod.rs vendored Normal file
View File

@@ -0,0 +1,145 @@
//! Types that enable reflection support.
use core::{
any::TypeId,
ops::{Deref, DerefMut},
};
use crate::{resource::Resource, world::World};
use bevy_reflect::{
std_traits::ReflectDefault, PartialReflect, Reflect, ReflectFromReflect, TypePath,
TypeRegistry, TypeRegistryArc,
};
mod bundle;
mod component;
mod entity_commands;
mod from_world;
mod map_entities;
mod resource;
pub use bundle::{ReflectBundle, ReflectBundleFns};
pub use component::{ReflectComponent, ReflectComponentFns};
pub use entity_commands::ReflectCommandExt;
pub use from_world::{ReflectFromWorld, ReflectFromWorldFns};
pub use map_entities::ReflectMapEntities;
pub use resource::{ReflectResource, ReflectResourceFns};
/// A [`Resource`] storing [`TypeRegistry`] for
/// type registrations relevant to a whole app.
#[derive(Resource, Clone, Default)]
pub struct AppTypeRegistry(pub TypeRegistryArc);
impl Deref for AppTypeRegistry {
type Target = TypeRegistryArc;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for AppTypeRegistry {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
/// A [`Resource`] storing [`FunctionRegistry`] for
/// function registrations relevant to a whole app.
///
/// [`FunctionRegistry`]: bevy_reflect::func::FunctionRegistry
#[cfg(feature = "reflect_functions")]
#[derive(Resource, Clone, Default)]
pub struct AppFunctionRegistry(pub bevy_reflect::func::FunctionRegistryArc);
#[cfg(feature = "reflect_functions")]
impl Deref for AppFunctionRegistry {
type Target = bevy_reflect::func::FunctionRegistryArc;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(feature = "reflect_functions")]
impl DerefMut for AppFunctionRegistry {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
/// Creates a `T` from a `&dyn PartialReflect`.
///
/// This will try the following strategies, in this order:
///
/// - use the reflected `FromReflect`, if it's present and doesn't fail;
/// - use the reflected `Default`, if it's present, and then call `apply` on the result;
/// - use the reflected `FromWorld`, just like the `Default`.
///
/// The first one that is present and doesn't fail will be used.
///
/// # Panics
///
/// If any strategy produces a `Box<dyn Reflect>` that doesn't store a value of type `T`
/// this method will panic.
///
/// If none of the strategies succeed, this method will panic.
pub fn from_reflect_with_fallback<T: Reflect + TypePath>(
reflected: &dyn PartialReflect,
world: &mut World,
registry: &TypeRegistry,
) -> T {
fn different_type_error<T: TypePath>(reflected: &str) -> ! {
panic!(
"The registration for the reflected `{}` trait for the type `{}` produced \
a value of a different type",
reflected,
T::type_path(),
);
}
// First, try `FromReflect`. This is handled differently from the others because
// it doesn't need a subsequent `apply` and may fail.
if let Some(reflect_from_reflect) =
registry.get_type_data::<ReflectFromReflect>(TypeId::of::<T>())
{
// If it fails it's ok, we can continue checking `Default` and `FromWorld`.
if let Some(value) = reflect_from_reflect.from_reflect(reflected) {
return value
.take::<T>()
.unwrap_or_else(|_| different_type_error::<T>("FromReflect"));
}
}
// Create an instance of `T` using either the reflected `Default` or `FromWorld`.
let mut value = if let Some(reflect_default) =
registry.get_type_data::<ReflectDefault>(TypeId::of::<T>())
{
reflect_default
.default()
.take::<T>()
.unwrap_or_else(|_| different_type_error::<T>("Default"))
} else if let Some(reflect_from_world) =
registry.get_type_data::<ReflectFromWorld>(TypeId::of::<T>())
{
reflect_from_world
.from_world(world)
.take::<T>()
.unwrap_or_else(|_| different_type_error::<T>("FromWorld"))
} else {
panic!(
"Couldn't create an instance of `{}` using the reflected `FromReflect`, \
`Default` or `FromWorld` traits. Are you perhaps missing a `#[reflect(Default)]` \
or `#[reflect(FromWorld)]`?",
// FIXME: once we have unique reflect, use `TypePath`.
core::any::type_name::<T>(),
);
};
value.apply(reflected);
value
}

256
vendor/bevy_ecs/src/reflect/resource.rs vendored Normal file
View File

@@ -0,0 +1,256 @@
//! Definitions for [`Resource`] reflection.
//!
//! # Architecture
//!
//! See the module doc for [`crate::reflect::component`].
use crate::{
change_detection::Mut,
component::ComponentId,
resource::Resource,
world::{
error::ResourceFetchError, unsafe_world_cell::UnsafeWorldCell, FilteredResources,
FilteredResourcesMut, World,
},
};
use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypePath, TypeRegistry};
use super::from_reflect_with_fallback;
/// A struct used to operate on reflected [`Resource`] of a type.
///
/// A [`ReflectResource`] for type `T` can be obtained via
/// [`bevy_reflect::TypeRegistration::data`].
#[derive(Clone)]
pub struct ReflectResource(ReflectResourceFns);
/// The raw function pointers needed to make up a [`ReflectResource`].
///
/// This is used when creating custom implementations of [`ReflectResource`] with
/// [`ReflectResource::new()`].
///
/// > **Note:**
/// > Creating custom implementations of [`ReflectResource`] is an advanced feature that most users
/// > will not need.
/// > Usually a [`ReflectResource`] is created for a type by deriving [`Reflect`]
/// > and adding the `#[reflect(Resource)]` attribute.
/// > After adding the component to the [`TypeRegistry`],
/// > its [`ReflectResource`] can then be retrieved when needed.
///
/// Creating a custom [`ReflectResource`] may be useful if you need to create new resource types at
/// runtime, for example, for scripting implementations.
///
/// By creating a custom [`ReflectResource`] and inserting it into a type's
/// [`TypeRegistration`][bevy_reflect::TypeRegistration],
/// you can modify the way that reflected resources of that type will be inserted into the bevy
/// world.
#[derive(Clone)]
pub struct ReflectResourceFns {
/// Function pointer implementing [`ReflectResource::insert()`].
pub insert: fn(&mut World, &dyn PartialReflect, &TypeRegistry),
/// Function pointer implementing [`ReflectResource::apply()`].
pub apply: fn(&mut World, &dyn PartialReflect),
/// Function pointer implementing [`ReflectResource::apply_or_insert()`].
pub apply_or_insert: fn(&mut World, &dyn PartialReflect, &TypeRegistry),
/// Function pointer implementing [`ReflectResource::remove()`].
pub remove: fn(&mut World),
/// Function pointer implementing [`ReflectResource::reflect()`].
pub reflect:
for<'w> fn(FilteredResources<'w, '_>) -> Result<&'w dyn Reflect, ResourceFetchError>,
/// Function pointer implementing [`ReflectResource::reflect_mut()`].
pub reflect_mut: for<'w> fn(
FilteredResourcesMut<'w, '_>,
) -> Result<Mut<'w, dyn Reflect>, ResourceFetchError>,
/// Function pointer implementing [`ReflectResource::reflect_unchecked_mut()`].
///
/// # Safety
/// The function may only be called with an [`UnsafeWorldCell`] that can be used to mutably access the relevant resource.
pub reflect_unchecked_mut: unsafe fn(UnsafeWorldCell<'_>) -> Option<Mut<'_, dyn Reflect>>,
/// Function pointer implementing [`ReflectResource::copy()`].
pub copy: fn(&World, &mut World, &TypeRegistry),
/// Function pointer implementing [`ReflectResource::register_resource()`].
pub register_resource: fn(&mut World) -> ComponentId,
}
impl ReflectResourceFns {
/// Get the default set of [`ReflectResourceFns`] for a specific resource type using its
/// [`FromType`] implementation.
///
/// This is useful if you want to start with the default implementation before overriding some
/// of the functions to create a custom implementation.
pub fn new<T: Resource + FromReflect + TypePath>() -> Self {
<ReflectResource as FromType<T>>::from_type().0
}
}
impl ReflectResource {
/// Insert a reflected [`Resource`] into the world like [`insert()`](World::insert_resource).
pub fn insert(
&self,
world: &mut World,
resource: &dyn PartialReflect,
registry: &TypeRegistry,
) {
(self.0.insert)(world, resource, registry);
}
/// Uses reflection to set the value of this [`Resource`] type in the world to the given value.
///
/// # Panics
///
/// Panics if there is no [`Resource`] of the given type.
pub fn apply(&self, world: &mut World, resource: &dyn PartialReflect) {
(self.0.apply)(world, resource);
}
/// Uses reflection to set the value of this [`Resource`] type in the world to the given value or insert a new one if it does not exist.
pub fn apply_or_insert(
&self,
world: &mut World,
resource: &dyn PartialReflect,
registry: &TypeRegistry,
) {
(self.0.apply_or_insert)(world, resource, registry);
}
/// Removes this [`Resource`] type from the world. Does nothing if it doesn't exist.
pub fn remove(&self, world: &mut World) {
(self.0.remove)(world);
}
/// Gets the value of this [`Resource`] type from the world as a reflected reference.
///
/// Note that [`&World`](World) is a valid type for `resources`.
pub fn reflect<'w, 's>(
&self,
resources: impl Into<FilteredResources<'w, 's>>,
) -> Result<&'w dyn Reflect, ResourceFetchError> {
(self.0.reflect)(resources.into())
}
/// Gets the value of this [`Resource`] type from the world as a mutable reflected reference.
///
/// Note that [`&mut World`](World) is a valid type for `resources`.
pub fn reflect_mut<'w, 's>(
&self,
resources: impl Into<FilteredResourcesMut<'w, 's>>,
) -> Result<Mut<'w, dyn Reflect>, ResourceFetchError> {
(self.0.reflect_mut)(resources.into())
}
/// # Safety
/// This method does not prevent you from having two mutable pointers to the same data,
/// violating Rust's aliasing rules. To avoid this:
/// * Only call this method with an [`UnsafeWorldCell`] which can be used to mutably access the resource.
/// * Don't call this method more than once in the same scope for a given [`Resource`].
pub unsafe fn reflect_unchecked_mut<'w>(
&self,
world: UnsafeWorldCell<'w>,
) -> Option<Mut<'w, dyn Reflect>> {
// SAFETY: caller promises to uphold uniqueness guarantees
unsafe { (self.0.reflect_unchecked_mut)(world) }
}
/// Gets the value of this [`Resource`] type from `source_world` and [applies](Self::apply()) it to the value of this [`Resource`] type in `destination_world`.
///
/// # Panics
///
/// Panics if there is no [`Resource`] of the given type.
pub fn copy(
&self,
source_world: &World,
destination_world: &mut World,
registry: &TypeRegistry,
) {
(self.0.copy)(source_world, destination_world, registry);
}
/// Register the type of this [`Resource`] in [`World`], returning the [`ComponentId`]
pub fn register_resource(&self, world: &mut World) -> ComponentId {
(self.0.register_resource)(world)
}
/// Create a custom implementation of [`ReflectResource`].
///
/// This is an advanced feature,
/// useful for scripting implementations,
/// that should not be used by most users
/// unless you know what you are doing.
///
/// Usually you should derive [`Reflect`] and add the `#[reflect(Resource)]` component
/// to generate a [`ReflectResource`] implementation automatically.
///
/// See [`ReflectResourceFns`] for more information.
pub fn new(&self, fns: ReflectResourceFns) -> Self {
Self(fns)
}
/// The underlying function pointers implementing methods on `ReflectResource`.
///
/// This is useful when you want to keep track locally of an individual
/// function pointer.
///
/// Calling [`TypeRegistry::get`] followed by
/// [`TypeRegistration::data::<ReflectResource>`] can be costly if done several
/// times per frame. Consider cloning [`ReflectResource`] and keeping it
/// between frames, cloning a `ReflectResource` is very cheap.
///
/// If you only need a subset of the methods on `ReflectResource`,
/// use `fn_pointers` to get the underlying [`ReflectResourceFns`]
/// and copy the subset of function pointers you care about.
///
/// [`TypeRegistration::data::<ReflectResource>`]: bevy_reflect::TypeRegistration::data
/// [`TypeRegistry::get`]: bevy_reflect::TypeRegistry::get
pub fn fn_pointers(&self) -> &ReflectResourceFns {
&self.0
}
}
impl<R: Resource + FromReflect + TypePath> FromType<R> for ReflectResource {
fn from_type() -> Self {
ReflectResource(ReflectResourceFns {
insert: |world, reflected_resource, registry| {
let resource = from_reflect_with_fallback::<R>(reflected_resource, world, registry);
world.insert_resource(resource);
},
apply: |world, reflected_resource| {
let mut resource = world.resource_mut::<R>();
resource.apply(reflected_resource);
},
apply_or_insert: |world, reflected_resource, registry| {
if let Some(mut resource) = world.get_resource_mut::<R>() {
resource.apply(reflected_resource);
} else {
let resource =
from_reflect_with_fallback::<R>(reflected_resource, world, registry);
world.insert_resource(resource);
}
},
remove: |world| {
world.remove_resource::<R>();
},
reflect: |world| world.get::<R>().map(|res| res.into_inner() as &dyn Reflect),
reflect_mut: |world| {
world
.into_mut::<R>()
.map(|res| res.map_unchanged(|value| value as &mut dyn Reflect))
},
reflect_unchecked_mut: |world| {
// SAFETY: all usages of `reflect_unchecked_mut` guarantee that there is either a single mutable
// reference or multiple immutable ones alive at any given point
let res = unsafe { world.get_resource_mut::<R>() };
res.map(|res| res.map_unchanged(|value| value as &mut dyn Reflect))
},
copy: |source_world, destination_world, registry| {
let source_resource = source_world.resource::<R>();
let destination_resource =
from_reflect_with_fallback::<R>(source_resource, destination_world, registry);
destination_world.insert_resource(destination_resource);
},
register_resource: |world: &mut World| -> ComponentId {
world.register_resource::<R>()
},
})
}
}

488
vendor/bevy_ecs/src/relationship/mod.rs vendored Normal file
View File

@@ -0,0 +1,488 @@
//! This module provides functionality to link entities to each other using specialized components called "relationships". See the [`Relationship`] trait for more info.
mod related_methods;
mod relationship_query;
mod relationship_source_collection;
use alloc::format;
pub use related_methods::*;
pub use relationship_query::*;
pub use relationship_source_collection::*;
use crate::{
component::{Component, HookContext, Mutable},
entity::{ComponentCloneCtx, Entity, SourceComponent},
error::{ignore, CommandWithEntity, HandleError},
system::entity_command::{self},
world::{DeferredWorld, EntityWorldMut},
};
use log::warn;
/// A [`Component`] on a "source" [`Entity`] that references another target [`Entity`], creating a "relationship" between them. Every [`Relationship`]
/// has a corresponding [`RelationshipTarget`] type (and vice-versa), which exists on the "target" entity of a relationship and contains the list of all
/// "source" entities that relate to the given "target"
///
/// The [`Relationship`] component is the "source of truth" and the [`RelationshipTarget`] component reflects that source of truth. When a [`Relationship`]
/// component is inserted on an [`Entity`], the corresponding [`RelationshipTarget`] component is immediately inserted on the target component if it does
/// not already exist, and the "source" entity is automatically added to the [`RelationshipTarget`] collection (this is done via "component hooks").
///
/// A common example of a [`Relationship`] is the parent / child relationship. Bevy ECS includes a canonical form of this via the [`ChildOf`](crate::hierarchy::ChildOf)
/// [`Relationship`] and the [`Children`](crate::hierarchy::Children) [`RelationshipTarget`].
///
/// [`Relationship`] and [`RelationshipTarget`] should always be derived via the [`Component`] trait to ensure the hooks are set up properly.
///
/// ## Derive
///
/// [`Relationship`] and [`RelationshipTarget`] can only be derived for structs with a single unnamed field, single named field
/// or for named structs where one field is annotated with `#[relationship]`.
/// If there are additional fields, they must all implement [`Default`].
///
/// [`RelationshipTarget`] also requires that the relationship field is private to prevent direct mutation,
/// ensuring the correctness of relationships.
/// ```
/// # use bevy_ecs::component::Component;
/// # use bevy_ecs::entity::Entity;
/// #[derive(Component)]
/// #[relationship(relationship_target = Children)]
/// pub struct ChildOf {
/// #[relationship]
/// pub parent: Entity,
/// internal: u8,
/// };
///
/// #[derive(Component)]
/// #[relationship_target(relationship = ChildOf)]
/// pub struct Children(Vec<Entity>);
/// ```
///
/// When deriving [`RelationshipTarget`] you can specify the `#[relationship_target(linked_spawn)]` attribute to
/// automatically despawn entities stored in an entity's [`RelationshipTarget`] when that entity is despawned:
///
/// ```
/// # use bevy_ecs::component::Component;
/// # use bevy_ecs::entity::Entity;
/// #[derive(Component)]
/// #[relationship(relationship_target = Children)]
/// pub struct ChildOf(pub Entity);
///
/// #[derive(Component)]
/// #[relationship_target(relationship = ChildOf, linked_spawn)]
/// pub struct Children(Vec<Entity>);
/// ```
pub trait Relationship: Component + Sized {
/// The [`Component`] added to the "target" entities of this [`Relationship`], which contains the list of all "source"
/// entities that relate to the "target".
type RelationshipTarget: RelationshipTarget<Relationship = Self>;
/// Gets the [`Entity`] ID of the related entity.
fn get(&self) -> Entity;
/// Creates this [`Relationship`] from the given `entity`.
fn from(entity: Entity) -> Self;
/// The `on_insert` component hook that maintains the [`Relationship`] / [`RelationshipTarget`] connection.
fn on_insert(
mut world: DeferredWorld,
HookContext {
entity,
caller,
relationship_hook_mode,
..
}: HookContext,
) {
match relationship_hook_mode {
RelationshipHookMode::Run => {}
RelationshipHookMode::Skip => return,
RelationshipHookMode::RunIfNotLinked => {
if <Self::RelationshipTarget as RelationshipTarget>::LINKED_SPAWN {
return;
}
}
}
let target_entity = world.entity(entity).get::<Self>().unwrap().get();
if target_entity == entity {
warn!(
"{}The {}({target_entity:?}) relationship on entity {entity:?} points to itself. The invalid {} relationship has been removed.",
caller.map(|location|format!("{location}: ")).unwrap_or_default(),
core::any::type_name::<Self>(),
core::any::type_name::<Self>()
);
world.commands().entity(entity).remove::<Self>();
return;
}
if let Ok(mut target_entity_mut) = world.get_entity_mut(target_entity) {
if let Some(mut relationship_target) =
target_entity_mut.get_mut::<Self::RelationshipTarget>()
{
relationship_target.collection_mut_risky().add(entity);
} else {
let mut target = <Self::RelationshipTarget as RelationshipTarget>::with_capacity(1);
target.collection_mut_risky().add(entity);
world.commands().entity(target_entity).insert(target);
}
} else {
warn!(
"{}The {}({target_entity:?}) relationship on entity {entity:?} relates to an entity that does not exist. The invalid {} relationship has been removed.",
caller.map(|location|format!("{location}: ")).unwrap_or_default(),
core::any::type_name::<Self>(),
core::any::type_name::<Self>()
);
world.commands().entity(entity).remove::<Self>();
}
}
/// The `on_replace` component hook that maintains the [`Relationship`] / [`RelationshipTarget`] connection.
// note: think of this as "on_drop"
fn on_replace(
mut world: DeferredWorld,
HookContext {
entity,
relationship_hook_mode,
..
}: HookContext,
) {
match relationship_hook_mode {
RelationshipHookMode::Run => {}
RelationshipHookMode::Skip => return,
RelationshipHookMode::RunIfNotLinked => {
if <Self::RelationshipTarget as RelationshipTarget>::LINKED_SPAWN {
return;
}
}
}
let target_entity = world.entity(entity).get::<Self>().unwrap().get();
if let Ok(mut target_entity_mut) = world.get_entity_mut(target_entity) {
if let Some(mut relationship_target) =
target_entity_mut.get_mut::<Self::RelationshipTarget>()
{
relationship_target.collection_mut_risky().remove(entity);
if relationship_target.len() == 0 {
let command = |mut entity: EntityWorldMut| {
// this "remove" operation must check emptiness because in the event that an identical
// relationship is inserted on top, this despawn would result in the removal of that identical
// relationship ... not what we want!
if entity
.get::<Self::RelationshipTarget>()
.is_some_and(RelationshipTarget::is_empty)
{
entity.remove::<Self::RelationshipTarget>();
}
};
world
.commands()
.queue(command.with_entity(target_entity).handle_error_with(ignore));
}
}
}
}
}
/// The iterator type for the source entities in a [`RelationshipTarget`] collection,
/// as defined in the [`RelationshipSourceCollection`] trait.
pub type SourceIter<'w, R> =
<<R as RelationshipTarget>::Collection as RelationshipSourceCollection>::SourceIter<'w>;
/// A [`Component`] containing the collection of entities that relate to this [`Entity`] via the associated `Relationship` type.
/// See the [`Relationship`] documentation for more information.
pub trait RelationshipTarget: Component<Mutability = Mutable> + Sized {
/// If this is true, when despawning or cloning (when [linked cloning is enabled](crate::entity::EntityClonerBuilder::linked_cloning)), the related entities targeting this entity will also be despawned or cloned.
///
/// For example, this is set to `true` for Bevy's built-in parent-child relation, defined by [`ChildOf`](crate::prelude::ChildOf) and [`Children`](crate::prelude::Children).
/// This means that when a parent is despawned, any children targeting that parent are also despawned (and the same applies to cloning).
///
/// To get around this behavior, you can first break the relationship between entities, and *then* despawn or clone.
/// This defaults to false when derived.
const LINKED_SPAWN: bool;
/// The [`Relationship`] that populates this [`RelationshipTarget`] collection.
type Relationship: Relationship<RelationshipTarget = Self>;
/// The collection type that stores the "source" entities for this [`RelationshipTarget`] component.
///
/// Check the list of types which implement [`RelationshipSourceCollection`] for the data structures that can be used inside of your component.
/// If you need a new collection type, you can implement the [`RelationshipSourceCollection`] trait
/// for a type you own which wraps the collection you want to use (to avoid the orphan rule),
/// or open an issue on the Bevy repository to request first-party support for your collection type.
type Collection: RelationshipSourceCollection;
/// Returns a reference to the stored [`RelationshipTarget::Collection`].
fn collection(&self) -> &Self::Collection;
/// Returns a mutable reference to the stored [`RelationshipTarget::Collection`].
///
/// # Warning
/// This should generally not be called by user code, as modifying the internal collection could invalidate the relationship.
/// The collection should not contain duplicates.
fn collection_mut_risky(&mut self) -> &mut Self::Collection;
/// Creates a new [`RelationshipTarget`] from the given [`RelationshipTarget::Collection`].
///
/// # Warning
/// This should generally not be called by user code, as constructing the internal collection could invalidate the relationship.
/// The collection should not contain duplicates.
fn from_collection_risky(collection: Self::Collection) -> Self;
/// The `on_replace` component hook that maintains the [`Relationship`] / [`RelationshipTarget`] connection.
// note: think of this as "on_drop"
fn on_replace(mut world: DeferredWorld, HookContext { entity, caller, .. }: HookContext) {
let (entities, mut commands) = world.entities_and_commands();
let relationship_target = entities.get(entity).unwrap().get::<Self>().unwrap();
for source_entity in relationship_target.iter() {
if entities.get(source_entity).is_ok() {
commands.queue(
entity_command::remove::<Self::Relationship>()
.with_entity(source_entity)
.handle_error_with(ignore),
);
} else {
warn!(
"{}Tried to despawn non-existent entity {}",
caller
.map(|location| format!("{location}: "))
.unwrap_or_default(),
source_entity
);
}
}
}
/// The `on_despawn` component hook that despawns entities stored in an entity's [`RelationshipTarget`] when
/// that entity is despawned.
// note: think of this as "on_drop"
fn on_despawn(mut world: DeferredWorld, HookContext { entity, caller, .. }: HookContext) {
let (entities, mut commands) = world.entities_and_commands();
let relationship_target = entities.get(entity).unwrap().get::<Self>().unwrap();
for source_entity in relationship_target.iter() {
if entities.get(source_entity).is_ok() {
commands.queue(
entity_command::despawn()
.with_entity(source_entity)
.handle_error_with(ignore),
);
} else {
warn!(
"{}Tried to despawn non-existent entity {}",
caller
.map(|location| format!("{location}: "))
.unwrap_or_default(),
source_entity
);
}
}
}
/// Creates this [`RelationshipTarget`] with the given pre-allocated entity capacity.
fn with_capacity(capacity: usize) -> Self {
let collection =
<Self::Collection as RelationshipSourceCollection>::with_capacity(capacity);
Self::from_collection_risky(collection)
}
/// Iterates the entities stored in this collection.
#[inline]
fn iter(&self) -> SourceIter<'_, Self> {
self.collection().iter()
}
/// Returns the number of entities in this collection.
#[inline]
fn len(&self) -> usize {
self.collection().len()
}
/// Returns true if this entity collection is empty.
#[inline]
fn is_empty(&self) -> bool {
self.collection().is_empty()
}
}
/// The "clone behavior" for [`RelationshipTarget`]. This actually creates an empty
/// [`RelationshipTarget`] instance with space reserved for the number of targets in the
/// original instance. The [`RelationshipTarget`] will then be populated with the proper components
/// when the corresponding [`Relationship`] sources of truth are inserted. Cloning the actual entities
/// in the original [`RelationshipTarget`] would result in duplicates, so we don't do that!
///
/// This will also queue up clones of the relationship sources if the [`EntityCloner`](crate::entity::EntityCloner) is configured
/// to spawn recursively.
pub fn clone_relationship_target<T: RelationshipTarget>(
source: &SourceComponent,
context: &mut ComponentCloneCtx,
) {
if let Some(component) = source.read::<T>() {
let mut cloned = T::with_capacity(component.len());
if context.linked_cloning() && T::LINKED_SPAWN {
let collection = cloned.collection_mut_risky();
for entity in component.iter() {
collection.add(entity);
context.queue_entity_clone(entity);
}
}
context.write_target_component(cloned);
}
}
/// Configures the conditions under which the Relationship insert/replace hooks will be run.
#[derive(Copy, Clone, Debug)]
pub enum RelationshipHookMode {
/// Relationship insert/replace hooks will always run
Run,
/// Relationship insert/replace hooks will run if [`RelationshipTarget::LINKED_SPAWN`] is false
RunIfNotLinked,
/// Relationship insert/replace hooks will always be skipped
Skip,
}
#[cfg(test)]
mod tests {
use crate::world::World;
use crate::{component::Component, entity::Entity};
use alloc::vec::Vec;
#[test]
fn custom_relationship() {
#[derive(Component)]
#[relationship(relationship_target = LikedBy)]
struct Likes(pub Entity);
#[derive(Component)]
#[relationship_target(relationship = Likes)]
struct LikedBy(Vec<Entity>);
let mut world = World::new();
let a = world.spawn_empty().id();
let b = world.spawn(Likes(a)).id();
let c = world.spawn(Likes(a)).id();
assert_eq!(world.entity(a).get::<LikedBy>().unwrap().0, &[b, c]);
}
#[test]
fn self_relationship_fails() {
#[derive(Component)]
#[relationship(relationship_target = RelTarget)]
struct Rel(Entity);
#[derive(Component)]
#[relationship_target(relationship = Rel)]
struct RelTarget(Vec<Entity>);
let mut world = World::new();
let a = world.spawn_empty().id();
world.entity_mut(a).insert(Rel(a));
assert!(!world.entity(a).contains::<Rel>());
assert!(!world.entity(a).contains::<RelTarget>());
}
#[test]
fn relationship_with_missing_target_fails() {
#[derive(Component)]
#[relationship(relationship_target = RelTarget)]
struct Rel(Entity);
#[derive(Component)]
#[relationship_target(relationship = Rel)]
struct RelTarget(Vec<Entity>);
let mut world = World::new();
let a = world.spawn_empty().id();
world.despawn(a);
let b = world.spawn(Rel(a)).id();
assert!(!world.entity(b).contains::<Rel>());
assert!(!world.entity(b).contains::<RelTarget>());
}
#[test]
fn relationship_with_multiple_non_target_fields_compiles() {
#[derive(Component)]
#[relationship(relationship_target=Target)]
#[expect(dead_code, reason = "test struct")]
struct Source {
#[relationship]
target: Entity,
foo: u8,
bar: u8,
}
#[derive(Component)]
#[relationship_target(relationship=Source)]
struct Target(Vec<Entity>);
// No assert necessary, looking to make sure compilation works with the macros
}
#[test]
fn relationship_target_with_multiple_non_target_fields_compiles() {
#[derive(Component)]
#[relationship(relationship_target=Target)]
struct Source(Entity);
#[derive(Component)]
#[relationship_target(relationship=Source)]
#[expect(dead_code, reason = "test struct")]
struct Target {
#[relationship]
target: Vec<Entity>,
foo: u8,
bar: u8,
}
// No assert necessary, looking to make sure compilation works with the macros
}
#[test]
fn parent_child_relationship_with_custom_relationship() {
use crate::prelude::ChildOf;
#[derive(Component)]
#[relationship(relationship_target = RelTarget)]
struct Rel(Entity);
#[derive(Component)]
#[relationship_target(relationship = Rel)]
struct RelTarget(Entity);
let mut world = World::new();
// Rel on Parent
// Despawn Parent
let mut commands = world.commands();
let child = commands.spawn_empty().id();
let parent = commands.spawn(Rel(child)).add_child(child).id();
commands.entity(parent).despawn();
world.flush();
assert!(world.get_entity(child).is_err());
assert!(world.get_entity(parent).is_err());
// Rel on Parent
// Despawn Child
let mut commands = world.commands();
let child = commands.spawn_empty().id();
let parent = commands.spawn(Rel(child)).add_child(child).id();
commands.entity(child).despawn();
world.flush();
assert!(world.get_entity(child).is_err());
assert!(!world.entity(parent).contains::<Rel>());
// Rel on Child
// Despawn Parent
let mut commands = world.commands();
let parent = commands.spawn_empty().id();
let child = commands.spawn((ChildOf(parent), Rel(parent))).id();
commands.entity(parent).despawn();
world.flush();
assert!(world.get_entity(child).is_err());
assert!(world.get_entity(parent).is_err());
// Rel on Child
// Despawn Child
let mut commands = world.commands();
let parent = commands.spawn_empty().id();
let child = commands.spawn((ChildOf(parent), Rel(parent))).id();
commands.entity(child).despawn();
world.flush();
assert!(world.get_entity(child).is_err());
assert!(!world.entity(parent).contains::<RelTarget>());
}
}

View File

@@ -0,0 +1,626 @@
use crate::{
bundle::Bundle,
entity::{hash_set::EntityHashSet, Entity},
relationship::{
Relationship, RelationshipHookMode, RelationshipSourceCollection, RelationshipTarget,
},
system::{Commands, EntityCommands},
world::{EntityWorldMut, World},
};
use bevy_platform::prelude::{Box, Vec};
use core::{marker::PhantomData, mem};
use super::OrderedRelationshipSourceCollection;
impl<'w> EntityWorldMut<'w> {
/// Spawns a entity related to this entity (with the `R` relationship) by taking a bundle
pub fn with_related<R: Relationship>(&mut self, bundle: impl Bundle) -> &mut Self {
let parent = self.id();
self.world_scope(|world| {
world.spawn((bundle, R::from(parent)));
});
self
}
/// Spawns entities related to this entity (with the `R` relationship) by taking a function that operates on a [`RelatedSpawner`].
pub fn with_related_entities<R: Relationship>(
&mut self,
func: impl FnOnce(&mut RelatedSpawner<R>),
) -> &mut Self {
let parent = self.id();
self.world_scope(|world| {
func(&mut RelatedSpawner::new(world, parent));
});
self
}
/// Relates the given entities to this entity with the relation `R`.
///
/// See [`add_one_related`](Self::add_one_related) if you want relate only one entity.
pub fn add_related<R: Relationship>(&mut self, related: &[Entity]) -> &mut Self {
let id = self.id();
self.world_scope(|world| {
for related in related {
world.entity_mut(*related).insert(R::from(id));
}
});
self
}
/// Relates the given entities to this entity with the relation `R`, starting at this particular index.
///
/// If the `related` has duplicates, a related entity will take the index of its last occurrence in `related`.
/// If the indices go out of bounds, they will be clamped into bounds.
/// This will not re-order existing related entities unless they are in `related`.
///
/// # Example
///
/// ```
/// use bevy_ecs::prelude::*;
///
/// let mut world = World::new();
/// let e0 = world.spawn_empty().id();
/// let e1 = world.spawn_empty().id();
/// let e2 = world.spawn_empty().id();
/// let e3 = world.spawn_empty().id();
/// let e4 = world.spawn_empty().id();
///
/// let mut main_entity = world.spawn_empty();
/// main_entity.add_related::<ChildOf>(&[e0, e1, e2, e2]);
/// main_entity.insert_related::<ChildOf>(1, &[e0, e3, e4, e4]);
/// let main_id = main_entity.id();
///
/// let relationship_source = main_entity.get::<Children>().unwrap().collection();
/// assert_eq!(relationship_source, &[e1, e0, e3, e2, e4]);
/// ```
pub fn insert_related<R: Relationship>(&mut self, index: usize, related: &[Entity]) -> &mut Self
where
<R::RelationshipTarget as RelationshipTarget>::Collection:
OrderedRelationshipSourceCollection,
{
let id = self.id();
self.world_scope(|world| {
for (offset, related) in related.iter().enumerate() {
let index = index.saturating_add(offset);
if world
.get::<R>(*related)
.is_some_and(|relationship| relationship.get() == id)
{
world
.get_mut::<R::RelationshipTarget>(id)
.expect("hooks should have added relationship target")
.collection_mut_risky()
.place(*related, index);
} else {
world.entity_mut(*related).insert(R::from(id));
world
.get_mut::<R::RelationshipTarget>(id)
.expect("hooks should have added relationship target")
.collection_mut_risky()
.place_most_recent(index);
}
}
});
self
}
/// Removes the relation `R` between this entity and the given entities.
pub fn remove_related<R: Relationship>(&mut self, related: &[Entity]) -> &mut Self {
let id = self.id();
self.world_scope(|world| {
for related in related {
if world
.get::<R>(*related)
.is_some_and(|relationship| relationship.get() == id)
{
world.entity_mut(*related).remove::<R>();
}
}
});
self
}
/// Replaces all the related entities with a new set of entities.
pub fn replace_related<R: Relationship>(&mut self, related: &[Entity]) -> &mut Self {
type Collection<R> =
<<R as Relationship>::RelationshipTarget as RelationshipTarget>::Collection;
if related.is_empty() {
self.remove::<R::RelationshipTarget>();
return self;
}
let Some(mut existing_relations) = self.get_mut::<R::RelationshipTarget>() else {
return self.add_related::<R>(related);
};
// We take the collection here so we can modify it without taking the component itself (this would create archetype move).
// SAFETY: We eventually return the correctly initialized collection into the target.
let mut existing_relations = mem::replace(
existing_relations.collection_mut_risky(),
Collection::<R>::with_capacity(0),
);
let mut potential_relations = EntityHashSet::from_iter(related.iter().copied());
let id = self.id();
self.world_scope(|world| {
for related in existing_relations.iter() {
if !potential_relations.remove(related) {
world.entity_mut(related).remove::<R>();
}
}
for related in potential_relations {
// SAFETY: We'll manually be adjusting the contents of the parent to fit the final state.
world
.entity_mut(related)
.insert_with_relationship_hook_mode(R::from(id), RelationshipHookMode::Skip);
}
});
// SAFETY: The entities we're inserting will be the entities that were either already there or entities that we've just inserted.
existing_relations.clear();
existing_relations.extend_from_iter(related.iter().copied());
self.insert(R::RelationshipTarget::from_collection_risky(
existing_relations,
));
self
}
/// Replaces all the related entities with a new set of entities.
///
/// This is a more efficient of [`Self::replace_related`] which doesn't allocate.
/// The passed in arguments must adhere to these invariants:
/// - `entities_to_unrelate`: A slice of entities to remove from the relationship source.
/// Entities need not be related to this entity, but must not appear in `entities_to_relate`
/// - `entities_to_relate`: A slice of entities to relate to this entity.
/// This must contain all entities that will remain related (i.e. not those in `entities_to_unrelate`) plus the newly related entities.
/// - `newly_related_entities`: A subset of `entities_to_relate` containing only entities not already related to this entity.
/// - Slices **must not** contain any duplicates
///
/// # Warning
///
/// Violating these invariants may lead to panics, crashes or unpredictable engine behavior.
///
/// # Panics
///
/// Panics when debug assertions are enabled and any invariants are broken.
///
// TODO: Consider making these iterators so users aren't required to allocate a separate buffers for the different slices.
pub fn replace_related_with_difference<R: Relationship>(
&mut self,
entities_to_unrelate: &[Entity],
entities_to_relate: &[Entity],
newly_related_entities: &[Entity],
) -> &mut Self {
#[cfg(debug_assertions)]
{
let entities_to_relate = EntityHashSet::from_iter(entities_to_relate.iter().copied());
let entities_to_unrelate =
EntityHashSet::from_iter(entities_to_unrelate.iter().copied());
let mut newly_related_entities =
EntityHashSet::from_iter(newly_related_entities.iter().copied());
assert!(
entities_to_relate.is_disjoint(&entities_to_unrelate),
"`entities_to_relate` ({entities_to_relate:?}) shared entities with `entities_to_unrelate` ({entities_to_unrelate:?})"
);
assert!(
newly_related_entities.is_disjoint(&entities_to_unrelate),
"`newly_related_entities` ({newly_related_entities:?}) shared entities with `entities_to_unrelate ({entities_to_unrelate:?})`"
);
assert!(
newly_related_entities.is_subset(&entities_to_relate),
"`newly_related_entities` ({newly_related_entities:?}) wasn't a subset of `entities_to_relate` ({entities_to_relate:?})"
);
if let Some(target) = self.get::<R::RelationshipTarget>() {
let existing_relationships: EntityHashSet = target.collection().iter().collect();
assert!(
existing_relationships.is_disjoint(&newly_related_entities),
"`newly_related_entities` contains an entity that wouldn't be newly related"
);
newly_related_entities.extend(existing_relationships);
newly_related_entities -= &entities_to_unrelate;
}
assert_eq!(newly_related_entities, entities_to_relate, "`entities_to_relate` ({entities_to_relate:?}) didn't contain all entities that would end up related");
};
if !self.contains::<R::RelationshipTarget>() {
self.add_related::<R>(entities_to_relate);
return self;
};
let this = self.id();
self.world_scope(|world| {
for unrelate in entities_to_unrelate {
world.entity_mut(*unrelate).remove::<R>();
}
for new_relation in newly_related_entities {
// We're changing the target collection manually so don't run the insert hook
world
.entity_mut(*new_relation)
.insert_with_relationship_hook_mode(R::from(this), RelationshipHookMode::Skip);
}
});
if !entities_to_relate.is_empty() {
if let Some(mut target) = self.get_mut::<R::RelationshipTarget>() {
// SAFETY: The invariants expected by this function mean we'll only be inserting entities that are already related.
let collection = target.collection_mut_risky();
collection.clear();
collection.extend_from_iter(entities_to_relate.iter().copied());
} else {
let mut empty =
<R::RelationshipTarget as RelationshipTarget>::Collection::with_capacity(
entities_to_relate.len(),
);
empty.extend_from_iter(entities_to_relate.iter().copied());
// SAFETY: We've just initialized this collection and we know there's no `RelationshipTarget` on `self`
self.insert(R::RelationshipTarget::from_collection_risky(empty));
}
}
self
}
/// Relates the given entity to this with the relation `R`.
///
/// See [`add_related`](Self::add_related) if you want to relate more than one entity.
pub fn add_one_related<R: Relationship>(&mut self, entity: Entity) -> &mut Self {
self.add_related::<R>(&[entity])
}
/// Despawns entities that relate to this one via the given [`RelationshipTarget`].
/// This entity will not be despawned.
pub fn despawn_related<S: RelationshipTarget>(&mut self) -> &mut Self {
if let Some(sources) = self.take::<S>() {
self.world_scope(|world| {
for entity in sources.iter() {
if let Ok(entity_mut) = world.get_entity_mut(entity) {
entity_mut.despawn();
}
}
});
}
self
}
/// Inserts a component or bundle of components into the entity and all related entities,
/// traversing the relationship tracked in `S` in a breadth-first manner.
///
/// # Warning
///
/// This method should only be called on relationships that form a tree-like structure.
/// Any cycles will cause this method to loop infinitely.
// We could keep track of a list of visited entities and track cycles,
// but this is not a very well-defined operation (or hard to write) for arbitrary relationships.
pub fn insert_recursive<S: RelationshipTarget>(
&mut self,
bundle: impl Bundle + Clone,
) -> &mut Self {
self.insert(bundle.clone());
if let Some(relationship_target) = self.get::<S>() {
let related_vec: Vec<Entity> = relationship_target.iter().collect();
for related in related_vec {
self.world_scope(|world| {
world
.entity_mut(related)
.insert_recursive::<S>(bundle.clone());
});
}
}
self
}
/// Removes a component or bundle of components of type `B` from the entity and all related entities,
/// traversing the relationship tracked in `S` in a breadth-first manner.
///
/// # Warning
///
/// This method should only be called on relationships that form a tree-like structure.
/// Any cycles will cause this method to loop infinitely.
pub fn remove_recursive<S: RelationshipTarget, B: Bundle>(&mut self) -> &mut Self {
self.remove::<B>();
if let Some(relationship_target) = self.get::<S>() {
let related_vec: Vec<Entity> = relationship_target.iter().collect();
for related in related_vec {
self.world_scope(|world| {
world.entity_mut(related).remove_recursive::<S, B>();
});
}
}
self
}
}
impl<'a> EntityCommands<'a> {
/// Spawns a entity related to this entity (with the `R` relationship) by taking a bundle
pub fn with_related<R: Relationship>(&mut self, bundle: impl Bundle) -> &mut Self {
let parent = self.id();
self.commands.spawn((bundle, R::from(parent)));
self
}
/// Spawns entities related to this entity (with the `R` relationship) by taking a function that operates on a [`RelatedSpawner`].
pub fn with_related_entities<R: Relationship>(
&mut self,
func: impl FnOnce(&mut RelatedSpawnerCommands<R>),
) -> &mut Self {
let id = self.id();
func(&mut RelatedSpawnerCommands::new(self.commands(), id));
self
}
/// Relates the given entities to this entity with the relation `R`.
///
/// See [`add_one_related`](Self::add_one_related) if you want relate only one entity.
pub fn add_related<R: Relationship>(&mut self, related: &[Entity]) -> &mut Self {
let related: Box<[Entity]> = related.into();
self.queue(move |mut entity: EntityWorldMut| {
entity.add_related::<R>(&related);
})
}
/// Relates the given entities to this entity with the relation `R`, starting at this particular index.
///
/// If the `related` has duplicates, a related entity will take the index of its last occurrence in `related`.
/// If the indices go out of bounds, they will be clamped into bounds.
/// This will not re-order existing related entities unless they are in `related`.
pub fn insert_related<R: Relationship>(&mut self, index: usize, related: &[Entity]) -> &mut Self
where
<R::RelationshipTarget as RelationshipTarget>::Collection:
OrderedRelationshipSourceCollection,
{
let related: Box<[Entity]> = related.into();
self.queue(move |mut entity: EntityWorldMut| {
entity.insert_related::<R>(index, &related);
})
}
/// Relates the given entity to this with the relation `R`.
///
/// See [`add_related`](Self::add_related) if you want to relate more than one entity.
pub fn add_one_related<R: Relationship>(&mut self, entity: Entity) -> &mut Self {
self.add_related::<R>(&[entity])
}
/// Removes the relation `R` between this entity and the given entities.
pub fn remove_related<R: Relationship>(&mut self, related: &[Entity]) -> &mut Self {
let related: Box<[Entity]> = related.into();
self.queue(move |mut entity: EntityWorldMut| {
entity.remove_related::<R>(&related);
})
}
/// Replaces all the related entities with the given set of new related entities.
pub fn replace_related<R: Relationship>(&mut self, related: &[Entity]) -> &mut Self {
let related: Box<[Entity]> = related.into();
self.queue(move |mut entity: EntityWorldMut| {
entity.replace_related::<R>(&related);
})
}
/// Replaces all the related entities with a new set of entities.
///
/// # Warning
///
/// Failing to maintain the functions invariants may lead to erratic engine behavior including random crashes.
/// Refer to [`EntityWorldMut::replace_related_with_difference`] for a list of these invariants.
///
/// # Panics
///
/// Panics when debug assertions are enable, an invariant is are broken and the command is executed.
pub fn replace_related_with_difference<R: Relationship>(
&mut self,
entities_to_unrelate: &[Entity],
entities_to_relate: &[Entity],
newly_related_entities: &[Entity],
) -> &mut Self {
let entities_to_unrelate: Box<[Entity]> = entities_to_unrelate.into();
let entities_to_relate: Box<[Entity]> = entities_to_relate.into();
let newly_related_entities: Box<[Entity]> = newly_related_entities.into();
self.queue(move |mut entity: EntityWorldMut| {
entity.replace_related_with_difference::<R>(
&entities_to_unrelate,
&entities_to_relate,
&newly_related_entities,
);
})
}
/// Despawns entities that relate to this one via the given [`RelationshipTarget`].
/// This entity will not be despawned.
pub fn despawn_related<S: RelationshipTarget>(&mut self) -> &mut Self {
self.queue(move |mut entity: EntityWorldMut| {
entity.despawn_related::<S>();
})
}
/// Inserts a component or bundle of components into the entity and all related entities,
/// traversing the relationship tracked in `S` in a breadth-first manner.
///
/// # Warning
///
/// This method should only be called on relationships that form a tree-like structure.
/// Any cycles will cause this method to loop infinitely.
pub fn insert_recursive<S: RelationshipTarget>(
&mut self,
bundle: impl Bundle + Clone,
) -> &mut Self {
self.queue(move |mut entity: EntityWorldMut| {
entity.insert_recursive::<S>(bundle);
})
}
/// Removes a component or bundle of components of type `B` from the entity and all related entities,
/// traversing the relationship tracked in `S` in a breadth-first manner.
///
/// # Warning
///
/// This method should only be called on relationships that form a tree-like structure.
/// Any cycles will cause this method to loop infinitely.
pub fn remove_recursive<S: RelationshipTarget, B: Bundle>(&mut self) -> &mut Self {
self.queue(move |mut entity: EntityWorldMut| {
entity.remove_recursive::<S, B>();
})
}
}
/// Directly spawns related "source" entities with the given [`Relationship`], targeting
/// a specific entity.
pub struct RelatedSpawner<'w, R: Relationship> {
target: Entity,
world: &'w mut World,
_marker: PhantomData<R>,
}
impl<'w, R: Relationship> RelatedSpawner<'w, R> {
/// Creates a new instance that will spawn entities targeting the `target` entity.
pub fn new(world: &'w mut World, target: Entity) -> Self {
Self {
world,
target,
_marker: PhantomData,
}
}
/// Spawns an entity with the given `bundle` and an `R` relationship targeting the `target`
/// entity this spawner was initialized with.
pub fn spawn(&mut self, bundle: impl Bundle) -> EntityWorldMut<'_> {
self.world.spawn((R::from(self.target), bundle))
}
/// Spawns an entity with an `R` relationship targeting the `target`
/// entity this spawner was initialized with.
pub fn spawn_empty(&mut self) -> EntityWorldMut<'_> {
self.world.spawn(R::from(self.target))
}
/// Returns the "target entity" used when spawning entities with an `R` [`Relationship`].
pub fn target_entity(&self) -> Entity {
self.target
}
/// Returns a reference to the underlying [`World`].
pub fn world(&self) -> &World {
self.world
}
/// Returns a mutable reference to the underlying [`World`].
pub fn world_mut(&mut self) -> &mut World {
self.world
}
}
/// Uses commands to spawn related "source" entities with the given [`Relationship`], targeting
/// a specific entity.
pub struct RelatedSpawnerCommands<'w, R: Relationship> {
target: Entity,
commands: Commands<'w, 'w>,
_marker: PhantomData<R>,
}
impl<'w, R: Relationship> RelatedSpawnerCommands<'w, R> {
/// Creates a new instance that will spawn entities targeting the `target` entity.
pub fn new(commands: Commands<'w, 'w>, target: Entity) -> Self {
Self {
commands,
target,
_marker: PhantomData,
}
}
/// Spawns an entity with the given `bundle` and an `R` relationship targeting the `target`
/// entity this spawner was initialized with.
pub fn spawn(&mut self, bundle: impl Bundle) -> EntityCommands<'_> {
self.commands.spawn((R::from(self.target), bundle))
}
/// Spawns an entity with an `R` relationship targeting the `target`
/// entity this spawner was initialized with.
pub fn spawn_empty(&mut self) -> EntityCommands<'_> {
self.commands.spawn(R::from(self.target))
}
/// Returns the "target entity" used when spawning entities with an `R` [`Relationship`].
pub fn target_entity(&self) -> Entity {
self.target
}
/// Returns the underlying [`Commands`].
pub fn commands(&mut self) -> Commands {
self.commands.reborrow()
}
/// Returns a mutable reference to the underlying [`Commands`].
pub fn commands_mut(&mut self) -> &mut Commands<'w, 'w> {
&mut self.commands
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::prelude::{ChildOf, Children, Component};
#[derive(Component, Clone, Copy)]
struct TestComponent;
#[test]
fn insert_and_remove_recursive() {
let mut world = World::new();
let a = world.spawn_empty().id();
let b = world.spawn(ChildOf(a)).id();
let c = world.spawn(ChildOf(a)).id();
let d = world.spawn(ChildOf(b)).id();
world
.entity_mut(a)
.insert_recursive::<Children>(TestComponent);
for entity in [a, b, c, d] {
assert!(world.entity(entity).contains::<TestComponent>());
}
world
.entity_mut(b)
.remove_recursive::<Children, TestComponent>();
// Parent
assert!(world.entity(a).contains::<TestComponent>());
// Target
assert!(!world.entity(b).contains::<TestComponent>());
// Sibling
assert!(world.entity(c).contains::<TestComponent>());
// Child
assert!(!world.entity(d).contains::<TestComponent>());
world
.entity_mut(a)
.remove_recursive::<Children, TestComponent>();
for entity in [a, b, c, d] {
assert!(!world.entity(entity).contains::<TestComponent>());
}
}
}

View File

@@ -0,0 +1,272 @@
use crate::{
entity::Entity,
query::{QueryData, QueryFilter},
relationship::{Relationship, RelationshipTarget},
system::Query,
};
use alloc::collections::VecDeque;
use smallvec::SmallVec;
use super::SourceIter;
impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// If the given `entity` contains the `R` [`Relationship`] component, returns the
/// target entity of that relationship.
pub fn related<R: Relationship>(&'w self, entity: Entity) -> Option<Entity>
where
<D as QueryData>::ReadOnly: QueryData<Item<'w> = &'w R>,
{
self.get(entity).map(R::get).ok()
}
/// If the given `entity` contains the `S` [`RelationshipTarget`] component, returns the
/// source entities stored on that component.
pub fn relationship_sources<S: RelationshipTarget>(
&'w self,
entity: Entity,
) -> impl Iterator<Item = Entity> + 'w
where
<D as QueryData>::ReadOnly: QueryData<Item<'w> = &'w S>,
{
self.get(entity)
.into_iter()
.flat_map(RelationshipTarget::iter)
}
/// Recursively walks up the tree defined by the given `R` [`Relationship`] until
/// there are no more related entities, returning the "root entity" of the relationship hierarchy.
///
/// # Warning
///
/// For relationship graphs that contain loops, this could loop infinitely.
/// If your relationship is not a tree (like Bevy's hierarchy), be sure to stop if you encounter a duplicate entity.
pub fn root_ancestor<R: Relationship>(&'w self, entity: Entity) -> Entity
where
<D as QueryData>::ReadOnly: QueryData<Item<'w> = &'w R>,
{
// Recursively search up the tree until we're out of parents
match self.get(entity) {
Ok(parent) => self.root_ancestor(parent.get()),
Err(_) => entity,
}
}
/// Iterates all "leaf entities" as defined by the [`RelationshipTarget`] hierarchy.
///
/// # Warning
///
/// For relationship graphs that contain loops, this could loop infinitely.
/// If your relationship is not a tree (like Bevy's hierarchy), be sure to stop if you encounter a duplicate entity.
pub fn iter_leaves<S: RelationshipTarget>(
&'w self,
entity: Entity,
) -> impl Iterator<Item = Entity> + 'w
where
<D as QueryData>::ReadOnly: QueryData<Item<'w> = &'w S>,
SourceIter<'w, S>: DoubleEndedIterator,
{
self.iter_descendants_depth_first(entity).filter(|entity| {
self.get(*entity)
// These are leaf nodes if they have the `Children` component but it's empty
.map(|children| children.len() == 0)
// Or if they don't have the `Children` component at all
.unwrap_or(true)
})
}
/// Iterates all sibling entities that also have the `R` [`Relationship`] with the same target entity.
pub fn iter_siblings<R: Relationship>(
&'w self,
entity: Entity,
) -> impl Iterator<Item = Entity> + 'w
where
D::ReadOnly: QueryData<Item<'w> = (Option<&'w R>, Option<&'w R::RelationshipTarget>)>,
{
self.get(entity)
.ok()
.and_then(|(maybe_parent, _)| maybe_parent.map(R::get))
.and_then(|parent| self.get(parent).ok())
.and_then(|(_, maybe_children)| maybe_children)
.into_iter()
.flat_map(move |children| children.iter().filter(move |child| *child != entity))
}
/// Iterates all descendant entities as defined by the given `entity`'s [`RelationshipTarget`] and their recursive
/// [`RelationshipTarget`].
///
/// # Warning
///
/// For relationship graphs that contain loops, this could loop infinitely.
/// If your relationship is not a tree (like Bevy's hierarchy), be sure to stop if you encounter a duplicate entity.
pub fn iter_descendants<S: RelationshipTarget>(
&'w self,
entity: Entity,
) -> DescendantIter<'w, 's, D, F, S>
where
D::ReadOnly: QueryData<Item<'w> = &'w S>,
{
DescendantIter::new(self, entity)
}
/// Iterates all descendant entities as defined by the given `entity`'s [`RelationshipTarget`] and their recursive
/// [`RelationshipTarget`] in depth-first order.
///
/// # Warning
///
/// For relationship graphs that contain loops, this could loop infinitely.
/// If your relationship is not a tree (like Bevy's hierarchy), be sure to stop if you encounter a duplicate entity.
pub fn iter_descendants_depth_first<S: RelationshipTarget>(
&'w self,
entity: Entity,
) -> DescendantDepthFirstIter<'w, 's, D, F, S>
where
D::ReadOnly: QueryData<Item<'w> = &'w S>,
SourceIter<'w, S>: DoubleEndedIterator,
{
DescendantDepthFirstIter::new(self, entity)
}
/// Iterates all ancestors of the given `entity` as defined by the `R` [`Relationship`].
///
/// # Warning
///
/// For relationship graphs that contain loops, this could loop infinitely.
/// If your relationship is not a tree (like Bevy's hierarchy), be sure to stop if you encounter a duplicate entity.
pub fn iter_ancestors<R: Relationship>(
&'w self,
entity: Entity,
) -> AncestorIter<'w, 's, D, F, R>
where
D::ReadOnly: QueryData<Item<'w> = &'w R>,
{
AncestorIter::new(self, entity)
}
}
/// An [`Iterator`] of [`Entity`]s over the descendants of an [`Entity`].
///
/// Traverses the hierarchy breadth-first.
pub struct DescendantIter<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget>
where
D::ReadOnly: QueryData<Item<'w> = &'w S>,
{
children_query: &'w Query<'w, 's, D, F>,
vecdeque: VecDeque<Entity>,
}
impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> DescendantIter<'w, 's, D, F, S>
where
D::ReadOnly: QueryData<Item<'w> = &'w S>,
{
/// Returns a new [`DescendantIter`].
pub fn new(children_query: &'w Query<'w, 's, D, F>, entity: Entity) -> Self {
DescendantIter {
children_query,
vecdeque: children_query
.get(entity)
.into_iter()
.flat_map(RelationshipTarget::iter)
.collect(),
}
}
}
impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> Iterator
for DescendantIter<'w, 's, D, F, S>
where
D::ReadOnly: QueryData<Item<'w> = &'w S>,
{
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
let entity = self.vecdeque.pop_front()?;
if let Ok(children) = self.children_query.get(entity) {
self.vecdeque.extend(children.iter());
}
Some(entity)
}
}
/// An [`Iterator`] of [`Entity`]s over the descendants of an [`Entity`].
///
/// Traverses the hierarchy depth-first.
pub struct DescendantDepthFirstIter<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget>
where
D::ReadOnly: QueryData<Item<'w> = &'w S>,
{
children_query: &'w Query<'w, 's, D, F>,
stack: SmallVec<[Entity; 8]>,
}
impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget>
DescendantDepthFirstIter<'w, 's, D, F, S>
where
D::ReadOnly: QueryData<Item<'w> = &'w S>,
SourceIter<'w, S>: DoubleEndedIterator,
{
/// Returns a new [`DescendantDepthFirstIter`].
pub fn new(children_query: &'w Query<'w, 's, D, F>, entity: Entity) -> Self {
DescendantDepthFirstIter {
children_query,
stack: children_query
.get(entity)
.map_or(SmallVec::new(), |children| children.iter().rev().collect()),
}
}
}
impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> Iterator
for DescendantDepthFirstIter<'w, 's, D, F, S>
where
D::ReadOnly: QueryData<Item<'w> = &'w S>,
SourceIter<'w, S>: DoubleEndedIterator,
{
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
let entity = self.stack.pop()?;
if let Ok(children) = self.children_query.get(entity) {
self.stack.extend(children.iter().rev());
}
Some(entity)
}
}
/// An [`Iterator`] of [`Entity`]s over the ancestors of an [`Entity`].
pub struct AncestorIter<'w, 's, D: QueryData, F: QueryFilter, R: Relationship>
where
D::ReadOnly: QueryData<Item<'w> = &'w R>,
{
parent_query: &'w Query<'w, 's, D, F>,
next: Option<Entity>,
}
impl<'w, 's, D: QueryData, F: QueryFilter, R: Relationship> AncestorIter<'w, 's, D, F, R>
where
D::ReadOnly: QueryData<Item<'w> = &'w R>,
{
/// Returns a new [`AncestorIter`].
pub fn new(parent_query: &'w Query<'w, 's, D, F>, entity: Entity) -> Self {
AncestorIter {
parent_query,
next: Some(entity),
}
}
}
impl<'w, 's, D: QueryData, F: QueryFilter, R: Relationship> Iterator
for AncestorIter<'w, 's, D, F, R>
where
D::ReadOnly: QueryData<Item<'w> = &'w R>,
{
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
self.next = self.parent_query.get(self.next?).ok().map(R::get);
self.next
}
}

View File

@@ -0,0 +1,586 @@
use crate::entity::{hash_set::EntityHashSet, Entity};
use alloc::vec::Vec;
use smallvec::SmallVec;
/// The internal [`Entity`] collection used by a [`RelationshipTarget`](crate::relationship::RelationshipTarget) component.
/// This is not intended to be modified directly by users, as it could invalidate the correctness of relationships.
pub trait RelationshipSourceCollection {
/// The type of iterator returned by the `iter` method.
///
/// This is an associated type (rather than using a method that returns an opaque return-position impl trait)
/// to ensure that all methods and traits (like [`DoubleEndedIterator`]) of the underlying collection's iterator
/// are available to the user when implemented without unduly restricting the possible collections.
///
/// The [`SourceIter`](super::SourceIter) type alias can be helpful to reduce confusion when working with this associated type.
type SourceIter<'a>: Iterator<Item = Entity>
where
Self: 'a;
/// Creates a new empty instance.
fn new() -> Self;
/// Returns an instance with the given pre-allocated entity `capacity`.
///
/// Some collections will ignore the provided `capacity` and return a default instance.
fn with_capacity(capacity: usize) -> Self;
/// Reserves capacity for at least `additional` more entities to be inserted.
///
/// Not all collections support this operation, in which case it is a no-op.
fn reserve(&mut self, additional: usize);
/// Adds the given `entity` to the collection.
///
/// Returns whether the entity was added to the collection.
/// Mainly useful when dealing with collections that don't allow
/// multiple instances of the same entity ([`EntityHashSet`]).
fn add(&mut self, entity: Entity) -> bool;
/// Removes the given `entity` from the collection.
///
/// Returns whether the collection actually contained
/// the entity.
fn remove(&mut self, entity: Entity) -> bool;
/// Iterates all entities in the collection.
fn iter(&self) -> Self::SourceIter<'_>;
/// Returns the current length of the collection.
fn len(&self) -> usize;
/// Clears the collection.
fn clear(&mut self);
/// Attempts to save memory by shrinking the capacity to fit the current length.
///
/// This operation is a no-op for collections that do not support it.
fn shrink_to_fit(&mut self);
/// Returns true if the collection contains no entities.
#[inline]
fn is_empty(&self) -> bool {
self.len() == 0
}
/// Add multiple entities to collection at once.
///
/// May be faster than repeatedly calling [`Self::add`].
fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {
// The method name shouldn't conflict with `Extend::extend` as it's in the rust prelude and
// would always conflict with it.
for entity in entities {
self.add(entity);
}
}
}
/// This trait signals that a [`RelationshipSourceCollection`] is ordered.
pub trait OrderedRelationshipSourceCollection: RelationshipSourceCollection {
/// Inserts the entity at a specific index.
/// If the index is too large, the entity will be added to the end of the collection.
fn insert(&mut self, index: usize, entity: Entity);
/// Removes the entity at the specified idnex if it exists.
fn remove_at(&mut self, index: usize) -> Option<Entity>;
/// Inserts the entity at a specific index.
/// This will never reorder other entities.
/// If the index is too large, the entity will be added to the end of the collection.
fn insert_stable(&mut self, index: usize, entity: Entity);
/// Removes the entity at the specified idnex if it exists.
/// This will never reorder other entities.
fn remove_at_stable(&mut self, index: usize) -> Option<Entity>;
/// Sorts the source collection.
fn sort(&mut self);
/// Inserts the entity at the proper place to maintain sorting.
fn insert_sorted(&mut self, entity: Entity);
/// This places the most recently added entity at the particular index.
fn place_most_recent(&mut self, index: usize);
/// This places the given entity at the particular index.
/// This will do nothing if the entity is not in the collection.
/// If the index is out of bounds, this will put the entity at the end.
fn place(&mut self, entity: Entity, index: usize);
/// Adds the entity at index 0.
fn push_front(&mut self, entity: Entity) {
self.insert(0, entity);
}
/// Adds the entity to the back of the collection.
fn push_back(&mut self, entity: Entity) {
self.insert(usize::MAX, entity);
}
/// Removes the first entity.
fn pop_front(&mut self) -> Option<Entity> {
self.remove_at(0)
}
/// Removes the last entity.
fn pop_back(&mut self) -> Option<Entity> {
if self.is_empty() {
None
} else {
self.remove_at(self.len() - 1)
}
}
}
impl RelationshipSourceCollection for Vec<Entity> {
type SourceIter<'a> = core::iter::Copied<core::slice::Iter<'a, Entity>>;
fn new() -> Self {
Vec::new()
}
fn reserve(&mut self, additional: usize) {
Vec::reserve(self, additional);
}
fn with_capacity(capacity: usize) -> Self {
Vec::with_capacity(capacity)
}
fn add(&mut self, entity: Entity) -> bool {
Vec::push(self, entity);
true
}
fn remove(&mut self, entity: Entity) -> bool {
if let Some(index) = <[Entity]>::iter(self).position(|e| *e == entity) {
Vec::remove(self, index);
return true;
}
false
}
fn iter(&self) -> Self::SourceIter<'_> {
<[Entity]>::iter(self).copied()
}
fn len(&self) -> usize {
Vec::len(self)
}
fn clear(&mut self) {
self.clear();
}
fn shrink_to_fit(&mut self) {
Vec::shrink_to_fit(self);
}
fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {
self.extend(entities);
}
}
impl OrderedRelationshipSourceCollection for Vec<Entity> {
fn insert(&mut self, index: usize, entity: Entity) {
self.push(entity);
let len = self.len();
if index < len {
self.swap(index, len - 1);
}
}
fn remove_at(&mut self, index: usize) -> Option<Entity> {
(index < self.len()).then(|| self.swap_remove(index))
}
fn insert_stable(&mut self, index: usize, entity: Entity) {
if index < self.len() {
Vec::insert(self, index, entity);
} else {
self.push(entity);
}
}
fn remove_at_stable(&mut self, index: usize) -> Option<Entity> {
(index < self.len()).then(|| self.remove(index))
}
fn sort(&mut self) {
self.sort_unstable();
}
fn insert_sorted(&mut self, entity: Entity) {
let index = self.partition_point(|e| e <= &entity);
self.insert_stable(index, entity);
}
fn place_most_recent(&mut self, index: usize) {
if let Some(entity) = self.pop() {
let index = index.min(self.len());
self.insert(index, entity);
}
}
fn place(&mut self, entity: Entity, index: usize) {
if let Some(current) = <[Entity]>::iter(self).position(|e| *e == entity) {
let index = index.min(self.len());
Vec::remove(self, current);
self.insert(index, entity);
};
}
}
impl RelationshipSourceCollection for EntityHashSet {
type SourceIter<'a> = core::iter::Copied<crate::entity::hash_set::Iter<'a>>;
fn new() -> Self {
EntityHashSet::new()
}
fn reserve(&mut self, additional: usize) {
self.0.reserve(additional);
}
fn with_capacity(capacity: usize) -> Self {
EntityHashSet::with_capacity(capacity)
}
fn add(&mut self, entity: Entity) -> bool {
self.insert(entity)
}
fn remove(&mut self, entity: Entity) -> bool {
// We need to call the remove method on the underlying hash set,
// which takes its argument by reference
self.0.remove(&entity)
}
fn iter(&self) -> Self::SourceIter<'_> {
self.iter().copied()
}
fn len(&self) -> usize {
self.len()
}
fn clear(&mut self) {
self.0.clear();
}
fn shrink_to_fit(&mut self) {
self.0.shrink_to_fit();
}
fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {
self.extend(entities);
}
}
impl<const N: usize> RelationshipSourceCollection for SmallVec<[Entity; N]> {
type SourceIter<'a> = core::iter::Copied<core::slice::Iter<'a, Entity>>;
fn new() -> Self {
SmallVec::new()
}
fn reserve(&mut self, additional: usize) {
SmallVec::reserve(self, additional);
}
fn with_capacity(capacity: usize) -> Self {
SmallVec::with_capacity(capacity)
}
fn add(&mut self, entity: Entity) -> bool {
SmallVec::push(self, entity);
true
}
fn remove(&mut self, entity: Entity) -> bool {
if let Some(index) = <[Entity]>::iter(self).position(|e| *e == entity) {
SmallVec::remove(self, index);
return true;
}
false
}
fn iter(&self) -> Self::SourceIter<'_> {
<[Entity]>::iter(self).copied()
}
fn len(&self) -> usize {
SmallVec::len(self)
}
fn clear(&mut self) {
self.clear();
}
fn shrink_to_fit(&mut self) {
SmallVec::shrink_to_fit(self);
}
fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {
self.extend(entities);
}
}
impl RelationshipSourceCollection for Entity {
type SourceIter<'a> = core::option::IntoIter<Entity>;
fn new() -> Self {
Entity::PLACEHOLDER
}
fn reserve(&mut self, _: usize) {}
fn with_capacity(_capacity: usize) -> Self {
Self::new()
}
fn add(&mut self, entity: Entity) -> bool {
assert_eq!(
*self,
Entity::PLACEHOLDER,
"Entity {entity} attempted to target an entity with a one-to-one relationship, but it is already targeted by {}. You must remove the original relationship first.",
*self
);
*self = entity;
true
}
fn remove(&mut self, entity: Entity) -> bool {
if *self == entity {
*self = Entity::PLACEHOLDER;
return true;
}
false
}
fn iter(&self) -> Self::SourceIter<'_> {
if *self == Entity::PLACEHOLDER {
None.into_iter()
} else {
Some(*self).into_iter()
}
}
fn len(&self) -> usize {
if *self == Entity::PLACEHOLDER {
return 0;
}
1
}
fn clear(&mut self) {
*self = Entity::PLACEHOLDER;
}
fn shrink_to_fit(&mut self) {}
fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {
for entity in entities {
assert_eq!(
*self,
Entity::PLACEHOLDER,
"Entity {entity} attempted to target an entity with a one-to-one relationship, but it is already targeted by {}. You must remove the original relationship first.",
*self
);
*self = entity;
}
}
}
impl<const N: usize> OrderedRelationshipSourceCollection for SmallVec<[Entity; N]> {
fn insert(&mut self, index: usize, entity: Entity) {
self.push(entity);
let len = self.len();
if index < len {
self.swap(index, len - 1);
}
}
fn remove_at(&mut self, index: usize) -> Option<Entity> {
(index < self.len()).then(|| self.swap_remove(index))
}
fn insert_stable(&mut self, index: usize, entity: Entity) {
if index < self.len() {
SmallVec::<[Entity; N]>::insert(self, index, entity);
} else {
self.push(entity);
}
}
fn remove_at_stable(&mut self, index: usize) -> Option<Entity> {
(index < self.len()).then(|| self.remove(index))
}
fn sort(&mut self) {
self.sort_unstable();
}
fn insert_sorted(&mut self, entity: Entity) {
let index = self.partition_point(|e| e <= &entity);
self.insert_stable(index, entity);
}
fn place_most_recent(&mut self, index: usize) {
if let Some(entity) = self.pop() {
let index = index.min(self.len() - 1);
self.insert(index, entity);
}
}
fn place(&mut self, entity: Entity, index: usize) {
if let Some(current) = <[Entity]>::iter(self).position(|e| *e == entity) {
// The len is at least 1, so the subtraction is safe.
let index = index.min(self.len() - 1);
SmallVec::<[Entity; N]>::remove(self, current);
self.insert(index, entity);
};
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::prelude::{Component, World};
use crate::relationship::RelationshipTarget;
#[test]
fn vec_relationship_source_collection() {
#[derive(Component)]
#[relationship(relationship_target = RelTarget)]
struct Rel(Entity);
#[derive(Component)]
#[relationship_target(relationship = Rel, linked_spawn)]
struct RelTarget(Vec<Entity>);
let mut world = World::new();
let a = world.spawn_empty().id();
let b = world.spawn_empty().id();
world.entity_mut(a).insert(Rel(b));
let rel_target = world.get::<RelTarget>(b).unwrap();
let collection = rel_target.collection();
assert_eq!(collection, &alloc::vec!(a));
}
#[test]
fn smallvec_relationship_source_collection() {
#[derive(Component)]
#[relationship(relationship_target = RelTarget)]
struct Rel(Entity);
#[derive(Component)]
#[relationship_target(relationship = Rel, linked_spawn)]
struct RelTarget(SmallVec<[Entity; 4]>);
let mut world = World::new();
let a = world.spawn_empty().id();
let b = world.spawn_empty().id();
world.entity_mut(a).insert(Rel(b));
let rel_target = world.get::<RelTarget>(b).unwrap();
let collection = rel_target.collection();
assert_eq!(collection, &SmallVec::from_buf([a]));
}
#[test]
fn entity_relationship_source_collection() {
#[derive(Component)]
#[relationship(relationship_target = RelTarget)]
struct Rel(Entity);
#[derive(Component)]
#[relationship_target(relationship = Rel)]
struct RelTarget(Entity);
let mut world = World::new();
let a = world.spawn_empty().id();
let b = world.spawn_empty().id();
world.entity_mut(a).insert(Rel(b));
let rel_target = world.get::<RelTarget>(b).unwrap();
let collection = rel_target.collection();
assert_eq!(collection, &a);
}
#[test]
fn one_to_one_relationships() {
#[derive(Component)]
#[relationship(relationship_target = Below)]
struct Above(Entity);
#[derive(Component)]
#[relationship_target(relationship = Above)]
struct Below(Entity);
let mut world = World::new();
let a = world.spawn_empty().id();
let b = world.spawn_empty().id();
world.entity_mut(a).insert(Above(b));
assert_eq!(a, world.get::<Below>(b).unwrap().0);
// Verify removing target removes relationship
world.entity_mut(b).remove::<Below>();
assert!(world.get::<Above>(a).is_none());
// Verify removing relationship removes target
world.entity_mut(a).insert(Above(b));
world.entity_mut(a).remove::<Above>();
assert!(world.get::<Below>(b).is_none());
// Actually - a is above c now! Verify relationship was updated correctly
let c = world.spawn_empty().id();
world.entity_mut(a).insert(Above(c));
assert!(world.get::<Below>(b).is_none());
assert_eq!(a, world.get::<Below>(c).unwrap().0);
}
#[test]
#[should_panic]
fn one_to_one_relationship_shared_target() {
#[derive(Component)]
#[relationship(relationship_target = Below)]
struct Above(Entity);
#[derive(Component)]
#[relationship_target(relationship = Above)]
struct Below(Entity);
let mut world = World::new();
let a = world.spawn_empty().id();
let b = world.spawn_empty().id();
let c = world.spawn_empty().id();
world.entity_mut(a).insert(Above(c));
world.entity_mut(b).insert(Above(c));
}
#[test]
fn one_to_one_relationship_reinsert() {
#[derive(Component)]
#[relationship(relationship_target = Below)]
struct Above(Entity);
#[derive(Component)]
#[relationship_target(relationship = Above)]
struct Below(Entity);
let mut world = World::new();
let a = world.spawn_empty().id();
let b = world.spawn_empty().id();
world.entity_mut(a).insert(Above(b));
world.entity_mut(a).insert(Above(b));
}
}

268
vendor/bevy_ecs/src/removal_detection.rs vendored Normal file
View File

@@ -0,0 +1,268 @@
//! Alerting events when a component is removed from an entity.
use crate::{
component::{Component, ComponentId, ComponentIdFor, Tick},
entity::Entity,
event::{Event, EventCursor, EventId, EventIterator, EventIteratorWithId, Events},
prelude::Local,
storage::SparseSet,
system::{ReadOnlySystemParam, SystemMeta, SystemParam},
world::{unsafe_world_cell::UnsafeWorldCell, World},
};
use derive_more::derive::Into;
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::Reflect;
use core::{
fmt::Debug,
iter,
marker::PhantomData,
ops::{Deref, DerefMut},
option,
};
/// Wrapper around [`Entity`] for [`RemovedComponents`].
/// Internally, `RemovedComponents` uses these as an `Events<RemovedComponentEntity>`.
#[derive(Event, Debug, Clone, Into)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "bevy_reflect", reflect(Debug, Clone))]
pub struct RemovedComponentEntity(Entity);
/// Wrapper around a [`EventCursor<RemovedComponentEntity>`] so that we
/// can differentiate events between components.
#[derive(Debug)]
pub struct RemovedComponentReader<T>
where
T: Component,
{
reader: EventCursor<RemovedComponentEntity>,
marker: PhantomData<T>,
}
impl<T: Component> Default for RemovedComponentReader<T> {
fn default() -> Self {
Self {
reader: Default::default(),
marker: PhantomData,
}
}
}
impl<T: Component> Deref for RemovedComponentReader<T> {
type Target = EventCursor<RemovedComponentEntity>;
fn deref(&self) -> &Self::Target {
&self.reader
}
}
impl<T: Component> DerefMut for RemovedComponentReader<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.reader
}
}
/// Stores the [`RemovedComponents`] event buffers for all types of component in a given [`World`].
#[derive(Default, Debug)]
pub struct RemovedComponentEvents {
event_sets: SparseSet<ComponentId, Events<RemovedComponentEntity>>,
}
impl RemovedComponentEvents {
/// Creates an empty storage buffer for component removal events.
pub fn new() -> Self {
Self::default()
}
/// For each type of component, swaps the event buffers and clears the oldest event buffer.
/// In general, this should be called once per frame/update.
pub fn update(&mut self) {
for (_component_id, events) in self.event_sets.iter_mut() {
events.update();
}
}
/// Returns an iterator over components and their entity events.
pub fn iter(&self) -> impl Iterator<Item = (&ComponentId, &Events<RemovedComponentEntity>)> {
self.event_sets.iter()
}
/// Gets the event storage for a given component.
pub fn get(
&self,
component_id: impl Into<ComponentId>,
) -> Option<&Events<RemovedComponentEntity>> {
self.event_sets.get(component_id.into())
}
/// Sends a removal event for the specified component.
pub fn send(&mut self, component_id: impl Into<ComponentId>, entity: Entity) {
self.event_sets
.get_or_insert_with(component_id.into(), Default::default)
.send(RemovedComponentEntity(entity));
}
}
/// A [`SystemParam`] that yields entities that had their `T` [`Component`]
/// removed or have been despawned with it.
///
/// This acts effectively the same as an [`EventReader`](crate::event::EventReader).
///
/// Note that this does not allow you to see which data existed before removal.
/// If you need this, you will need to track the component data value on your own,
/// using a regularly scheduled system that requests `Query<(Entity, &T), Changed<T>>`
/// and stores the data somewhere safe to later cross-reference.
///
/// If you are using `bevy_ecs` as a standalone crate,
/// note that the `RemovedComponents` list will not be automatically cleared for you,
/// and will need to be manually flushed using [`World::clear_trackers`](World::clear_trackers).
///
/// For users of `bevy` and `bevy_app`, [`World::clear_trackers`](World::clear_trackers) is
/// automatically called by `bevy_app::App::update` and `bevy_app::SubApp::update`.
/// For the main world, this is delayed until after all `SubApp`s have run.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// # use bevy_ecs::component::Component;
/// # use bevy_ecs::system::IntoSystem;
/// # use bevy_ecs::removal_detection::RemovedComponents;
/// #
/// # #[derive(Component)]
/// # struct MyComponent;
/// fn react_on_removal(mut removed: RemovedComponents<MyComponent>) {
/// removed.read().for_each(|removed_entity| println!("{}", removed_entity));
/// }
/// # bevy_ecs::system::assert_is_system(react_on_removal);
/// ```
#[derive(SystemParam)]
pub struct RemovedComponents<'w, 's, T: Component> {
component_id: ComponentIdFor<'s, T>,
reader: Local<'s, RemovedComponentReader<T>>,
event_sets: &'w RemovedComponentEvents,
}
/// Iterator over entities that had a specific component removed.
///
/// See [`RemovedComponents`].
pub type RemovedIter<'a> = iter::Map<
iter::Flatten<option::IntoIter<iter::Cloned<EventIterator<'a, RemovedComponentEntity>>>>,
fn(RemovedComponentEntity) -> Entity,
>;
/// Iterator over entities that had a specific component removed.
///
/// See [`RemovedComponents`].
pub type RemovedIterWithId<'a> = iter::Map<
iter::Flatten<option::IntoIter<EventIteratorWithId<'a, RemovedComponentEntity>>>,
fn(
(&RemovedComponentEntity, EventId<RemovedComponentEntity>),
) -> (Entity, EventId<RemovedComponentEntity>),
>;
fn map_id_events(
(entity, id): (&RemovedComponentEntity, EventId<RemovedComponentEntity>),
) -> (Entity, EventId<RemovedComponentEntity>) {
(entity.clone().into(), id)
}
// For all practical purposes, the api surface of `RemovedComponents<T>`
// should be similar to `EventReader<T>` to reduce confusion.
impl<'w, 's, T: Component> RemovedComponents<'w, 's, T> {
/// Fetch underlying [`EventCursor`].
pub fn reader(&self) -> &EventCursor<RemovedComponentEntity> {
&self.reader
}
/// Fetch underlying [`EventCursor`] mutably.
pub fn reader_mut(&mut self) -> &mut EventCursor<RemovedComponentEntity> {
&mut self.reader
}
/// Fetch underlying [`Events`].
pub fn events(&self) -> Option<&Events<RemovedComponentEntity>> {
self.event_sets.get(self.component_id.get())
}
/// Destructures to get a mutable reference to the `EventCursor`
/// and a reference to `Events`.
///
/// This is necessary since Rust can't detect destructuring through methods and most
/// usecases of the reader uses the `Events` as well.
pub fn reader_mut_with_events(
&mut self,
) -> Option<(
&mut RemovedComponentReader<T>,
&Events<RemovedComponentEntity>,
)> {
self.event_sets
.get(self.component_id.get())
.map(|events| (&mut *self.reader, events))
}
/// Iterates over the events this [`RemovedComponents`] has not seen yet. This updates the
/// [`RemovedComponents`]'s event counter, which means subsequent event reads will not include events
/// that happened before now.
pub fn read(&mut self) -> RemovedIter<'_> {
self.reader_mut_with_events()
.map(|(reader, events)| reader.read(events).cloned())
.into_iter()
.flatten()
.map(RemovedComponentEntity::into)
}
/// Like [`read`](Self::read), except also returning the [`EventId`] of the events.
pub fn read_with_id(&mut self) -> RemovedIterWithId<'_> {
self.reader_mut_with_events()
.map(|(reader, events)| reader.read_with_id(events))
.into_iter()
.flatten()
.map(map_id_events)
}
/// Determines the number of removal events available to be read from this [`RemovedComponents`] without consuming any.
pub fn len(&self) -> usize {
self.events()
.map(|events| self.reader.len(events))
.unwrap_or(0)
}
/// Returns `true` if there are no events available to read.
pub fn is_empty(&self) -> bool {
self.events()
.is_none_or(|events| self.reader.is_empty(events))
}
/// Consumes all available events.
///
/// This means these events will not appear in calls to [`RemovedComponents::read()`] or
/// [`RemovedComponents::read_with_id()`] and [`RemovedComponents::is_empty()`] will return `true`.
pub fn clear(&mut self) {
if let Some((reader, events)) = self.reader_mut_with_events() {
reader.clear(events);
}
}
}
// SAFETY: Only reads World removed component events
unsafe impl<'a> ReadOnlySystemParam for &'a RemovedComponentEvents {}
// SAFETY: no component value access.
unsafe impl<'a> SystemParam for &'a RemovedComponentEvents {
type State = ();
type Item<'w, 's> = &'w RemovedComponentEvents;
fn init_state(_world: &mut World, _system_meta: &mut SystemMeta) -> Self::State {}
#[inline]
unsafe fn get_param<'w, 's>(
_state: &'s mut Self::State,
_system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
_change_tick: Tick,
) -> Self::Item<'w, 's> {
world.removed_components()
}
}

75
vendor/bevy_ecs/src/resource.rs vendored Normal file
View File

@@ -0,0 +1,75 @@
//! Resources are unique, singleton-like data types that can be accessed from systems and stored in the [`World`](crate::world::World).
// The derive macro for the `Resource` trait
pub use bevy_ecs_macros::Resource;
/// A type that can be inserted into a [`World`] as a singleton.
///
/// You can access resource data in systems using the [`Res`] and [`ResMut`] system parameters
///
/// Only one resource of each type can be stored in a [`World`] at any given time.
///
/// # Examples
///
/// ```
/// # let mut world = World::default();
/// # let mut schedule = Schedule::default();
/// # use bevy_ecs::prelude::*;
/// #[derive(Resource)]
/// struct MyResource { value: u32 }
///
/// world.insert_resource(MyResource { value: 42 });
///
/// fn read_resource_system(resource: Res<MyResource>) {
/// assert_eq!(resource.value, 42);
/// }
///
/// fn write_resource_system(mut resource: ResMut<MyResource>) {
/// assert_eq!(resource.value, 42);
/// resource.value = 0;
/// assert_eq!(resource.value, 0);
/// }
/// # schedule.add_systems((read_resource_system, write_resource_system).chain());
/// # schedule.run(&mut world);
/// ```
///
/// # `!Sync` Resources
/// A `!Sync` type cannot implement `Resource`. However, it is possible to wrap a `Send` but not `Sync`
/// type in [`SyncCell`] or the currently unstable [`Exclusive`] to make it `Sync`. This forces only
/// having mutable access (`&mut T` only, never `&T`), but makes it safe to reference across multiple
/// threads.
///
/// This will fail to compile since `RefCell` is `!Sync`.
/// ```compile_fail
/// # use std::cell::RefCell;
/// # use bevy_ecs::resource::Resource;
///
/// #[derive(Resource)]
/// struct NotSync {
/// counter: RefCell<usize>,
/// }
/// ```
///
/// This will compile since the `RefCell` is wrapped with `SyncCell`.
/// ```
/// # use std::cell::RefCell;
/// # use bevy_ecs::resource::Resource;
/// use bevy_utils::synccell::SyncCell;
///
/// #[derive(Resource)]
/// struct ActuallySync {
/// counter: SyncCell<RefCell<usize>>,
/// }
/// ```
///
/// [`Exclusive`]: https://doc.rust-lang.org/nightly/std/sync/struct.Exclusive.html
/// [`World`]: crate::world::World
/// [`Res`]: crate::system::Res
/// [`ResMut`]: crate::system::ResMut
/// [`SyncCell`]: bevy_utils::synccell::SyncCell
#[diagnostic::on_unimplemented(
message = "`{Self}` is not a `Resource`",
label = "invalid `Resource`",
note = "consider annotating `{Self}` with `#[derive(Resource)]`"
)]
pub trait Resource: Send + Sync + 'static {}

View File

@@ -0,0 +1,252 @@
use alloc::{boxed::Box, collections::BTreeSet, vec::Vec};
use bevy_platform::collections::HashMap;
use crate::system::IntoSystem;
use crate::world::World;
use super::{
is_apply_deferred, ApplyDeferred, DiGraph, Direction, NodeId, ReportCycles, ScheduleBuildError,
ScheduleBuildPass, ScheduleGraph, SystemNode,
};
/// A [`ScheduleBuildPass`] that inserts [`ApplyDeferred`] systems into the schedule graph
/// when there are [`Deferred`](crate::prelude::Deferred)
/// in one system and there are ordering dependencies on that system. [`Commands`](crate::system::Commands) is one
/// such deferred buffer.
///
/// This pass is typically automatically added to the schedule. You can disable this by setting
/// [`ScheduleBuildSettings::auto_insert_apply_deferred`](crate::schedule::ScheduleBuildSettings::auto_insert_apply_deferred)
/// to `false`. You may want to disable this if you only want to sync deferred params at the end of the schedule,
/// or want to manually insert all your sync points.
#[derive(Debug, Default)]
pub struct AutoInsertApplyDeferredPass {
/// Dependency edges that will **not** automatically insert an instance of `ApplyDeferred` on the edge.
no_sync_edges: BTreeSet<(NodeId, NodeId)>,
auto_sync_node_ids: HashMap<u32, NodeId>,
}
/// If added to a dependency edge, the edge will not be considered for auto sync point insertions.
pub struct IgnoreDeferred;
impl AutoInsertApplyDeferredPass {
/// Returns the `NodeId` of the cached auto sync point. Will create
/// a new one if needed.
fn get_sync_point(&mut self, graph: &mut ScheduleGraph, distance: u32) -> NodeId {
self.auto_sync_node_ids
.get(&distance)
.copied()
.or_else(|| {
let node_id = self.add_auto_sync(graph);
self.auto_sync_node_ids.insert(distance, node_id);
Some(node_id)
})
.unwrap()
}
/// add an [`ApplyDeferred`] system with no config
fn add_auto_sync(&mut self, graph: &mut ScheduleGraph) -> NodeId {
let id = NodeId::System(graph.systems.len());
graph
.systems
.push(SystemNode::new(Box::new(IntoSystem::into_system(
ApplyDeferred,
))));
graph.system_conditions.push(Vec::new());
// ignore ambiguities with auto sync points
// They aren't under user control, so no one should know or care.
graph.ambiguous_with_all.insert(id);
id
}
}
impl ScheduleBuildPass for AutoInsertApplyDeferredPass {
type EdgeOptions = IgnoreDeferred;
fn add_dependency(&mut self, from: NodeId, to: NodeId, options: Option<&Self::EdgeOptions>) {
if options.is_some() {
self.no_sync_edges.insert((from, to));
}
}
fn build(
&mut self,
_world: &mut World,
graph: &mut ScheduleGraph,
dependency_flattened: &mut DiGraph,
) -> Result<(), ScheduleBuildError> {
let mut sync_point_graph = dependency_flattened.clone();
let topo = graph.topsort_graph(dependency_flattened, ReportCycles::Dependency)?;
fn set_has_conditions(graph: &ScheduleGraph, node: NodeId) -> bool {
!graph.set_conditions_at(node).is_empty()
|| graph
.hierarchy()
.graph()
.edges_directed(node, Direction::Incoming)
.any(|(parent, _)| set_has_conditions(graph, parent))
}
fn system_has_conditions(graph: &ScheduleGraph, node: NodeId) -> bool {
assert!(node.is_system());
!graph.system_conditions[node.index()].is_empty()
|| graph
.hierarchy()
.graph()
.edges_directed(node, Direction::Incoming)
.any(|(parent, _)| set_has_conditions(graph, parent))
}
let mut system_has_conditions_cache = HashMap::<usize, bool>::default();
let mut is_valid_explicit_sync_point = |system: NodeId| {
let index = system.index();
is_apply_deferred(graph.systems[index].get().unwrap())
&& !*system_has_conditions_cache
.entry(index)
.or_insert_with(|| system_has_conditions(graph, system))
};
// Calculate the distance for each node.
// The "distance" is the number of sync points between a node and the beginning of the graph.
// Also store if a preceding edge would have added a sync point but was ignored to add it at
// a later edge that is not ignored.
let mut distances_and_pending_sync: HashMap<usize, (u32, bool)> =
HashMap::with_capacity_and_hasher(topo.len(), Default::default());
// Keep track of any explicit sync nodes for a specific distance.
let mut distance_to_explicit_sync_node: HashMap<u32, NodeId> = HashMap::default();
// Determine the distance for every node and collect the explicit sync points.
for node in &topo {
let (node_distance, mut node_needs_sync) = distances_and_pending_sync
.get(&node.index())
.copied()
.unwrap_or_default();
if is_valid_explicit_sync_point(*node) {
// The distance of this sync point does not change anymore as the iteration order
// makes sure that this node is no unvisited target of another node.
// Because of this, the sync point can be stored for this distance to be reused as
// automatically added sync points later.
distance_to_explicit_sync_node.insert(node_distance, *node);
// This node just did a sync, so the only reason to do another sync is if one was
// explicitly scheduled afterwards.
node_needs_sync = false;
} else if !node_needs_sync {
// No previous node has postponed sync points to add so check if the system itself
// has deferred params that require a sync point to apply them.
node_needs_sync = graph.systems[node.index()].get().unwrap().has_deferred();
}
for target in dependency_flattened.neighbors_directed(*node, Direction::Outgoing) {
let (target_distance, target_pending_sync) = distances_and_pending_sync
.entry(target.index())
.or_default();
let mut edge_needs_sync = node_needs_sync;
if node_needs_sync
&& !graph.systems[target.index()].get().unwrap().is_exclusive()
&& self.no_sync_edges.contains(&(*node, target))
{
// The node has deferred params to apply, but this edge is ignoring sync points.
// Mark the target as 'delaying' those commands to a future edge and the current
// edge as not needing a sync point.
*target_pending_sync = true;
edge_needs_sync = false;
}
let mut weight = 0;
if edge_needs_sync || is_valid_explicit_sync_point(target) {
// The target distance grows if a sync point is added between it and the node.
// Also raise the distance if the target is a sync point itself so it then again
// raises the distance of following nodes as that is what the distance is about.
weight = 1;
}
// The target cannot have fewer sync points in front of it than the preceding node.
*target_distance = (node_distance + weight).max(*target_distance);
}
}
// Find any edges which have a different number of sync points between them and make sure
// there is a sync point between them.
for node in &topo {
let (node_distance, _) = distances_and_pending_sync
.get(&node.index())
.copied()
.unwrap_or_default();
for target in dependency_flattened.neighbors_directed(*node, Direction::Outgoing) {
let (target_distance, _) = distances_and_pending_sync
.get(&target.index())
.copied()
.unwrap_or_default();
if node_distance == target_distance {
// These nodes are the same distance, so they don't need an edge between them.
continue;
}
if is_apply_deferred(graph.systems[target.index()].get().unwrap()) {
// We don't need to insert a sync point since ApplyDeferred is a sync point
// already!
continue;
}
let sync_point = distance_to_explicit_sync_node
.get(&target_distance)
.copied()
.unwrap_or_else(|| self.get_sync_point(graph, target_distance));
sync_point_graph.add_edge(*node, sync_point);
sync_point_graph.add_edge(sync_point, target);
// The edge without the sync point is now redundant.
sync_point_graph.remove_edge(*node, target);
}
}
*dependency_flattened = sync_point_graph;
Ok(())
}
fn collapse_set(
&mut self,
set: NodeId,
systems: &[NodeId],
dependency_flattened: &DiGraph,
) -> impl Iterator<Item = (NodeId, NodeId)> {
if systems.is_empty() {
// collapse dependencies for empty sets
for a in dependency_flattened.neighbors_directed(set, Direction::Incoming) {
for b in dependency_flattened.neighbors_directed(set, Direction::Outgoing) {
if self.no_sync_edges.contains(&(a, set))
&& self.no_sync_edges.contains(&(set, b))
{
self.no_sync_edges.insert((a, b));
}
}
}
} else {
for a in dependency_flattened.neighbors_directed(set, Direction::Incoming) {
for &sys in systems {
if self.no_sync_edges.contains(&(a, set)) {
self.no_sync_edges.insert((a, sys));
}
}
}
for b in dependency_flattened.neighbors_directed(set, Direction::Outgoing) {
for &sys in systems {
if self.no_sync_edges.contains(&(set, b)) {
self.no_sync_edges.insert((sys, b));
}
}
}
}
core::iter::empty()
}
}

1411
vendor/bevy_ecs/src/schedule/condition.rs vendored Normal file

File diff suppressed because it is too large Load Diff

647
vendor/bevy_ecs/src/schedule/config.rs vendored Normal file
View File

@@ -0,0 +1,647 @@
use alloc::{boxed::Box, vec, vec::Vec};
use variadics_please::all_tuples;
use crate::{
error::Result,
never::Never,
schedule::{
auto_insert_apply_deferred::IgnoreDeferred,
condition::{BoxedCondition, Condition},
graph::{Ambiguity, Dependency, DependencyKind, GraphInfo},
set::{InternedSystemSet, IntoSystemSet, SystemSet},
Chain,
},
system::{BoxedSystem, InfallibleSystemWrapper, IntoSystem, ScheduleSystem, System},
};
fn new_condition<M>(condition: impl Condition<M>) -> BoxedCondition {
let condition_system = IntoSystem::into_system(condition);
assert!(
condition_system.is_send(),
"Condition `{}` accesses `NonSend` resources. This is not currently supported.",
condition_system.name()
);
Box::new(condition_system)
}
fn ambiguous_with(graph_info: &mut GraphInfo, set: InternedSystemSet) {
match &mut graph_info.ambiguous_with {
detection @ Ambiguity::Check => {
*detection = Ambiguity::IgnoreWithSet(vec![set]);
}
Ambiguity::IgnoreWithSet(ambiguous_with) => {
ambiguous_with.push(set);
}
Ambiguity::IgnoreAll => (),
}
}
/// Stores data to differentiate different schedulable structs.
pub trait Schedulable {
/// Additional data used to configure independent scheduling. Stored in [`ScheduleConfig`].
type Metadata;
/// Additional data used to configure a schedulable group. Stored in [`ScheduleConfigs`].
type GroupMetadata;
/// Initializes a configuration from this node.
fn into_config(self) -> ScheduleConfig<Self>
where
Self: Sized;
}
impl Schedulable for ScheduleSystem {
type Metadata = GraphInfo;
type GroupMetadata = Chain;
fn into_config(self) -> ScheduleConfig<Self> {
let sets = self.default_system_sets().clone();
ScheduleConfig {
node: self,
metadata: GraphInfo {
hierarchy: sets,
..Default::default()
},
conditions: Vec::new(),
}
}
}
impl Schedulable for InternedSystemSet {
type Metadata = GraphInfo;
type GroupMetadata = Chain;
fn into_config(self) -> ScheduleConfig<Self> {
assert!(
self.system_type().is_none(),
"configuring system type sets is not allowed"
);
ScheduleConfig {
node: self,
metadata: GraphInfo::default(),
conditions: Vec::new(),
}
}
}
/// Stores configuration for a single generic node (a system or a system set)
///
/// The configuration includes the node itself, scheduling metadata
/// (hierarchy: in which sets is the node contained,
/// dependencies: before/after which other nodes should this node run)
/// and the run conditions associated with this node.
pub struct ScheduleConfig<T: Schedulable> {
pub(crate) node: T,
pub(crate) metadata: T::Metadata,
pub(crate) conditions: Vec<BoxedCondition>,
}
/// Single or nested configurations for [`Schedulable`]s.
pub enum ScheduleConfigs<T: Schedulable> {
/// Configuration for a single [`Schedulable`].
ScheduleConfig(ScheduleConfig<T>),
/// Configuration for a tuple of nested `Configs` instances.
Configs {
/// Configuration for each element of the tuple.
configs: Vec<ScheduleConfigs<T>>,
/// Run conditions applied to everything in the tuple.
collective_conditions: Vec<BoxedCondition>,
/// Metadata to be applied to all elements in the tuple.
metadata: T::GroupMetadata,
},
}
impl<T: Schedulable<Metadata = GraphInfo, GroupMetadata = Chain>> ScheduleConfigs<T> {
/// Adds a new boxed system set to the systems.
pub fn in_set_inner(&mut self, set: InternedSystemSet) {
match self {
Self::ScheduleConfig(config) => {
config.metadata.hierarchy.push(set);
}
Self::Configs { configs, .. } => {
for config in configs {
config.in_set_inner(set);
}
}
}
}
fn before_inner(&mut self, set: InternedSystemSet) {
match self {
Self::ScheduleConfig(config) => {
config
.metadata
.dependencies
.push(Dependency::new(DependencyKind::Before, set));
}
Self::Configs { configs, .. } => {
for config in configs {
config.before_inner(set);
}
}
}
}
fn after_inner(&mut self, set: InternedSystemSet) {
match self {
Self::ScheduleConfig(config) => {
config
.metadata
.dependencies
.push(Dependency::new(DependencyKind::After, set));
}
Self::Configs { configs, .. } => {
for config in configs {
config.after_inner(set);
}
}
}
}
fn before_ignore_deferred_inner(&mut self, set: InternedSystemSet) {
match self {
Self::ScheduleConfig(config) => {
config
.metadata
.dependencies
.push(Dependency::new(DependencyKind::Before, set).add_config(IgnoreDeferred));
}
Self::Configs { configs, .. } => {
for config in configs {
config.before_ignore_deferred_inner(set.intern());
}
}
}
}
fn after_ignore_deferred_inner(&mut self, set: InternedSystemSet) {
match self {
Self::ScheduleConfig(config) => {
config
.metadata
.dependencies
.push(Dependency::new(DependencyKind::After, set).add_config(IgnoreDeferred));
}
Self::Configs { configs, .. } => {
for config in configs {
config.after_ignore_deferred_inner(set.intern());
}
}
}
}
fn distributive_run_if_inner<M>(&mut self, condition: impl Condition<M> + Clone) {
match self {
Self::ScheduleConfig(config) => {
config.conditions.push(new_condition(condition));
}
Self::Configs { configs, .. } => {
for config in configs {
config.distributive_run_if_inner(condition.clone());
}
}
}
}
fn ambiguous_with_inner(&mut self, set: InternedSystemSet) {
match self {
Self::ScheduleConfig(config) => {
ambiguous_with(&mut config.metadata, set);
}
Self::Configs { configs, .. } => {
for config in configs {
config.ambiguous_with_inner(set);
}
}
}
}
fn ambiguous_with_all_inner(&mut self) {
match self {
Self::ScheduleConfig(config) => {
config.metadata.ambiguous_with = Ambiguity::IgnoreAll;
}
Self::Configs { configs, .. } => {
for config in configs {
config.ambiguous_with_all_inner();
}
}
}
}
/// Adds a new boxed run condition to the systems.
///
/// This is useful if you have a run condition whose concrete type is unknown.
/// Prefer `run_if` for run conditions whose type is known at compile time.
pub fn run_if_dyn(&mut self, condition: BoxedCondition) {
match self {
Self::ScheduleConfig(config) => {
config.conditions.push(condition);
}
Self::Configs {
collective_conditions,
..
} => {
collective_conditions.push(condition);
}
}
}
fn chain_inner(mut self) -> Self {
match &mut self {
Self::ScheduleConfig(_) => { /* no op */ }
Self::Configs { metadata, .. } => {
metadata.set_chained();
}
};
self
}
fn chain_ignore_deferred_inner(mut self) -> Self {
match &mut self {
Self::ScheduleConfig(_) => { /* no op */ }
Self::Configs { metadata, .. } => {
metadata.set_chained_with_config(IgnoreDeferred);
}
}
self
}
}
/// Types that can convert into a [`ScheduleConfigs`].
///
/// This trait is implemented for "systems" (functions whose arguments all implement
/// [`SystemParam`](crate::system::SystemParam)), or tuples thereof.
/// It is a common entry point for system configurations.
///
/// # Usage notes
///
/// This trait should only be used as a bound for trait implementations or as an
/// argument to a function. If system configs need to be returned from a
/// function or stored somewhere, use [`ScheduleConfigs`] instead of this trait.
///
/// # Examples
///
/// ```
/// # use bevy_ecs::{schedule::IntoScheduleConfigs, system::ScheduleSystem};
/// # struct AppMock;
/// # struct Update;
/// # impl AppMock {
/// # pub fn add_systems<M>(
/// # &mut self,
/// # schedule: Update,
/// # systems: impl IntoScheduleConfigs<ScheduleSystem, M>,
/// # ) -> &mut Self { self }
/// # }
/// # let mut app = AppMock;
///
/// fn handle_input() {}
///
/// fn update_camera() {}
/// fn update_character() {}
///
/// app.add_systems(
/// Update,
/// (
/// handle_input,
/// (update_camera, update_character).after(handle_input)
/// )
/// );
/// ```
#[diagnostic::on_unimplemented(
message = "`{Self}` does not describe a valid system configuration",
label = "invalid system configuration"
)]
pub trait IntoScheduleConfigs<T: Schedulable<Metadata = GraphInfo, GroupMetadata = Chain>, Marker>:
Sized
{
/// Convert into a [`ScheduleConfigs`].
fn into_configs(self) -> ScheduleConfigs<T>;
/// Add these systems to the provided `set`.
#[track_caller]
fn in_set(self, set: impl SystemSet) -> ScheduleConfigs<T> {
self.into_configs().in_set(set)
}
/// Runs before all systems in `set`. If `self` has any systems that produce [`Commands`](crate::system::Commands)
/// or other [`Deferred`](crate::system::Deferred) operations, all systems in `set` will see their effect.
///
/// If automatically inserting [`ApplyDeferred`](crate::schedule::ApplyDeferred) like
/// this isn't desired, use [`before_ignore_deferred`](Self::before_ignore_deferred) instead.
///
/// Calling [`.chain`](Self::chain) is often more convenient and ensures that all systems are added to the schedule.
/// Please check the [caveats section of `.after`](Self::after) for details.
fn before<M>(self, set: impl IntoSystemSet<M>) -> ScheduleConfigs<T> {
self.into_configs().before(set)
}
/// Run after all systems in `set`. If `set` has any systems that produce [`Commands`](crate::system::Commands)
/// or other [`Deferred`](crate::system::Deferred) operations, all systems in `self` will see their effect.
///
/// If automatically inserting [`ApplyDeferred`](crate::schedule::ApplyDeferred) like
/// this isn't desired, use [`after_ignore_deferred`](Self::after_ignore_deferred) instead.
///
/// Calling [`.chain`](Self::chain) is often more convenient and ensures that all systems are added to the schedule.
///
/// # Caveats
///
/// If you configure two [`System`]s like `(GameSystem::A).after(GameSystem::B)` or `(GameSystem::A).before(GameSystem::B)`, the `GameSystem::B` will not be automatically scheduled.
///
/// This means that the system `GameSystem::A` and the system or systems in `GameSystem::B` will run independently of each other if `GameSystem::B` was never explicitly scheduled with [`configure_sets`]
/// If that is the case, `.after`/`.before` will not provide the desired behavior
/// and the systems can run in parallel or in any order determined by the scheduler.
/// Only use `after(GameSystem::B)` and `before(GameSystem::B)` when you know that `B` has already been scheduled for you,
/// e.g. when it was provided by Bevy or a third-party dependency,
/// or you manually scheduled it somewhere else in your app.
///
/// Another caveat is that if `GameSystem::B` is placed in a different schedule than `GameSystem::A`,
/// any ordering calls between them—whether using `.before`, `.after`, or `.chain`—will be silently ignored.
///
/// [`configure_sets`]: https://docs.rs/bevy/latest/bevy/app/struct.App.html#method.configure_sets
fn after<M>(self, set: impl IntoSystemSet<M>) -> ScheduleConfigs<T> {
self.into_configs().after(set)
}
/// Run before all systems in `set`.
///
/// Unlike [`before`](Self::before), this will not cause the systems in
/// `set` to wait for the deferred effects of `self` to be applied.
fn before_ignore_deferred<M>(self, set: impl IntoSystemSet<M>) -> ScheduleConfigs<T> {
self.into_configs().before_ignore_deferred(set)
}
/// Run after all systems in `set`.
///
/// Unlike [`after`](Self::after), this will not wait for the deferred
/// effects of systems in `set` to be applied.
fn after_ignore_deferred<M>(self, set: impl IntoSystemSet<M>) -> ScheduleConfigs<T> {
self.into_configs().after_ignore_deferred(set)
}
/// Add a run condition to each contained system.
///
/// Each system will receive its own clone of the [`Condition`] and will only run
/// if the `Condition` is true.
///
/// Each individual condition will be evaluated at most once (per schedule run),
/// right before the corresponding system prepares to run.
///
/// This is equivalent to calling [`run_if`](IntoScheduleConfigs::run_if) on each individual
/// system, as shown below:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # let mut schedule = Schedule::default();
/// # fn a() {}
/// # fn b() {}
/// # fn condition() -> bool { true }
/// schedule.add_systems((a, b).distributive_run_if(condition));
/// schedule.add_systems((a.run_if(condition), b.run_if(condition)));
/// ```
///
/// # Note
///
/// Because the conditions are evaluated separately for each system, there is no guarantee
/// that all evaluations in a single schedule run will yield the same result. If another
/// system is run inbetween two evaluations it could cause the result of the condition to change.
///
/// Use [`run_if`](ScheduleConfigs::run_if) on a [`SystemSet`] if you want to make sure
/// that either all or none of the systems are run, or you don't want to evaluate the run
/// condition for each contained system separately.
fn distributive_run_if<M>(self, condition: impl Condition<M> + Clone) -> ScheduleConfigs<T> {
self.into_configs().distributive_run_if(condition)
}
/// Run the systems only if the [`Condition`] is `true`.
///
/// The `Condition` will be evaluated at most once (per schedule run),
/// the first time a system in this set prepares to run.
///
/// If this set contains more than one system, calling `run_if` is equivalent to adding each
/// system to a common set and configuring the run condition on that set, as shown below:
///
/// # Examples
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # let mut schedule = Schedule::default();
/// # fn a() {}
/// # fn b() {}
/// # fn condition() -> bool { true }
/// # #[derive(SystemSet, Debug, Eq, PartialEq, Hash, Clone, Copy)]
/// # struct C;
/// schedule.add_systems((a, b).run_if(condition));
/// schedule.add_systems((a, b).in_set(C)).configure_sets(C.run_if(condition));
/// ```
///
/// # Note
///
/// Because the condition will only be evaluated once, there is no guarantee that the condition
/// is upheld after the first system has run. You need to make sure that no other systems that
/// could invalidate the condition are scheduled inbetween the first and last run system.
///
/// Use [`distributive_run_if`](IntoScheduleConfigs::distributive_run_if) if you want the
/// condition to be evaluated for each individual system, right before one is run.
fn run_if<M>(self, condition: impl Condition<M>) -> ScheduleConfigs<T> {
self.into_configs().run_if(condition)
}
/// Suppress warnings and errors that would result from these systems having ambiguities
/// (conflicting access but indeterminate order) with systems in `set`.
fn ambiguous_with<M>(self, set: impl IntoSystemSet<M>) -> ScheduleConfigs<T> {
self.into_configs().ambiguous_with(set)
}
/// Suppress warnings and errors that would result from these systems having ambiguities
/// (conflicting access but indeterminate order) with any other system.
fn ambiguous_with_all(self) -> ScheduleConfigs<T> {
self.into_configs().ambiguous_with_all()
}
/// Treat this collection as a sequence of systems.
///
/// Ordering constraints will be applied between the successive elements.
///
/// If the preceding node on an edge has deferred parameters, an [`ApplyDeferred`](crate::schedule::ApplyDeferred)
/// will be inserted on the edge. If this behavior is not desired consider using
/// [`chain_ignore_deferred`](Self::chain_ignore_deferred) instead.
fn chain(self) -> ScheduleConfigs<T> {
self.into_configs().chain()
}
/// Treat this collection as a sequence of systems.
///
/// Ordering constraints will be applied between the successive elements.
///
/// Unlike [`chain`](Self::chain) this will **not** add [`ApplyDeferred`](crate::schedule::ApplyDeferred) on the edges.
fn chain_ignore_deferred(self) -> ScheduleConfigs<T> {
self.into_configs().chain_ignore_deferred()
}
}
impl<T: Schedulable<Metadata = GraphInfo, GroupMetadata = Chain>> IntoScheduleConfigs<T, ()>
for ScheduleConfigs<T>
{
fn into_configs(self) -> Self {
self
}
#[track_caller]
fn in_set(mut self, set: impl SystemSet) -> Self {
assert!(
set.system_type().is_none(),
"adding arbitrary systems to a system type set is not allowed"
);
self.in_set_inner(set.intern());
self
}
fn before<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
let set = set.into_system_set();
self.before_inner(set.intern());
self
}
fn after<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
let set = set.into_system_set();
self.after_inner(set.intern());
self
}
fn before_ignore_deferred<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
let set = set.into_system_set();
self.before_ignore_deferred_inner(set.intern());
self
}
fn after_ignore_deferred<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
let set = set.into_system_set();
self.after_ignore_deferred_inner(set.intern());
self
}
fn distributive_run_if<M>(
mut self,
condition: impl Condition<M> + Clone,
) -> ScheduleConfigs<T> {
self.distributive_run_if_inner(condition);
self
}
fn run_if<M>(mut self, condition: impl Condition<M>) -> ScheduleConfigs<T> {
self.run_if_dyn(new_condition(condition));
self
}
fn ambiguous_with<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
let set = set.into_system_set();
self.ambiguous_with_inner(set.intern());
self
}
fn ambiguous_with_all(mut self) -> Self {
self.ambiguous_with_all_inner();
self
}
fn chain(self) -> Self {
self.chain_inner()
}
fn chain_ignore_deferred(self) -> Self {
self.chain_ignore_deferred_inner()
}
}
/// Marker component to allow for conflicting implementations of [`IntoScheduleConfigs`]
#[doc(hidden)]
pub struct Infallible;
impl<F, Marker> IntoScheduleConfigs<ScheduleSystem, (Infallible, Marker)> for F
where
F: IntoSystem<(), (), Marker>,
{
fn into_configs(self) -> ScheduleConfigs<ScheduleSystem> {
let wrapper = InfallibleSystemWrapper::new(IntoSystem::into_system(self));
ScheduleConfigs::ScheduleConfig(ScheduleSystem::into_config(Box::new(wrapper)))
}
}
impl<F, Marker> IntoScheduleConfigs<ScheduleSystem, (Never, Marker)> for F
where
F: IntoSystem<(), Never, Marker>,
{
fn into_configs(self) -> ScheduleConfigs<ScheduleSystem> {
let wrapper = InfallibleSystemWrapper::new(IntoSystem::into_system(self));
ScheduleConfigs::ScheduleConfig(ScheduleSystem::into_config(Box::new(wrapper)))
}
}
/// Marker component to allow for conflicting implementations of [`IntoScheduleConfigs`]
#[doc(hidden)]
pub struct Fallible;
impl<F, Marker> IntoScheduleConfigs<ScheduleSystem, (Fallible, Marker)> for F
where
F: IntoSystem<(), Result, Marker>,
{
fn into_configs(self) -> ScheduleConfigs<ScheduleSystem> {
let boxed_system = Box::new(IntoSystem::into_system(self));
ScheduleConfigs::ScheduleConfig(ScheduleSystem::into_config(boxed_system))
}
}
impl IntoScheduleConfigs<ScheduleSystem, ()> for BoxedSystem<(), Result> {
fn into_configs(self) -> ScheduleConfigs<ScheduleSystem> {
ScheduleConfigs::ScheduleConfig(ScheduleSystem::into_config(self))
}
}
impl<S: SystemSet> IntoScheduleConfigs<InternedSystemSet, ()> for S {
fn into_configs(self) -> ScheduleConfigs<InternedSystemSet> {
ScheduleConfigs::ScheduleConfig(InternedSystemSet::into_config(self.intern()))
}
}
#[doc(hidden)]
pub struct ScheduleConfigTupleMarker;
macro_rules! impl_node_type_collection {
($(#[$meta:meta])* $(($param: ident, $sys: ident)),*) => {
$(#[$meta])*
impl<$($param, $sys),*, T: Schedulable<Metadata = GraphInfo, GroupMetadata = Chain>> IntoScheduleConfigs<T, (ScheduleConfigTupleMarker, $($param,)*)> for ($($sys,)*)
where
$($sys: IntoScheduleConfigs<T, $param>),*
{
#[expect(
clippy::allow_attributes,
reason = "We are inside a macro, and as such, `non_snake_case` is not guaranteed to apply."
)]
#[allow(
non_snake_case,
reason = "Variable names are provided by the macro caller, not by us."
)]
fn into_configs(self) -> ScheduleConfigs<T> {
let ($($sys,)*) = self;
ScheduleConfigs::Configs {
metadata: Default::default(),
configs: vec![$($sys.into_configs(),)*],
collective_conditions: Vec::new(),
}
}
}
}
}
all_tuples!(
#[doc(fake_variadic)]
impl_node_type_collection,
1,
20,
P,
S
);

View File

@@ -0,0 +1,572 @@
#[cfg(feature = "std")]
mod multi_threaded;
mod simple;
mod single_threaded;
use alloc::{borrow::Cow, vec, vec::Vec};
use core::any::TypeId;
pub use self::{simple::SimpleExecutor, single_threaded::SingleThreadedExecutor};
#[cfg(feature = "std")]
pub use self::multi_threaded::{MainThreadExecutor, MultiThreadedExecutor};
use fixedbitset::FixedBitSet;
use crate::{
archetype::ArchetypeComponentId,
component::{ComponentId, Tick},
error::{BevyError, ErrorContext, Result},
prelude::{IntoSystemSet, SystemSet},
query::Access,
schedule::{BoxedCondition, InternedSystemSet, NodeId, SystemTypeSet},
system::{ScheduleSystem, System, SystemIn, SystemParamValidationError},
world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, World},
};
/// Types that can run a [`SystemSchedule`] on a [`World`].
pub(super) trait SystemExecutor: Send + Sync {
fn kind(&self) -> ExecutorKind;
fn init(&mut self, schedule: &SystemSchedule);
fn run(
&mut self,
schedule: &mut SystemSchedule,
world: &mut World,
skip_systems: Option<&FixedBitSet>,
error_handler: fn(BevyError, ErrorContext),
);
fn set_apply_final_deferred(&mut self, value: bool);
}
/// Specifies how a [`Schedule`](super::Schedule) will be run.
///
/// The default depends on the target platform:
/// - [`SingleThreaded`](ExecutorKind::SingleThreaded) on Wasm.
/// - [`MultiThreaded`](ExecutorKind::MultiThreaded) everywhere else.
#[derive(PartialEq, Eq, Default, Debug, Copy, Clone)]
pub enum ExecutorKind {
/// Runs the schedule using a single thread.
///
/// Useful if you're dealing with a single-threaded environment, saving your threads for
/// other things, or just trying minimize overhead.
#[cfg_attr(any(target_arch = "wasm32", not(feature = "multi_threaded")), default)]
SingleThreaded,
/// Like [`SingleThreaded`](ExecutorKind::SingleThreaded) but calls [`apply_deferred`](crate::system::System::apply_deferred)
/// immediately after running each system.
Simple,
/// Runs the schedule using a thread pool. Non-conflicting systems can run in parallel.
#[cfg(feature = "std")]
#[cfg_attr(all(not(target_arch = "wasm32"), feature = "multi_threaded"), default)]
MultiThreaded,
}
/// Holds systems and conditions of a [`Schedule`](super::Schedule) sorted in topological order
/// (along with dependency information for `multi_threaded` execution).
///
/// Since the arrays are sorted in the same order, elements are referenced by their index.
/// [`FixedBitSet`] is used as a smaller, more efficient substitute of `HashSet<usize>`.
#[derive(Default)]
pub struct SystemSchedule {
/// List of system node ids.
pub(super) system_ids: Vec<NodeId>,
/// Indexed by system node id.
pub(super) systems: Vec<ScheduleSystem>,
/// Indexed by system node id.
pub(super) system_conditions: Vec<Vec<BoxedCondition>>,
/// Indexed by system node id.
/// Number of systems that the system immediately depends on.
#[cfg_attr(
not(feature = "std"),
expect(dead_code, reason = "currently only used with the std feature")
)]
pub(super) system_dependencies: Vec<usize>,
/// Indexed by system node id.
/// List of systems that immediately depend on the system.
#[cfg_attr(
not(feature = "std"),
expect(dead_code, reason = "currently only used with the std feature")
)]
pub(super) system_dependents: Vec<Vec<usize>>,
/// Indexed by system node id.
/// List of sets containing the system that have conditions
pub(super) sets_with_conditions_of_systems: Vec<FixedBitSet>,
/// List of system set node ids.
pub(super) set_ids: Vec<NodeId>,
/// Indexed by system set node id.
pub(super) set_conditions: Vec<Vec<BoxedCondition>>,
/// Indexed by system set node id.
/// List of systems that are in sets that have conditions.
///
/// If a set doesn't run because of its conditions, this is used to skip all systems in it.
pub(super) systems_in_sets_with_conditions: Vec<FixedBitSet>,
}
impl SystemSchedule {
/// Creates an empty [`SystemSchedule`].
pub const fn new() -> Self {
Self {
systems: Vec::new(),
system_conditions: Vec::new(),
set_conditions: Vec::new(),
system_ids: Vec::new(),
set_ids: Vec::new(),
system_dependencies: Vec::new(),
system_dependents: Vec::new(),
sets_with_conditions_of_systems: Vec::new(),
systems_in_sets_with_conditions: Vec::new(),
}
}
}
/// See [`ApplyDeferred`].
#[deprecated(
since = "0.16.0",
note = "Use `ApplyDeferred` instead. This was previously a function but is now a marker struct System."
)]
#[expect(
non_upper_case_globals,
reason = "This item is deprecated; as such, its previous name needs to stay."
)]
pub const apply_deferred: ApplyDeferred = ApplyDeferred;
/// A special [`System`] that instructs the executor to call
/// [`System::apply_deferred`] on the systems that have run but not applied
/// their [`Deferred`] system parameters (like [`Commands`]) or other system buffers.
///
/// ## Scheduling
///
/// `ApplyDeferred` systems are scheduled *by default*
/// - later in the same schedule run (for example, if a system with `Commands` param
/// is scheduled in `Update`, all the changes will be visible in `PostUpdate`)
/// - between systems with dependencies if the dependency [has deferred buffers]
/// (if system `bar` directly or indirectly depends on `foo`, and `foo` uses
/// `Commands` param, changes to the world in `foo` will be visible in `bar`)
///
/// ## Notes
/// - This system (currently) does nothing if it's called manually or wrapped
/// inside a [`PipeSystem`].
/// - Modifying a [`Schedule`] may change the order buffers are applied.
///
/// [`System::apply_deferred`]: crate::system::System::apply_deferred
/// [`Deferred`]: crate::system::Deferred
/// [`Commands`]: crate::prelude::Commands
/// [has deferred buffers]: crate::system::System::has_deferred
/// [`PipeSystem`]: crate::system::PipeSystem
/// [`Schedule`]: super::Schedule
#[doc(alias = "apply_system_buffers")]
pub struct ApplyDeferred;
/// Returns `true` if the [`System`] is an instance of [`ApplyDeferred`].
pub(super) fn is_apply_deferred(system: &ScheduleSystem) -> bool {
system.type_id() == TypeId::of::<ApplyDeferred>()
}
impl System for ApplyDeferred {
type In = ();
type Out = Result<()>;
fn name(&self) -> Cow<'static, str> {
Cow::Borrowed("bevy_ecs::apply_deferred")
}
fn component_access(&self) -> &Access<ComponentId> {
// This system accesses no components.
const { &Access::new() }
}
fn archetype_component_access(&self) -> &Access<ArchetypeComponentId> {
// This system accesses no archetype components.
const { &Access::new() }
}
fn is_send(&self) -> bool {
// Although this system itself does nothing on its own, the system
// executor uses it to apply deferred commands. Commands must be allowed
// to access non-send resources, so this system must be non-send for
// scheduling purposes.
false
}
fn is_exclusive(&self) -> bool {
// This system is labeled exclusive because it is used by the system
// executor to find places where deferred commands should be applied,
// and commands can only be applied with exclusive access to the world.
true
}
fn has_deferred(&self) -> bool {
// This system itself doesn't have any commands to apply, but when it
// is pulled from the schedule to be ran, the executor will apply
// deferred commands from other systems.
false
}
unsafe fn run_unsafe(
&mut self,
_input: SystemIn<'_, Self>,
_world: UnsafeWorldCell,
) -> Self::Out {
// This system does nothing on its own. The executor will apply deferred
// commands from other systems instead of running this system.
Ok(())
}
fn run(&mut self, _input: SystemIn<'_, Self>, _world: &mut World) -> Self::Out {
// This system does nothing on its own. The executor will apply deferred
// commands from other systems instead of running this system.
Ok(())
}
fn apply_deferred(&mut self, _world: &mut World) {}
fn queue_deferred(&mut self, _world: DeferredWorld) {}
unsafe fn validate_param_unsafe(
&mut self,
_world: UnsafeWorldCell,
) -> Result<(), SystemParamValidationError> {
// This system is always valid to run because it doesn't do anything,
// and only used as a marker for the executor.
Ok(())
}
fn initialize(&mut self, _world: &mut World) {}
fn update_archetype_component_access(&mut self, _world: UnsafeWorldCell) {}
fn check_change_tick(&mut self, _change_tick: Tick) {}
fn default_system_sets(&self) -> Vec<InternedSystemSet> {
vec![SystemTypeSet::<Self>::new().intern()]
}
fn get_last_run(&self) -> Tick {
// This system is never run, so it has no last run tick.
Tick::MAX
}
fn set_last_run(&mut self, _last_run: Tick) {}
}
impl IntoSystemSet<()> for ApplyDeferred {
type Set = SystemTypeSet<Self>;
fn into_system_set(self) -> Self::Set {
SystemTypeSet::<Self>::new()
}
}
/// These functions hide the bottom of the callstack from `RUST_BACKTRACE=1` (assuming the default panic handler is used).
///
/// The full callstack will still be visible with `RUST_BACKTRACE=full`.
/// They are specialized for `System::run` & co instead of being generic over closures because this avoids an
/// extra frame in the backtrace.
///
/// This is reliant on undocumented behavior in Rust's default panic handler, which checks the call stack for symbols
/// containing the string `__rust_begin_short_backtrace` in their mangled name.
mod __rust_begin_short_backtrace {
use core::hint::black_box;
use crate::{
error::Result,
system::{ReadOnlySystem, ScheduleSystem},
world::{unsafe_world_cell::UnsafeWorldCell, World},
};
/// # Safety
/// See `System::run_unsafe`.
#[inline(never)]
pub(super) unsafe fn run_unsafe(system: &mut ScheduleSystem, world: UnsafeWorldCell) -> Result {
let result = system.run_unsafe((), world);
black_box(());
result
}
/// # Safety
/// See `ReadOnlySystem::run_unsafe`.
#[cfg_attr(
not(feature = "std"),
expect(dead_code, reason = "currently only used with the std feature")
)]
#[inline(never)]
pub(super) unsafe fn readonly_run_unsafe<O: 'static>(
system: &mut dyn ReadOnlySystem<In = (), Out = O>,
world: UnsafeWorldCell,
) -> O {
black_box(system.run_unsafe((), world))
}
#[inline(never)]
pub(super) fn run(system: &mut ScheduleSystem, world: &mut World) -> Result {
let result = system.run((), world);
black_box(());
result
}
#[inline(never)]
pub(super) fn readonly_run<O: 'static>(
system: &mut dyn ReadOnlySystem<In = (), Out = O>,
world: &mut World,
) -> O {
black_box(system.run((), world))
}
}
#[cfg(test)]
mod tests {
use crate::{
prelude::{Component, In, IntoSystem, Resource, Schedule},
schedule::ExecutorKind,
system::{Populated, Res, ResMut, Single},
world::World,
};
#[derive(Component)]
struct TestComponent;
const EXECUTORS: [ExecutorKind; 3] = [
ExecutorKind::Simple,
ExecutorKind::SingleThreaded,
ExecutorKind::MultiThreaded,
];
#[derive(Resource, Default)]
struct TestState {
populated_ran: bool,
single_ran: bool,
}
#[derive(Resource, Default)]
struct Counter(u8);
fn set_single_state(mut _single: Single<&TestComponent>, mut state: ResMut<TestState>) {
state.single_ran = true;
}
fn set_populated_state(
mut _populated: Populated<&TestComponent>,
mut state: ResMut<TestState>,
) {
state.populated_ran = true;
}
#[test]
#[expect(clippy::print_stdout, reason = "std and println are allowed in tests")]
fn single_and_populated_skipped_and_run() {
for executor in EXECUTORS {
std::println!("Testing executor: {:?}", executor);
let mut world = World::new();
world.init_resource::<TestState>();
let mut schedule = Schedule::default();
schedule.set_executor_kind(executor);
schedule.add_systems((set_single_state, set_populated_state));
schedule.run(&mut world);
let state = world.get_resource::<TestState>().unwrap();
assert!(!state.single_ran);
assert!(!state.populated_ran);
world.spawn(TestComponent);
schedule.run(&mut world);
let state = world.get_resource::<TestState>().unwrap();
assert!(state.single_ran);
assert!(state.populated_ran);
}
}
fn look_for_missing_resource(_res: Res<TestState>) {}
#[test]
#[should_panic]
fn missing_resource_panics_simple() {
let mut world = World::new();
let mut schedule = Schedule::default();
schedule.set_executor_kind(ExecutorKind::Simple);
schedule.add_systems(look_for_missing_resource);
schedule.run(&mut world);
}
#[test]
#[should_panic]
fn missing_resource_panics_single_threaded() {
let mut world = World::new();
let mut schedule = Schedule::default();
schedule.set_executor_kind(ExecutorKind::SingleThreaded);
schedule.add_systems(look_for_missing_resource);
schedule.run(&mut world);
}
#[test]
#[should_panic]
fn missing_resource_panics_multi_threaded() {
let mut world = World::new();
let mut schedule = Schedule::default();
schedule.set_executor_kind(ExecutorKind::MultiThreaded);
schedule.add_systems(look_for_missing_resource);
schedule.run(&mut world);
}
#[test]
fn piped_systems_first_system_skipped() {
// This system should be skipped when run due to no matching entity
fn pipe_out(_single: Single<&TestComponent>) -> u8 {
42
}
fn pipe_in(_input: In<u8>, mut counter: ResMut<Counter>) {
counter.0 += 1;
}
let mut world = World::new();
world.init_resource::<Counter>();
let mut schedule = Schedule::default();
schedule.add_systems(pipe_out.pipe(pipe_in));
schedule.run(&mut world);
let counter = world.resource::<Counter>();
assert_eq!(counter.0, 0);
}
#[test]
fn piped_system_second_system_skipped() {
fn pipe_out(mut counter: ResMut<Counter>) -> u8 {
counter.0 += 1;
42
}
// This system should be skipped when run due to no matching entity
fn pipe_in(_input: In<u8>, _single: Single<&TestComponent>) {}
let mut world = World::new();
world.init_resource::<Counter>();
let mut schedule = Schedule::default();
schedule.add_systems(pipe_out.pipe(pipe_in));
schedule.run(&mut world);
let counter = world.resource::<Counter>();
assert_eq!(counter.0, 0);
}
#[test]
#[should_panic]
fn piped_system_first_system_panics() {
// This system should panic when run because the resource is missing
fn pipe_out(_res: Res<TestState>) -> u8 {
42
}
fn pipe_in(_input: In<u8>) {}
let mut world = World::new();
let mut schedule = Schedule::default();
schedule.add_systems(pipe_out.pipe(pipe_in));
schedule.run(&mut world);
}
#[test]
#[should_panic]
fn piped_system_second_system_panics() {
fn pipe_out() -> u8 {
42
}
// This system should panic when run because the resource is missing
fn pipe_in(_input: In<u8>, _res: Res<TestState>) {}
let mut world = World::new();
let mut schedule = Schedule::default();
schedule.add_systems(pipe_out.pipe(pipe_in));
schedule.run(&mut world);
}
// This test runs without panicking because we've
// decided to use early-out behavior for piped systems
#[test]
fn piped_system_skip_and_panic() {
// This system should be skipped when run due to no matching entity
fn pipe_out(_single: Single<&TestComponent>) -> u8 {
42
}
// This system should panic when run because the resource is missing
fn pipe_in(_input: In<u8>, _res: Res<TestState>) {}
let mut world = World::new();
let mut schedule = Schedule::default();
schedule.add_systems(pipe_out.pipe(pipe_in));
schedule.run(&mut world);
}
#[test]
#[should_panic]
fn piped_system_panic_and_skip() {
// This system should panic when run because the resource is missing
fn pipe_out(_res: Res<TestState>) -> u8 {
42
}
// This system should be skipped when run due to no matching entity
fn pipe_in(_input: In<u8>, _single: Single<&TestComponent>) {}
let mut world = World::new();
let mut schedule = Schedule::default();
schedule.add_systems(pipe_out.pipe(pipe_in));
schedule.run(&mut world);
}
#[test]
#[should_panic]
fn piped_system_panic_and_panic() {
// This system should panic when run because the resource is missing
fn pipe_out(_res: Res<TestState>) -> u8 {
42
}
// This system should panic when run because the resource is missing
fn pipe_in(_input: In<u8>, _res: Res<TestState>) {}
let mut world = World::new();
let mut schedule = Schedule::default();
schedule.add_systems(pipe_out.pipe(pipe_in));
schedule.run(&mut world);
}
#[test]
fn piped_system_skip_and_skip() {
// This system should be skipped when run due to no matching entity
fn pipe_out(_single: Single<&TestComponent>, mut counter: ResMut<Counter>) -> u8 {
counter.0 += 1;
42
}
// This system should be skipped when run due to no matching entity
fn pipe_in(_input: In<u8>, _single: Single<&TestComponent>, mut counter: ResMut<Counter>) {
counter.0 += 1;
}
let mut world = World::new();
world.init_resource::<Counter>();
let mut schedule = Schedule::default();
schedule.add_systems(pipe_out.pipe(pipe_in));
schedule.run(&mut world);
let counter = world.resource::<Counter>();
assert_eq!(counter.0, 0);
}
}

View File

@@ -0,0 +1,886 @@
use alloc::{boxed::Box, vec::Vec};
use bevy_platform::sync::Arc;
use bevy_tasks::{ComputeTaskPool, Scope, TaskPool, ThreadExecutor};
use bevy_utils::{default, syncunsafecell::SyncUnsafeCell};
use concurrent_queue::ConcurrentQueue;
use core::{any::Any, panic::AssertUnwindSafe};
use fixedbitset::FixedBitSet;
#[cfg(feature = "std")]
use std::eprintln;
use std::sync::{Mutex, MutexGuard};
#[cfg(feature = "trace")]
use tracing::{info_span, Span};
use crate::{
archetype::ArchetypeComponentId,
error::{default_error_handler, BevyError, ErrorContext, Result},
prelude::Resource,
query::Access,
schedule::{is_apply_deferred, BoxedCondition, ExecutorKind, SystemExecutor, SystemSchedule},
system::ScheduleSystem,
world::{unsafe_world_cell::UnsafeWorldCell, World},
};
use super::__rust_begin_short_backtrace;
/// Borrowed data used by the [`MultiThreadedExecutor`].
struct Environment<'env, 'sys> {
executor: &'env MultiThreadedExecutor,
systems: &'sys [SyncUnsafeCell<ScheduleSystem>],
conditions: SyncUnsafeCell<Conditions<'sys>>,
world_cell: UnsafeWorldCell<'env>,
}
struct Conditions<'a> {
system_conditions: &'a mut [Vec<BoxedCondition>],
set_conditions: &'a mut [Vec<BoxedCondition>],
sets_with_conditions_of_systems: &'a [FixedBitSet],
systems_in_sets_with_conditions: &'a [FixedBitSet],
}
impl<'env, 'sys> Environment<'env, 'sys> {
fn new(
executor: &'env MultiThreadedExecutor,
schedule: &'sys mut SystemSchedule,
world: &'env mut World,
) -> Self {
Environment {
executor,
systems: SyncUnsafeCell::from_mut(schedule.systems.as_mut_slice()).as_slice_of_cells(),
conditions: SyncUnsafeCell::new(Conditions {
system_conditions: &mut schedule.system_conditions,
set_conditions: &mut schedule.set_conditions,
sets_with_conditions_of_systems: &schedule.sets_with_conditions_of_systems,
systems_in_sets_with_conditions: &schedule.systems_in_sets_with_conditions,
}),
world_cell: world.as_unsafe_world_cell(),
}
}
}
/// Per-system data used by the [`MultiThreadedExecutor`].
// Copied here because it can't be read from the system when it's running.
struct SystemTaskMetadata {
/// The [`ArchetypeComponentId`] access of the system.
archetype_component_access: Access<ArchetypeComponentId>,
/// Indices of the systems that directly depend on the system.
dependents: Vec<usize>,
/// Is `true` if the system does not access `!Send` data.
is_send: bool,
/// Is `true` if the system is exclusive.
is_exclusive: bool,
}
/// The result of running a system that is sent across a channel.
struct SystemResult {
system_index: usize,
}
/// Runs the schedule using a thread pool. Non-conflicting systems can run in parallel.
pub struct MultiThreadedExecutor {
/// The running state, protected by a mutex so that a reference to the executor can be shared across tasks.
state: Mutex<ExecutorState>,
/// Queue of system completion events.
system_completion: ConcurrentQueue<SystemResult>,
/// Setting when true applies deferred system buffers after all systems have run
apply_final_deferred: bool,
/// When set, tells the executor that a thread has panicked.
panic_payload: Mutex<Option<Box<dyn Any + Send>>>,
starting_systems: FixedBitSet,
/// Cached tracing span
#[cfg(feature = "trace")]
executor_span: Span,
}
/// The state of the executor while running.
pub struct ExecutorState {
/// Metadata for scheduling and running system tasks.
system_task_metadata: Vec<SystemTaskMetadata>,
/// Union of the accesses of all currently running systems.
active_access: Access<ArchetypeComponentId>,
/// Returns `true` if a system with non-`Send` access is running.
local_thread_running: bool,
/// Returns `true` if an exclusive system is running.
exclusive_running: bool,
/// The number of systems that are running.
num_running_systems: usize,
/// The number of dependencies each system has that have not completed.
num_dependencies_remaining: Vec<usize>,
/// System sets whose conditions have been evaluated.
evaluated_sets: FixedBitSet,
/// Systems that have no remaining dependencies and are waiting to run.
ready_systems: FixedBitSet,
/// copy of `ready_systems`
ready_systems_copy: FixedBitSet,
/// Systems that are running.
running_systems: FixedBitSet,
/// Systems that got skipped.
skipped_systems: FixedBitSet,
/// Systems whose conditions have been evaluated and were run or skipped.
completed_systems: FixedBitSet,
/// Systems that have run but have not had their buffers applied.
unapplied_systems: FixedBitSet,
}
/// References to data required by the executor.
/// This is copied to each system task so that can invoke the executor when they complete.
// These all need to outlive 'scope in order to be sent to new tasks,
// and keeping them all in a struct means we can use lifetime elision.
#[derive(Copy, Clone)]
struct Context<'scope, 'env, 'sys> {
environment: &'env Environment<'env, 'sys>,
scope: &'scope Scope<'scope, 'env, ()>,
error_handler: fn(BevyError, ErrorContext),
}
impl Default for MultiThreadedExecutor {
fn default() -> Self {
Self::new()
}
}
impl SystemExecutor for MultiThreadedExecutor {
fn kind(&self) -> ExecutorKind {
ExecutorKind::MultiThreaded
}
fn init(&mut self, schedule: &SystemSchedule) {
let state = self.state.get_mut().unwrap();
// pre-allocate space
let sys_count = schedule.system_ids.len();
let set_count = schedule.set_ids.len();
self.system_completion = ConcurrentQueue::bounded(sys_count.max(1));
self.starting_systems = FixedBitSet::with_capacity(sys_count);
state.evaluated_sets = FixedBitSet::with_capacity(set_count);
state.ready_systems = FixedBitSet::with_capacity(sys_count);
state.ready_systems_copy = FixedBitSet::with_capacity(sys_count);
state.running_systems = FixedBitSet::with_capacity(sys_count);
state.completed_systems = FixedBitSet::with_capacity(sys_count);
state.skipped_systems = FixedBitSet::with_capacity(sys_count);
state.unapplied_systems = FixedBitSet::with_capacity(sys_count);
state.system_task_metadata = Vec::with_capacity(sys_count);
for index in 0..sys_count {
state.system_task_metadata.push(SystemTaskMetadata {
archetype_component_access: default(),
dependents: schedule.system_dependents[index].clone(),
is_send: schedule.systems[index].is_send(),
is_exclusive: schedule.systems[index].is_exclusive(),
});
if schedule.system_dependencies[index] == 0 {
self.starting_systems.insert(index);
}
}
state.num_dependencies_remaining = Vec::with_capacity(sys_count);
}
fn run(
&mut self,
schedule: &mut SystemSchedule,
world: &mut World,
_skip_systems: Option<&FixedBitSet>,
error_handler: fn(BevyError, ErrorContext),
) {
let state = self.state.get_mut().unwrap();
// reset counts
if schedule.systems.is_empty() {
return;
}
state.num_running_systems = 0;
state
.num_dependencies_remaining
.clone_from(&schedule.system_dependencies);
state.ready_systems.clone_from(&self.starting_systems);
// If stepping is enabled, make sure we skip those systems that should
// not be run.
#[cfg(feature = "bevy_debug_stepping")]
if let Some(skipped_systems) = _skip_systems {
debug_assert_eq!(skipped_systems.len(), state.completed_systems.len());
// mark skipped systems as completed
state.completed_systems |= skipped_systems;
// signal the dependencies for each of the skipped systems, as
// though they had run
for system_index in skipped_systems.ones() {
state.signal_dependents(system_index);
state.ready_systems.remove(system_index);
}
}
let thread_executor = world
.get_resource::<MainThreadExecutor>()
.map(|e| e.0.clone());
let thread_executor = thread_executor.as_deref();
let environment = &Environment::new(self, schedule, world);
ComputeTaskPool::get_or_init(TaskPool::default).scope_with_executor(
false,
thread_executor,
|scope| {
let context = Context {
environment,
scope,
error_handler,
};
// The first tick won't need to process finished systems, but we still need to run the loop in
// tick_executor() in case a system completes while the first tick still holds the mutex.
context.tick_executor();
},
);
// End the borrows of self and world in environment by copying out the reference to systems.
let systems = environment.systems;
let state = self.state.get_mut().unwrap();
if self.apply_final_deferred {
// Do one final apply buffers after all systems have completed
// Commands should be applied while on the scope's thread, not the executor's thread
let res = apply_deferred(&state.unapplied_systems, systems, world);
if let Err(payload) = res {
let panic_payload = self.panic_payload.get_mut().unwrap();
*panic_payload = Some(payload);
}
state.unapplied_systems.clear();
}
// check to see if there was a panic
let payload = self.panic_payload.get_mut().unwrap();
if let Some(payload) = payload.take() {
std::panic::resume_unwind(payload);
}
debug_assert!(state.ready_systems.is_clear());
debug_assert!(state.running_systems.is_clear());
state.active_access.clear();
state.evaluated_sets.clear();
state.skipped_systems.clear();
state.completed_systems.clear();
}
fn set_apply_final_deferred(&mut self, value: bool) {
self.apply_final_deferred = value;
}
}
impl<'scope, 'env: 'scope, 'sys> Context<'scope, 'env, 'sys> {
fn system_completed(
&self,
system_index: usize,
res: Result<(), Box<dyn Any + Send>>,
system: &ScheduleSystem,
) {
// tell the executor that the system finished
self.environment
.executor
.system_completion
.push(SystemResult { system_index })
.unwrap_or_else(|error| unreachable!("{}", error));
if let Err(payload) = res {
#[cfg(feature = "std")]
#[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")]
{
eprintln!("Encountered a panic in system `{}`!", &*system.name());
}
// set the payload to propagate the error
{
let mut panic_payload = self.environment.executor.panic_payload.lock().unwrap();
*panic_payload = Some(payload);
}
}
self.tick_executor();
}
fn try_lock<'a>(&'a self) -> Option<(&'a mut Conditions<'sys>, MutexGuard<'a, ExecutorState>)> {
let guard = self.environment.executor.state.try_lock().ok()?;
// SAFETY: This is an exclusive access as no other location fetches conditions mutably, and
// is synchronized by the lock on the executor state.
let conditions = unsafe { &mut *self.environment.conditions.get() };
Some((conditions, guard))
}
fn tick_executor(&self) {
// Ensure that the executor handles any events pushed to the system_completion queue by this thread.
// If this thread acquires the lock, the executor runs after the push() and they are processed.
// If this thread does not acquire the lock, then the is_empty() check on the other thread runs
// after the lock is released, which is after try_lock() failed, which is after the push()
// on this thread, so the is_empty() check will see the new events and loop.
loop {
let Some((conditions, mut guard)) = self.try_lock() else {
return;
};
guard.tick(self, conditions);
// Make sure we drop the guard before checking system_completion.is_empty(), or we could lose events.
drop(guard);
if self.environment.executor.system_completion.is_empty() {
return;
}
}
}
}
impl MultiThreadedExecutor {
/// Creates a new `multi_threaded` executor for use with a [`Schedule`].
///
/// [`Schedule`]: crate::schedule::Schedule
pub fn new() -> Self {
Self {
state: Mutex::new(ExecutorState::new()),
system_completion: ConcurrentQueue::unbounded(),
starting_systems: FixedBitSet::new(),
apply_final_deferred: true,
panic_payload: Mutex::new(None),
#[cfg(feature = "trace")]
executor_span: info_span!("multithreaded executor"),
}
}
}
impl ExecutorState {
fn new() -> Self {
Self {
system_task_metadata: Vec::new(),
num_running_systems: 0,
num_dependencies_remaining: Vec::new(),
active_access: default(),
local_thread_running: false,
exclusive_running: false,
evaluated_sets: FixedBitSet::new(),
ready_systems: FixedBitSet::new(),
ready_systems_copy: FixedBitSet::new(),
running_systems: FixedBitSet::new(),
skipped_systems: FixedBitSet::new(),
completed_systems: FixedBitSet::new(),
unapplied_systems: FixedBitSet::new(),
}
}
fn tick(&mut self, context: &Context, conditions: &mut Conditions) {
#[cfg(feature = "trace")]
let _span = context.environment.executor.executor_span.enter();
for result in context.environment.executor.system_completion.try_iter() {
self.finish_system_and_handle_dependents(result);
}
self.rebuild_active_access();
// SAFETY:
// - `finish_system_and_handle_dependents` has updated the currently running systems.
// - `rebuild_active_access` locks access for all currently running systems.
unsafe {
self.spawn_system_tasks(context, conditions);
}
}
/// # Safety
/// - Caller must ensure that `self.ready_systems` does not contain any systems that
/// have been mutably borrowed (such as the systems currently running).
/// - `world_cell` must have permission to access all world data (not counting
/// any world data that is claimed by systems currently running on this executor).
unsafe fn spawn_system_tasks(&mut self, context: &Context, conditions: &mut Conditions) {
if self.exclusive_running {
return;
}
// can't borrow since loop mutably borrows `self`
let mut ready_systems = core::mem::take(&mut self.ready_systems_copy);
// Skipping systems may cause their dependents to become ready immediately.
// If that happens, we need to run again immediately or we may fail to spawn those dependents.
let mut check_for_new_ready_systems = true;
while check_for_new_ready_systems {
check_for_new_ready_systems = false;
ready_systems.clone_from(&self.ready_systems);
for system_index in ready_systems.ones() {
debug_assert!(!self.running_systems.contains(system_index));
// SAFETY: Caller assured that these systems are not running.
// Therefore, no other reference to this system exists and there is no aliasing.
let system = unsafe { &mut *context.environment.systems[system_index].get() };
if !self.can_run(
system_index,
system,
conditions,
context.environment.world_cell,
) {
// NOTE: exclusive systems with ambiguities are susceptible to
// being significantly displaced here (compared to single-threaded order)
// if systems after them in topological order can run
// if that becomes an issue, `break;` if exclusive system
continue;
}
self.ready_systems.remove(system_index);
// SAFETY: `can_run` returned true, which means that:
// - It must have called `update_archetype_component_access` for each run condition.
// - There can be no systems running whose accesses would conflict with any conditions.
if unsafe {
!self.should_run(
system_index,
system,
conditions,
context.environment.world_cell,
)
} {
self.skip_system_and_signal_dependents(system_index);
// signal_dependents may have set more systems to ready.
check_for_new_ready_systems = true;
continue;
}
self.running_systems.insert(system_index);
self.num_running_systems += 1;
if self.system_task_metadata[system_index].is_exclusive {
// SAFETY: `can_run` returned true for this system,
// which means no systems are currently borrowed.
unsafe {
self.spawn_exclusive_system_task(context, system_index);
}
check_for_new_ready_systems = false;
break;
}
// SAFETY:
// - Caller ensured no other reference to this system exists.
// - `system_task_metadata[system_index].is_exclusive` is `false`,
// so `System::is_exclusive` returned `false` when we called it.
// - `can_run` has been called, which calls `update_archetype_component_access` with this system.
// - `can_run` returned true, so no systems with conflicting world access are running.
unsafe {
self.spawn_system_task(context, system_index);
}
}
}
// give back
self.ready_systems_copy = ready_systems;
}
fn can_run(
&mut self,
system_index: usize,
system: &mut ScheduleSystem,
conditions: &mut Conditions,
world: UnsafeWorldCell,
) -> bool {
let system_meta = &self.system_task_metadata[system_index];
if system_meta.is_exclusive && self.num_running_systems > 0 {
return false;
}
if !system_meta.is_send && self.local_thread_running {
return false;
}
// TODO: an earlier out if world's archetypes did not change
for set_idx in conditions.sets_with_conditions_of_systems[system_index]
.difference(&self.evaluated_sets)
{
for condition in &mut conditions.set_conditions[set_idx] {
condition.update_archetype_component_access(world);
if !condition
.archetype_component_access()
.is_compatible(&self.active_access)
{
return false;
}
}
}
for condition in &mut conditions.system_conditions[system_index] {
condition.update_archetype_component_access(world);
if !condition
.archetype_component_access()
.is_compatible(&self.active_access)
{
return false;
}
}
if !self.skipped_systems.contains(system_index) {
system.update_archetype_component_access(world);
if !system
.archetype_component_access()
.is_compatible(&self.active_access)
{
return false;
}
self.system_task_metadata[system_index]
.archetype_component_access
.clone_from(system.archetype_component_access());
}
true
}
/// # Safety
/// * `world` must have permission to read any world data required by
/// the system's conditions: this includes conditions for the system
/// itself, and conditions for any of the system's sets.
/// * `update_archetype_component` must have been called with `world`
/// for the system as well as system and system set's run conditions.
unsafe fn should_run(
&mut self,
system_index: usize,
system: &mut ScheduleSystem,
conditions: &mut Conditions,
world: UnsafeWorldCell,
) -> bool {
let mut should_run = !self.skipped_systems.contains(system_index);
let error_handler = default_error_handler();
for set_idx in conditions.sets_with_conditions_of_systems[system_index].ones() {
if self.evaluated_sets.contains(set_idx) {
continue;
}
// Evaluate the system set's conditions.
// SAFETY:
// - The caller ensures that `world` has permission to read any data
// required by the conditions.
// - `update_archetype_component_access` has been called for each run condition.
let set_conditions_met = unsafe {
evaluate_and_fold_conditions(&mut conditions.set_conditions[set_idx], world)
};
if !set_conditions_met {
self.skipped_systems
.union_with(&conditions.systems_in_sets_with_conditions[set_idx]);
}
should_run &= set_conditions_met;
self.evaluated_sets.insert(set_idx);
}
// Evaluate the system's conditions.
// SAFETY:
// - The caller ensures that `world` has permission to read any data
// required by the conditions.
// - `update_archetype_component_access` has been called for each run condition.
let system_conditions_met = unsafe {
evaluate_and_fold_conditions(&mut conditions.system_conditions[system_index], world)
};
if !system_conditions_met {
self.skipped_systems.insert(system_index);
}
should_run &= system_conditions_met;
if should_run {
// SAFETY:
// - The caller ensures that `world` has permission to read any data
// required by the system.
// - `update_archetype_component_access` has been called for system.
let valid_params = match unsafe { system.validate_param_unsafe(world) } {
Ok(()) => true,
Err(e) => {
if !e.skipped {
error_handler(
e.into(),
ErrorContext::System {
name: system.name(),
last_run: system.get_last_run(),
},
);
}
false
}
};
if !valid_params {
self.skipped_systems.insert(system_index);
}
should_run &= valid_params;
}
should_run
}
/// # Safety
/// - Caller must not alias systems that are running.
/// - `is_exclusive` must have returned `false` for the specified system.
/// - `world` must have permission to access the world data
/// used by the specified system.
/// - `update_archetype_component_access` must have been called with `world`
/// on the system associated with `system_index`.
unsafe fn spawn_system_task(&mut self, context: &Context, system_index: usize) {
// SAFETY: this system is not running, no other reference exists
let system = unsafe { &mut *context.environment.systems[system_index].get() };
// Move the full context object into the new future.
let context = *context;
let system_meta = &self.system_task_metadata[system_index];
let task = async move {
let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
// SAFETY:
// - The caller ensures that we have permission to
// access the world data used by the system.
// - `is_exclusive` returned false
// - `update_archetype_component_access` has been called.
unsafe {
if let Err(err) = __rust_begin_short_backtrace::run_unsafe(
system,
context.environment.world_cell,
) {
(context.error_handler)(
err,
ErrorContext::System {
name: system.name(),
last_run: system.get_last_run(),
},
);
}
};
}));
context.system_completed(system_index, res, system);
};
self.active_access
.extend(&system_meta.archetype_component_access);
if system_meta.is_send {
context.scope.spawn(task);
} else {
self.local_thread_running = true;
context.scope.spawn_on_external(task);
}
}
/// # Safety
/// Caller must ensure no systems are currently borrowed.
unsafe fn spawn_exclusive_system_task(&mut self, context: &Context, system_index: usize) {
// SAFETY: this system is not running, no other reference exists
let system = unsafe { &mut *context.environment.systems[system_index].get() };
// Move the full context object into the new future.
let context = *context;
if is_apply_deferred(system) {
// TODO: avoid allocation
let unapplied_systems = self.unapplied_systems.clone();
self.unapplied_systems.clear();
let task = async move {
// SAFETY: `can_run` returned true for this system, which means
// that no other systems currently have access to the world.
let world = unsafe { context.environment.world_cell.world_mut() };
let res = apply_deferred(&unapplied_systems, context.environment.systems, world);
context.system_completed(system_index, res, system);
};
context.scope.spawn_on_scope(task);
} else {
let task = async move {
// SAFETY: `can_run` returned true for this system, which means
// that no other systems currently have access to the world.
let world = unsafe { context.environment.world_cell.world_mut() };
let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
if let Err(err) = __rust_begin_short_backtrace::run(system, world) {
(context.error_handler)(
err,
ErrorContext::System {
name: system.name(),
last_run: system.get_last_run(),
},
);
}
}));
context.system_completed(system_index, res, system);
};
context.scope.spawn_on_scope(task);
}
self.exclusive_running = true;
self.local_thread_running = true;
}
fn finish_system_and_handle_dependents(&mut self, result: SystemResult) {
let SystemResult { system_index, .. } = result;
if self.system_task_metadata[system_index].is_exclusive {
self.exclusive_running = false;
}
if !self.system_task_metadata[system_index].is_send {
self.local_thread_running = false;
}
debug_assert!(self.num_running_systems >= 1);
self.num_running_systems -= 1;
self.running_systems.remove(system_index);
self.completed_systems.insert(system_index);
self.unapplied_systems.insert(system_index);
self.signal_dependents(system_index);
}
fn skip_system_and_signal_dependents(&mut self, system_index: usize) {
self.completed_systems.insert(system_index);
self.signal_dependents(system_index);
}
fn signal_dependents(&mut self, system_index: usize) {
for &dep_idx in &self.system_task_metadata[system_index].dependents {
let remaining = &mut self.num_dependencies_remaining[dep_idx];
debug_assert!(*remaining >= 1);
*remaining -= 1;
if *remaining == 0 && !self.completed_systems.contains(dep_idx) {
self.ready_systems.insert(dep_idx);
}
}
}
fn rebuild_active_access(&mut self) {
self.active_access.clear();
for index in self.running_systems.ones() {
let system_meta = &self.system_task_metadata[index];
self.active_access
.extend(&system_meta.archetype_component_access);
}
}
}
fn apply_deferred(
unapplied_systems: &FixedBitSet,
systems: &[SyncUnsafeCell<ScheduleSystem>],
world: &mut World,
) -> Result<(), Box<dyn Any + Send>> {
for system_index in unapplied_systems.ones() {
// SAFETY: none of these systems are running, no other references exist
let system = unsafe { &mut *systems[system_index].get() };
let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
system.apply_deferred(world);
}));
if let Err(payload) = res {
#[cfg(feature = "std")]
#[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")]
{
eprintln!(
"Encountered a panic when applying buffers for system `{}`!",
&*system.name()
);
}
return Err(payload);
}
}
Ok(())
}
/// # Safety
/// - `world` must have permission to read any world data
/// required by `conditions`.
/// - `update_archetype_component_access` must have been called
/// with `world` for each condition in `conditions`.
unsafe fn evaluate_and_fold_conditions(
conditions: &mut [BoxedCondition],
world: UnsafeWorldCell,
) -> bool {
let error_handler = default_error_handler();
#[expect(
clippy::unnecessary_fold,
reason = "Short-circuiting here would prevent conditions from mutating their own state as needed."
)]
conditions
.iter_mut()
.map(|condition| {
// SAFETY:
// - The caller ensures that `world` has permission to read any data
// required by the condition.
// - `update_archetype_component_access` has been called for condition.
match unsafe { condition.validate_param_unsafe(world) } {
Ok(()) => (),
Err(e) => {
if !e.skipped {
error_handler(
e.into(),
ErrorContext::System {
name: condition.name(),
last_run: condition.get_last_run(),
},
);
}
return false;
}
}
// SAFETY:
// - The caller ensures that `world` has permission to read any data
// required by the condition.
// - `update_archetype_component_access` has been called for condition.
unsafe { __rust_begin_short_backtrace::readonly_run_unsafe(&mut **condition, world) }
})
.fold(true, |acc, res| acc && res)
}
/// New-typed [`ThreadExecutor`] [`Resource`] that is used to run systems on the main thread
#[derive(Resource, Clone)]
pub struct MainThreadExecutor(pub Arc<ThreadExecutor<'static>>);
impl Default for MainThreadExecutor {
fn default() -> Self {
Self::new()
}
}
impl MainThreadExecutor {
/// Creates a new executor that can be used to run systems on the main thread.
pub fn new() -> Self {
MainThreadExecutor(TaskPool::get_thread_executor())
}
}
#[cfg(test)]
mod tests {
use crate::{
prelude::Resource,
schedule::{ExecutorKind, IntoScheduleConfigs, Schedule},
system::Commands,
world::World,
};
#[derive(Resource)]
struct R;
#[test]
fn skipped_systems_notify_dependents() {
let mut world = World::new();
let mut schedule = Schedule::default();
schedule.set_executor_kind(ExecutorKind::MultiThreaded);
schedule.add_systems(
(
(|| {}).run_if(|| false),
// This system depends on a system that is always skipped.
|mut commands: Commands| {
commands.insert_resource(R);
},
)
.chain(),
);
schedule.run(&mut world);
assert!(world.get_resource::<R>().is_some());
}
/// Regression test for a weird bug flagged by MIRI in
/// `spawn_exclusive_system_task`, related to a `&mut World` being captured
/// inside an `async` block and somehow remaining alive even after its last use.
#[test]
fn check_spawn_exclusive_system_task_miri() {
let mut world = World::new();
let mut schedule = Schedule::default();
schedule.set_executor_kind(ExecutorKind::MultiThreaded);
schedule.add_systems(((|_: Commands| {}), |_: Commands| {}).chain());
schedule.run(&mut world);
}
}

View File

@@ -0,0 +1,210 @@
use core::panic::AssertUnwindSafe;
use fixedbitset::FixedBitSet;
#[cfg(feature = "trace")]
use tracing::info_span;
#[cfg(feature = "std")]
use std::eprintln;
use crate::{
error::{default_error_handler, BevyError, ErrorContext},
schedule::{
executor::is_apply_deferred, BoxedCondition, ExecutorKind, SystemExecutor, SystemSchedule,
},
world::World,
};
use super::__rust_begin_short_backtrace;
/// A variant of [`SingleThreadedExecutor`](crate::schedule::SingleThreadedExecutor) that calls
/// [`apply_deferred`](crate::system::System::apply_deferred) immediately after running each system.
#[derive(Default)]
pub struct SimpleExecutor {
/// Systems sets whose conditions have been evaluated.
evaluated_sets: FixedBitSet,
/// Systems that have run or been skipped.
completed_systems: FixedBitSet,
}
impl SystemExecutor for SimpleExecutor {
fn kind(&self) -> ExecutorKind {
ExecutorKind::Simple
}
fn init(&mut self, schedule: &SystemSchedule) {
let sys_count = schedule.system_ids.len();
let set_count = schedule.set_ids.len();
self.evaluated_sets = FixedBitSet::with_capacity(set_count);
self.completed_systems = FixedBitSet::with_capacity(sys_count);
}
fn run(
&mut self,
schedule: &mut SystemSchedule,
world: &mut World,
_skip_systems: Option<&FixedBitSet>,
error_handler: fn(BevyError, ErrorContext),
) {
// If stepping is enabled, make sure we skip those systems that should
// not be run.
#[cfg(feature = "bevy_debug_stepping")]
if let Some(skipped_systems) = _skip_systems {
// mark skipped systems as completed
self.completed_systems |= skipped_systems;
}
for system_index in 0..schedule.systems.len() {
#[cfg(feature = "trace")]
let name = schedule.systems[system_index].name();
#[cfg(feature = "trace")]
let should_run_span = info_span!("check_conditions", name = &*name).entered();
let mut should_run = !self.completed_systems.contains(system_index);
for set_idx in schedule.sets_with_conditions_of_systems[system_index].ones() {
if self.evaluated_sets.contains(set_idx) {
continue;
}
// evaluate system set's conditions
let set_conditions_met =
evaluate_and_fold_conditions(&mut schedule.set_conditions[set_idx], world);
if !set_conditions_met {
self.completed_systems
.union_with(&schedule.systems_in_sets_with_conditions[set_idx]);
}
should_run &= set_conditions_met;
self.evaluated_sets.insert(set_idx);
}
// evaluate system's conditions
let system_conditions_met =
evaluate_and_fold_conditions(&mut schedule.system_conditions[system_index], world);
should_run &= system_conditions_met;
let system = &mut schedule.systems[system_index];
if should_run {
let valid_params = match system.validate_param(world) {
Ok(()) => true,
Err(e) => {
if !e.skipped {
error_handler(
e.into(),
ErrorContext::System {
name: system.name(),
last_run: system.get_last_run(),
},
);
}
false
}
};
should_run &= valid_params;
}
#[cfg(feature = "trace")]
should_run_span.exit();
// system has either been skipped or will run
self.completed_systems.insert(system_index);
if !should_run {
continue;
}
if is_apply_deferred(system) {
continue;
}
let f = AssertUnwindSafe(|| {
if let Err(err) = __rust_begin_short_backtrace::run(system, world) {
error_handler(
err,
ErrorContext::System {
name: system.name(),
last_run: system.get_last_run(),
},
);
}
});
#[cfg(feature = "std")]
#[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")]
{
if let Err(payload) = std::panic::catch_unwind(f) {
eprintln!("Encountered a panic in system `{}`!", &*system.name());
std::panic::resume_unwind(payload);
}
}
#[cfg(not(feature = "std"))]
{
(f)();
}
}
self.evaluated_sets.clear();
self.completed_systems.clear();
}
fn set_apply_final_deferred(&mut self, _: bool) {
// do nothing. simple executor does not do a final sync
}
}
impl SimpleExecutor {
/// Creates a new simple executor for use in a [`Schedule`](crate::schedule::Schedule).
/// This calls each system in order and immediately calls [`System::apply_deferred`](crate::system::System).
pub const fn new() -> Self {
Self {
evaluated_sets: FixedBitSet::new(),
completed_systems: FixedBitSet::new(),
}
}
}
fn evaluate_and_fold_conditions(conditions: &mut [BoxedCondition], world: &mut World) -> bool {
let error_handler = default_error_handler();
#[expect(
clippy::unnecessary_fold,
reason = "Short-circuiting here would prevent conditions from mutating their own state as needed."
)]
conditions
.iter_mut()
.map(|condition| {
match condition.validate_param(world) {
Ok(()) => (),
Err(e) => {
if !e.skipped {
error_handler(
e.into(),
ErrorContext::System {
name: condition.name(),
last_run: condition.get_last_run(),
},
);
}
return false;
}
}
__rust_begin_short_backtrace::readonly_run(&mut **condition, world)
})
.fold(true, |acc, res| acc && res)
}
#[cfg(test)]
#[test]
fn skip_automatic_sync_points() {
// Schedules automatically insert ApplyDeferred systems, but these should
// not be executed as they only serve as markers and are not initialized
use crate::prelude::*;
let mut sched = Schedule::default();
sched.set_executor_kind(ExecutorKind::Simple);
sched.add_systems((|_: Commands| (), || ()).chain());
let mut world = World::new();
sched.run(&mut world);
}

View File

@@ -0,0 +1,241 @@
use core::panic::AssertUnwindSafe;
use fixedbitset::FixedBitSet;
#[cfg(feature = "trace")]
use tracing::info_span;
#[cfg(feature = "std")]
use std::eprintln;
use crate::{
error::{default_error_handler, BevyError, ErrorContext},
schedule::{is_apply_deferred, BoxedCondition, ExecutorKind, SystemExecutor, SystemSchedule},
world::World,
};
use super::__rust_begin_short_backtrace;
/// Runs the schedule using a single thread.
///
/// Useful if you're dealing with a single-threaded environment, saving your threads for
/// other things, or just trying minimize overhead.
#[derive(Default)]
pub struct SingleThreadedExecutor {
/// System sets whose conditions have been evaluated.
evaluated_sets: FixedBitSet,
/// Systems that have run or been skipped.
completed_systems: FixedBitSet,
/// Systems that have run but have not had their buffers applied.
unapplied_systems: FixedBitSet,
/// Setting when true applies deferred system buffers after all systems have run
apply_final_deferred: bool,
}
impl SystemExecutor for SingleThreadedExecutor {
fn kind(&self) -> ExecutorKind {
ExecutorKind::SingleThreaded
}
fn init(&mut self, schedule: &SystemSchedule) {
// pre-allocate space
let sys_count = schedule.system_ids.len();
let set_count = schedule.set_ids.len();
self.evaluated_sets = FixedBitSet::with_capacity(set_count);
self.completed_systems = FixedBitSet::with_capacity(sys_count);
self.unapplied_systems = FixedBitSet::with_capacity(sys_count);
}
fn run(
&mut self,
schedule: &mut SystemSchedule,
world: &mut World,
_skip_systems: Option<&FixedBitSet>,
error_handler: fn(BevyError, ErrorContext),
) {
// If stepping is enabled, make sure we skip those systems that should
// not be run.
#[cfg(feature = "bevy_debug_stepping")]
if let Some(skipped_systems) = _skip_systems {
// mark skipped systems as completed
self.completed_systems |= skipped_systems;
}
for system_index in 0..schedule.systems.len() {
#[cfg(feature = "trace")]
let name = schedule.systems[system_index].name();
#[cfg(feature = "trace")]
let should_run_span = info_span!("check_conditions", name = &*name).entered();
let mut should_run = !self.completed_systems.contains(system_index);
for set_idx in schedule.sets_with_conditions_of_systems[system_index].ones() {
if self.evaluated_sets.contains(set_idx) {
continue;
}
// evaluate system set's conditions
let set_conditions_met =
evaluate_and_fold_conditions(&mut schedule.set_conditions[set_idx], world);
if !set_conditions_met {
self.completed_systems
.union_with(&schedule.systems_in_sets_with_conditions[set_idx]);
}
should_run &= set_conditions_met;
self.evaluated_sets.insert(set_idx);
}
// evaluate system's conditions
let system_conditions_met =
evaluate_and_fold_conditions(&mut schedule.system_conditions[system_index], world);
should_run &= system_conditions_met;
let system = &mut schedule.systems[system_index];
if should_run {
let valid_params = match system.validate_param(world) {
Ok(()) => true,
Err(e) => {
if !e.skipped {
error_handler(
e.into(),
ErrorContext::System {
name: system.name(),
last_run: system.get_last_run(),
},
);
}
false
}
};
should_run &= valid_params;
}
#[cfg(feature = "trace")]
should_run_span.exit();
// system has either been skipped or will run
self.completed_systems.insert(system_index);
if !should_run {
continue;
}
if is_apply_deferred(system) {
self.apply_deferred(schedule, world);
continue;
}
let f = AssertUnwindSafe(|| {
if system.is_exclusive() {
if let Err(err) = __rust_begin_short_backtrace::run(system, world) {
error_handler(
err,
ErrorContext::System {
name: system.name(),
last_run: system.get_last_run(),
},
);
}
} else {
// Use run_unsafe to avoid immediately applying deferred buffers
let world = world.as_unsafe_world_cell();
system.update_archetype_component_access(world);
// SAFETY: We have exclusive, single-threaded access to the world and
// update_archetype_component_access is being called immediately before this.
unsafe {
if let Err(err) = __rust_begin_short_backtrace::run_unsafe(system, world) {
error_handler(
err,
ErrorContext::System {
name: system.name(),
last_run: system.get_last_run(),
},
);
}
};
}
});
#[cfg(feature = "std")]
#[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")]
{
if let Err(payload) = std::panic::catch_unwind(f) {
eprintln!("Encountered a panic in system `{}`!", &*system.name());
std::panic::resume_unwind(payload);
}
}
#[cfg(not(feature = "std"))]
{
(f)();
}
self.unapplied_systems.insert(system_index);
}
if self.apply_final_deferred {
self.apply_deferred(schedule, world);
}
self.evaluated_sets.clear();
self.completed_systems.clear();
}
fn set_apply_final_deferred(&mut self, apply_final_deferred: bool) {
self.apply_final_deferred = apply_final_deferred;
}
}
impl SingleThreadedExecutor {
/// Creates a new single-threaded executor for use in a [`Schedule`].
///
/// [`Schedule`]: crate::schedule::Schedule
pub const fn new() -> Self {
Self {
evaluated_sets: FixedBitSet::new(),
completed_systems: FixedBitSet::new(),
unapplied_systems: FixedBitSet::new(),
apply_final_deferred: true,
}
}
fn apply_deferred(&mut self, schedule: &mut SystemSchedule, world: &mut World) {
for system_index in self.unapplied_systems.ones() {
let system = &mut schedule.systems[system_index];
system.apply_deferred(world);
}
self.unapplied_systems.clear();
}
}
fn evaluate_and_fold_conditions(conditions: &mut [BoxedCondition], world: &mut World) -> bool {
let error_handler: fn(BevyError, ErrorContext) = default_error_handler();
#[expect(
clippy::unnecessary_fold,
reason = "Short-circuiting here would prevent conditions from mutating their own state as needed."
)]
conditions
.iter_mut()
.map(|condition| {
match condition.validate_param(world) {
Ok(()) => (),
Err(e) => {
if !e.skipped {
error_handler(
e.into(),
ErrorContext::System {
name: condition.name(),
last_run: condition.get_last_run(),
},
);
}
return false;
}
}
__rust_begin_short_backtrace::readonly_run(&mut **condition, world)
})
.fold(true, |acc, res| acc && res)
}

View File

@@ -0,0 +1,474 @@
//! `Graph<DIRECTED>` is a graph datastructure where node values are mapping
//! keys.
//! Based on the `GraphMap` datastructure from [`petgraph`].
//!
//! [`petgraph`]: https://docs.rs/petgraph/0.6.5/petgraph/
use alloc::vec::Vec;
use bevy_platform::{collections::HashSet, hash::FixedHasher};
use core::{
fmt,
hash::{BuildHasher, Hash},
};
use indexmap::IndexMap;
use smallvec::SmallVec;
use super::NodeId;
use Direction::{Incoming, Outgoing};
/// A `Graph` with undirected edges.
///
/// For example, an edge between *1* and *2* is equivalent to an edge between
/// *2* and *1*.
pub type UnGraph<S = FixedHasher> = Graph<false, S>;
/// A `Graph` with directed edges.
///
/// For example, an edge from *1* to *2* is distinct from an edge from *2* to
/// *1*.
pub type DiGraph<S = FixedHasher> = Graph<true, S>;
/// `Graph<DIRECTED>` is a graph datastructure using an associative array
/// of its node weights `NodeId`.
///
/// It uses a combined adjacency list and sparse adjacency matrix
/// representation, using **O(|N| + |E|)** space, and allows testing for edge
/// existence in constant time.
///
/// `Graph` is parameterized over:
///
/// - Constant generic bool `DIRECTED` determines whether the graph edges are directed or
/// undirected.
/// - The `BuildHasher` `S`.
///
/// You can use the type aliases `UnGraph` and `DiGraph` for convenience.
///
/// `Graph` does not allow parallel edges, but self loops are allowed.
#[derive(Clone)]
pub struct Graph<const DIRECTED: bool, S = FixedHasher>
where
S: BuildHasher,
{
nodes: IndexMap<NodeId, Vec<CompactNodeIdAndDirection>, S>,
edges: HashSet<CompactNodeIdPair, S>,
}
impl<const DIRECTED: bool, S: BuildHasher> fmt::Debug for Graph<DIRECTED, S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.nodes.fmt(f)
}
}
impl<const DIRECTED: bool, S> Graph<DIRECTED, S>
where
S: BuildHasher,
{
/// Create a new `Graph` with estimated capacity.
pub fn with_capacity(nodes: usize, edges: usize) -> Self
where
S: Default,
{
Self {
nodes: IndexMap::with_capacity_and_hasher(nodes, S::default()),
edges: HashSet::with_capacity_and_hasher(edges, S::default()),
}
}
/// Use their natural order to map the node pair (a, b) to a canonical edge id.
#[inline]
fn edge_key(a: NodeId, b: NodeId) -> CompactNodeIdPair {
let (a, b) = if DIRECTED || a <= b { (a, b) } else { (b, a) };
CompactNodeIdPair::store(a, b)
}
/// Return the number of nodes in the graph.
pub fn node_count(&self) -> usize {
self.nodes.len()
}
/// Add node `n` to the graph.
pub fn add_node(&mut self, n: NodeId) {
self.nodes.entry(n).or_default();
}
/// Remove a node `n` from the graph.
///
/// Computes in **O(N)** time, due to the removal of edges with other nodes.
pub fn remove_node(&mut self, n: NodeId) {
let Some(links) = self.nodes.swap_remove(&n) else {
return;
};
let links = links.into_iter().map(CompactNodeIdAndDirection::load);
for (succ, dir) in links {
let edge = if dir == Outgoing {
Self::edge_key(n, succ)
} else {
Self::edge_key(succ, n)
};
// remove all successor links
self.remove_single_edge(succ, n, dir.opposite());
// Remove all edge values
self.edges.remove(&edge);
}
}
/// Return `true` if the node is contained in the graph.
pub fn contains_node(&self, n: NodeId) -> bool {
self.nodes.contains_key(&n)
}
/// Add an edge connecting `a` and `b` to the graph.
/// For a directed graph, the edge is directed from `a` to `b`.
///
/// Inserts nodes `a` and/or `b` if they aren't already part of the graph.
pub fn add_edge(&mut self, a: NodeId, b: NodeId) {
if self.edges.insert(Self::edge_key(a, b)) {
// insert in the adjacency list if it's a new edge
self.nodes
.entry(a)
.or_insert_with(|| Vec::with_capacity(1))
.push(CompactNodeIdAndDirection::store(b, Outgoing));
if a != b {
// self loops don't have the Incoming entry
self.nodes
.entry(b)
.or_insert_with(|| Vec::with_capacity(1))
.push(CompactNodeIdAndDirection::store(a, Incoming));
}
}
}
/// Remove edge relation from a to b
///
/// Return `true` if it did exist.
fn remove_single_edge(&mut self, a: NodeId, b: NodeId, dir: Direction) -> bool {
let Some(sus) = self.nodes.get_mut(&a) else {
return false;
};
let Some(index) = sus
.iter()
.copied()
.map(CompactNodeIdAndDirection::load)
.position(|elt| (DIRECTED && elt == (b, dir)) || (!DIRECTED && elt.0 == b))
else {
return false;
};
sus.swap_remove(index);
true
}
/// Remove edge from `a` to `b` from the graph.
///
/// Return `false` if the edge didn't exist.
pub fn remove_edge(&mut self, a: NodeId, b: NodeId) -> bool {
let exist1 = self.remove_single_edge(a, b, Outgoing);
let exist2 = if a != b {
self.remove_single_edge(b, a, Incoming)
} else {
exist1
};
let weight = self.edges.remove(&Self::edge_key(a, b));
debug_assert!(exist1 == exist2 && exist1 == weight);
weight
}
/// Return `true` if the edge connecting `a` with `b` is contained in the graph.
pub fn contains_edge(&self, a: NodeId, b: NodeId) -> bool {
self.edges.contains(&Self::edge_key(a, b))
}
/// Return an iterator over the nodes of the graph.
pub fn nodes(
&self,
) -> impl DoubleEndedIterator<Item = NodeId> + ExactSizeIterator<Item = NodeId> + '_ {
self.nodes.keys().copied()
}
/// Return an iterator of all nodes with an edge starting from `a`.
pub fn neighbors(&self, a: NodeId) -> impl DoubleEndedIterator<Item = NodeId> + '_ {
let iter = match self.nodes.get(&a) {
Some(neigh) => neigh.iter(),
None => [].iter(),
};
iter.copied()
.map(CompactNodeIdAndDirection::load)
.filter_map(|(n, dir)| (!DIRECTED || dir == Outgoing).then_some(n))
}
/// Return an iterator of all neighbors that have an edge between them and
/// `a`, in the specified direction.
/// If the graph's edges are undirected, this is equivalent to *.neighbors(a)*.
pub fn neighbors_directed(
&self,
a: NodeId,
dir: Direction,
) -> impl DoubleEndedIterator<Item = NodeId> + '_ {
let iter = match self.nodes.get(&a) {
Some(neigh) => neigh.iter(),
None => [].iter(),
};
iter.copied()
.map(CompactNodeIdAndDirection::load)
.filter_map(move |(n, d)| (!DIRECTED || d == dir || n == a).then_some(n))
}
/// Return an iterator of target nodes with an edge starting from `a`,
/// paired with their respective edge weights.
pub fn edges(&self, a: NodeId) -> impl DoubleEndedIterator<Item = (NodeId, NodeId)> + '_ {
self.neighbors(a)
.map(move |b| match self.edges.get(&Self::edge_key(a, b)) {
None => unreachable!(),
Some(_) => (a, b),
})
}
/// Return an iterator of target nodes with an edge starting from `a`,
/// paired with their respective edge weights.
pub fn edges_directed(
&self,
a: NodeId,
dir: Direction,
) -> impl DoubleEndedIterator<Item = (NodeId, NodeId)> + '_ {
self.neighbors_directed(a, dir).map(move |b| {
let (a, b) = if dir == Incoming { (b, a) } else { (a, b) };
match self.edges.get(&Self::edge_key(a, b)) {
None => unreachable!(),
Some(_) => (a, b),
}
})
}
/// Return an iterator over all edges of the graph with their weight in arbitrary order.
pub fn all_edges(&self) -> impl ExactSizeIterator<Item = (NodeId, NodeId)> + '_ {
self.edges.iter().copied().map(CompactNodeIdPair::load)
}
pub(crate) fn to_index(&self, ix: NodeId) -> usize {
self.nodes.get_index_of(&ix).unwrap()
}
}
/// Create a new empty `Graph`.
impl<const DIRECTED: bool, S> Default for Graph<DIRECTED, S>
where
S: BuildHasher + Default,
{
fn default() -> Self {
Self::with_capacity(0, 0)
}
}
impl<S: BuildHasher> DiGraph<S> {
/// Iterate over all *Strongly Connected Components* in this graph.
pub(crate) fn iter_sccs(&self) -> impl Iterator<Item = SmallVec<[NodeId; 4]>> + '_ {
super::tarjan_scc::new_tarjan_scc(self)
}
}
/// Edge direction.
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
#[repr(u8)]
pub enum Direction {
/// An `Outgoing` edge is an outward edge *from* the current node.
Outgoing = 0,
/// An `Incoming` edge is an inbound edge *to* the current node.
Incoming = 1,
}
impl Direction {
/// Return the opposite `Direction`.
#[inline]
pub fn opposite(self) -> Self {
match self {
Self::Outgoing => Self::Incoming,
Self::Incoming => Self::Outgoing,
}
}
}
/// Compact storage of a [`NodeId`] and a [`Direction`].
#[derive(Clone, Copy)]
struct CompactNodeIdAndDirection {
index: usize,
is_system: bool,
direction: Direction,
}
impl fmt::Debug for CompactNodeIdAndDirection {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.load().fmt(f)
}
}
impl CompactNodeIdAndDirection {
const fn store(node: NodeId, direction: Direction) -> Self {
let index = node.index();
let is_system = node.is_system();
Self {
index,
is_system,
direction,
}
}
const fn load(self) -> (NodeId, Direction) {
let Self {
index,
is_system,
direction,
} = self;
let node = match is_system {
true => NodeId::System(index),
false => NodeId::Set(index),
};
(node, direction)
}
}
/// Compact storage of a [`NodeId`] pair.
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
struct CompactNodeIdPair {
index_a: usize,
index_b: usize,
is_system_a: bool,
is_system_b: bool,
}
impl fmt::Debug for CompactNodeIdPair {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.load().fmt(f)
}
}
impl CompactNodeIdPair {
const fn store(a: NodeId, b: NodeId) -> Self {
let index_a = a.index();
let is_system_a = a.is_system();
let index_b = b.index();
let is_system_b = b.is_system();
Self {
index_a,
index_b,
is_system_a,
is_system_b,
}
}
const fn load(self) -> (NodeId, NodeId) {
let Self {
index_a,
index_b,
is_system_a,
is_system_b,
} = self;
let a = match is_system_a {
true => NodeId::System(index_a),
false => NodeId::Set(index_a),
};
let b = match is_system_b {
true => NodeId::System(index_b),
false => NodeId::Set(index_b),
};
(a, b)
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;
/// The `Graph` type _must_ preserve the order that nodes are inserted in if
/// no removals occur. Removals are permitted to swap the latest node into the
/// location of the removed node.
#[test]
fn node_order_preservation() {
use NodeId::System;
let mut graph = <DiGraph>::default();
graph.add_node(System(1));
graph.add_node(System(2));
graph.add_node(System(3));
graph.add_node(System(4));
assert_eq!(
graph.nodes().collect::<Vec<_>>(),
vec![System(1), System(2), System(3), System(4)]
);
graph.remove_node(System(1));
assert_eq!(
graph.nodes().collect::<Vec<_>>(),
vec![System(4), System(2), System(3)]
);
graph.remove_node(System(4));
assert_eq!(
graph.nodes().collect::<Vec<_>>(),
vec![System(3), System(2)]
);
graph.remove_node(System(2));
assert_eq!(graph.nodes().collect::<Vec<_>>(), vec![System(3)]);
graph.remove_node(System(3));
assert_eq!(graph.nodes().collect::<Vec<_>>(), vec![]);
}
/// Nodes that have bidirectional edges (or any edge in the case of undirected graphs) are
/// considered strongly connected. A strongly connected component is a collection of
/// nodes where there exists a path from any node to any other node in the collection.
#[test]
fn strongly_connected_components() {
use NodeId::System;
let mut graph = <DiGraph>::default();
graph.add_edge(System(1), System(2));
graph.add_edge(System(2), System(1));
graph.add_edge(System(2), System(3));
graph.add_edge(System(3), System(2));
graph.add_edge(System(4), System(5));
graph.add_edge(System(5), System(4));
graph.add_edge(System(6), System(2));
let sccs = graph
.iter_sccs()
.map(|scc| scc.to_vec())
.collect::<Vec<_>>();
assert_eq!(
sccs,
vec![
vec![System(3), System(2), System(1)],
vec![System(5), System(4)],
vec![System(6)]
]
);
}
}

View File

@@ -0,0 +1,331 @@
use alloc::{boxed::Box, vec, vec::Vec};
use core::{
any::{Any, TypeId},
fmt::Debug,
};
use smallvec::SmallVec;
use bevy_platform::collections::{HashMap, HashSet};
use bevy_utils::TypeIdMap;
use fixedbitset::FixedBitSet;
use crate::schedule::set::*;
mod graph_map;
mod node;
mod tarjan_scc;
pub use graph_map::{DiGraph, Direction, UnGraph};
pub use node::NodeId;
/// Specifies what kind of edge should be added to the dependency graph.
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub(crate) enum DependencyKind {
/// A node that should be preceded.
Before,
/// A node that should be succeeded.
After,
}
/// An edge to be added to the dependency graph.
pub(crate) struct Dependency {
pub(crate) kind: DependencyKind,
pub(crate) set: InternedSystemSet,
pub(crate) options: TypeIdMap<Box<dyn Any>>,
}
impl Dependency {
pub fn new(kind: DependencyKind, set: InternedSystemSet) -> Self {
Self {
kind,
set,
options: Default::default(),
}
}
pub fn add_config<T: 'static>(mut self, option: T) -> Self {
self.options.insert(TypeId::of::<T>(), Box::new(option));
self
}
}
/// Configures ambiguity detection for a single system.
#[derive(Clone, Debug, Default)]
pub(crate) enum Ambiguity {
#[default]
Check,
/// Ignore warnings with systems in any of these system sets. May contain duplicates.
IgnoreWithSet(Vec<InternedSystemSet>),
/// Ignore all warnings.
IgnoreAll,
}
/// Metadata about how the node fits in the schedule graph
#[derive(Default)]
pub struct GraphInfo {
/// the sets that the node belongs to (hierarchy)
pub(crate) hierarchy: Vec<InternedSystemSet>,
/// the sets that the node depends on (must run before or after)
pub(crate) dependencies: Vec<Dependency>,
pub(crate) ambiguous_with: Ambiguity,
}
/// Converts 2D row-major pair of indices into a 1D array index.
pub(crate) fn index(row: usize, col: usize, num_cols: usize) -> usize {
debug_assert!(col < num_cols);
(row * num_cols) + col
}
/// Converts a 1D array index into a 2D row-major pair of indices.
pub(crate) fn row_col(index: usize, num_cols: usize) -> (usize, usize) {
(index / num_cols, index % num_cols)
}
/// Stores the results of the graph analysis.
pub(crate) struct CheckGraphResults {
/// Boolean reachability matrix for the graph.
pub(crate) reachable: FixedBitSet,
/// Pairs of nodes that have a path connecting them.
pub(crate) connected: HashSet<(NodeId, NodeId)>,
/// Pairs of nodes that don't have a path connecting them.
pub(crate) disconnected: Vec<(NodeId, NodeId)>,
/// Edges that are redundant because a longer path exists.
pub(crate) transitive_edges: Vec<(NodeId, NodeId)>,
/// Variant of the graph with no transitive edges.
pub(crate) transitive_reduction: DiGraph,
/// Variant of the graph with all possible transitive edges.
// TODO: this will very likely be used by "if-needed" ordering
#[expect(dead_code, reason = "See the TODO above this attribute.")]
pub(crate) transitive_closure: DiGraph,
}
impl Default for CheckGraphResults {
fn default() -> Self {
Self {
reachable: FixedBitSet::new(),
connected: HashSet::default(),
disconnected: Vec::new(),
transitive_edges: Vec::new(),
transitive_reduction: DiGraph::default(),
transitive_closure: DiGraph::default(),
}
}
}
/// Processes a DAG and computes its:
/// - transitive reduction (along with the set of removed edges)
/// - transitive closure
/// - reachability matrix (as a bitset)
/// - pairs of nodes connected by a path
/// - pairs of nodes not connected by a path
///
/// The algorithm implemented comes from
/// ["On the calculation of transitive reduction-closure of orders"][1] by Habib, Morvan and Rampon.
///
/// [1]: https://doi.org/10.1016/0012-365X(93)90164-O
pub(crate) fn check_graph(graph: &DiGraph, topological_order: &[NodeId]) -> CheckGraphResults {
if graph.node_count() == 0 {
return CheckGraphResults::default();
}
let n = graph.node_count();
// build a copy of the graph where the nodes and edges appear in topsorted order
let mut map = <HashMap<_, _>>::with_capacity_and_hasher(n, Default::default());
let mut topsorted = <DiGraph>::default();
// iterate nodes in topological order
for (i, &node) in topological_order.iter().enumerate() {
map.insert(node, i);
topsorted.add_node(node);
// insert nodes as successors to their predecessors
for pred in graph.neighbors_directed(node, Direction::Incoming) {
topsorted.add_edge(pred, node);
}
}
let mut reachable = FixedBitSet::with_capacity(n * n);
let mut connected = <HashSet<_>>::default();
let mut disconnected = Vec::new();
let mut transitive_edges = Vec::new();
let mut transitive_reduction = DiGraph::default();
let mut transitive_closure = DiGraph::default();
let mut visited = FixedBitSet::with_capacity(n);
// iterate nodes in topological order
for node in topsorted.nodes() {
transitive_reduction.add_node(node);
transitive_closure.add_node(node);
}
// iterate nodes in reverse topological order
for a in topsorted.nodes().rev() {
let index_a = *map.get(&a).unwrap();
// iterate their successors in topological order
for b in topsorted.neighbors_directed(a, Direction::Outgoing) {
let index_b = *map.get(&b).unwrap();
debug_assert!(index_a < index_b);
if !visited[index_b] {
// edge <a, b> is not redundant
transitive_reduction.add_edge(a, b);
transitive_closure.add_edge(a, b);
reachable.insert(index(index_a, index_b, n));
let successors = transitive_closure
.neighbors_directed(b, Direction::Outgoing)
.collect::<Vec<_>>();
for c in successors {
let index_c = *map.get(&c).unwrap();
debug_assert!(index_b < index_c);
if !visited[index_c] {
visited.insert(index_c);
transitive_closure.add_edge(a, c);
reachable.insert(index(index_a, index_c, n));
}
}
} else {
// edge <a, b> is redundant
transitive_edges.push((a, b));
}
}
visited.clear();
}
// partition pairs of nodes into "connected by path" and "not connected by path"
for i in 0..(n - 1) {
// reachable is upper triangular because the nodes were topsorted
for index in index(i, i + 1, n)..=index(i, n - 1, n) {
let (a, b) = row_col(index, n);
let pair = (topological_order[a], topological_order[b]);
if reachable[index] {
connected.insert(pair);
} else {
disconnected.push(pair);
}
}
}
// fill diagonal (nodes reach themselves)
// for i in 0..n {
// reachable.set(index(i, i, n), true);
// }
CheckGraphResults {
reachable,
connected,
disconnected,
transitive_edges,
transitive_reduction,
transitive_closure,
}
}
/// Returns the simple cycles in a strongly-connected component of a directed graph.
///
/// The algorithm implemented comes from
/// ["Finding all the elementary circuits of a directed graph"][1] by D. B. Johnson.
///
/// [1]: https://doi.org/10.1137/0204007
pub fn simple_cycles_in_component(graph: &DiGraph, scc: &[NodeId]) -> Vec<Vec<NodeId>> {
let mut cycles = vec![];
let mut sccs = vec![SmallVec::from_slice(scc)];
while let Some(mut scc) = sccs.pop() {
// only look at nodes and edges in this strongly-connected component
let mut subgraph = <DiGraph>::default();
for &node in &scc {
subgraph.add_node(node);
}
for &node in &scc {
for successor in graph.neighbors(node) {
if subgraph.contains_node(successor) {
subgraph.add_edge(node, successor);
}
}
}
// path of nodes that may form a cycle
let mut path = Vec::with_capacity(subgraph.node_count());
// we mark nodes as "blocked" to avoid finding permutations of the same cycles
let mut blocked: HashSet<_> =
HashSet::with_capacity_and_hasher(subgraph.node_count(), Default::default());
// connects nodes along path segments that can't be part of a cycle (given current root)
// those nodes can be unblocked at the same time
let mut unblock_together: HashMap<NodeId, HashSet<NodeId>> =
HashMap::with_capacity_and_hasher(subgraph.node_count(), Default::default());
// stack for unblocking nodes
let mut unblock_stack = Vec::with_capacity(subgraph.node_count());
// nodes can be involved in multiple cycles
let mut maybe_in_more_cycles: HashSet<NodeId> =
HashSet::with_capacity_and_hasher(subgraph.node_count(), Default::default());
// stack for DFS
let mut stack = Vec::with_capacity(subgraph.node_count());
// we're going to look for all cycles that begin and end at this node
let root = scc.pop().unwrap();
// start a path at the root
path.clear();
path.push(root);
// mark this node as blocked
blocked.insert(root);
// DFS
stack.clear();
stack.push((root, subgraph.neighbors(root)));
while !stack.is_empty() {
let &mut (ref node, ref mut successors) = stack.last_mut().unwrap();
if let Some(next) = successors.next() {
if next == root {
// found a cycle
maybe_in_more_cycles.extend(path.iter());
cycles.push(path.clone());
} else if !blocked.contains(&next) {
// first time seeing `next` on this path
maybe_in_more_cycles.remove(&next);
path.push(next);
blocked.insert(next);
stack.push((next, subgraph.neighbors(next)));
continue;
} else {
// not first time seeing `next` on this path
}
}
if successors.peekable().peek().is_none() {
if maybe_in_more_cycles.contains(node) {
unblock_stack.push(*node);
// unblock this node's ancestors
while let Some(n) = unblock_stack.pop() {
if blocked.remove(&n) {
let unblock_predecessors = unblock_together.entry(n).or_default();
unblock_stack.extend(unblock_predecessors.iter());
unblock_predecessors.clear();
}
}
} else {
// if its descendants can be unblocked later, this node will be too
for successor in subgraph.neighbors(*node) {
unblock_together.entry(successor).or_default().insert(*node);
}
}
// remove node from path and DFS stack
path.pop();
stack.pop();
}
}
drop(stack);
// remove node from subgraph
subgraph.remove_node(root);
// divide remainder into smaller SCCs
sccs.extend(subgraph.iter_sccs().filter(|scc| scc.len() > 1));
}
cycles
}

View File

@@ -0,0 +1,47 @@
use core::fmt::Debug;
/// Unique identifier for a system or system set stored in a [`ScheduleGraph`].
///
/// [`ScheduleGraph`]: crate::schedule::ScheduleGraph
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum NodeId {
/// Identifier for a system.
System(usize),
/// Identifier for a system set.
Set(usize),
}
impl NodeId {
/// Returns the internal integer value.
pub const fn index(&self) -> usize {
match self {
NodeId::System(index) | NodeId::Set(index) => *index,
}
}
/// Returns `true` if the identified node is a system.
pub const fn is_system(&self) -> bool {
matches!(self, NodeId::System(_))
}
/// Returns `true` if the identified node is a system set.
pub const fn is_set(&self) -> bool {
matches!(self, NodeId::Set(_))
}
/// Compare this [`NodeId`] with another.
pub const fn cmp(&self, other: &Self) -> core::cmp::Ordering {
use core::cmp::Ordering::{Equal, Greater, Less};
use NodeId::{Set, System};
match (self, other) {
(System(a), System(b)) | (Set(a), Set(b)) => match a.checked_sub(*b) {
None => Less,
Some(0) => Equal,
Some(_) => Greater,
},
(System(_), Set(_)) => Less,
(Set(_), System(_)) => Greater,
}
}
}

View File

@@ -0,0 +1,223 @@
use super::DiGraph;
use super::NodeId;
use alloc::vec::Vec;
use core::hash::BuildHasher;
use core::num::NonZeroUsize;
use smallvec::SmallVec;
/// Create an iterator over *strongly connected components* using Algorithm 3 in
/// [A Space-Efficient Algorithm for Finding Strongly Connected Components][1] by David J. Pierce,
/// which is a memory-efficient variation of [Tarjan's algorithm][2].
///
///
/// [1]: https://homepages.ecs.vuw.ac.nz/~djp/files/P05.pdf
/// [2]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
///
/// Returns each strongly strongly connected component (scc).
/// The order of node ids within each scc is arbitrary, but the order of
/// the sccs is their postorder (reverse topological sort).
pub(crate) fn new_tarjan_scc<S: BuildHasher>(
graph: &DiGraph<S>,
) -> impl Iterator<Item = SmallVec<[NodeId; 4]>> + '_ {
// Create a list of all nodes we need to visit.
let unchecked_nodes = graph.nodes();
// For each node we need to visit, we also need to visit its neighbors.
// Storing the iterator for each set of neighbors allows this list to be computed without
// an additional allocation.
let nodes = graph
.nodes()
.map(|node| NodeData {
root_index: None,
neighbors: graph.neighbors(node),
})
.collect::<Vec<_>>();
TarjanScc {
graph,
unchecked_nodes,
index: 1, // Invariant: index < component_count at all times.
component_count: usize::MAX, // Will hold if component_count is initialized to number of nodes - 1 or higher.
nodes,
stack: Vec::new(),
visitation_stack: Vec::new(),
start: None,
index_adjustment: None,
}
}
struct NodeData<N: Iterator<Item = NodeId>> {
root_index: Option<NonZeroUsize>,
neighbors: N,
}
/// A state for computing the *strongly connected components* using [Tarjan's algorithm][1].
///
/// This is based on [`TarjanScc`] from [`petgraph`].
///
/// [1]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
/// [`petgraph`]: https://docs.rs/petgraph/0.6.5/petgraph/
/// [`TarjanScc`]: https://docs.rs/petgraph/0.6.5/petgraph/algo/struct.TarjanScc.html
struct TarjanScc<'graph, Hasher, AllNodes, Neighbors>
where
Hasher: BuildHasher,
AllNodes: Iterator<Item = NodeId>,
Neighbors: Iterator<Item = NodeId>,
{
/// Source of truth [`DiGraph`]
graph: &'graph DiGraph<Hasher>,
/// An [`Iterator`] of [`NodeId`]s from the `graph` which may not have been visited yet.
unchecked_nodes: AllNodes,
/// The index of the next SCC
index: usize,
/// A count of potentially remaining SCCs
component_count: usize,
/// Information about each [`NodeId`], including a possible SCC index and an
/// [`Iterator`] of possibly unvisited neighbors.
nodes: Vec<NodeData<Neighbors>>,
/// A stack of [`NodeId`]s where a SCC will be found starting at the top of the stack.
stack: Vec<NodeId>,
/// A stack of [`NodeId`]s which need to be visited to determine which SCC they belong to.
visitation_stack: Vec<(NodeId, bool)>,
/// An index into the `stack` indicating the starting point of a SCC.
start: Option<usize>,
/// An adjustment to the `index` which will be applied once the current SCC is found.
index_adjustment: Option<usize>,
}
impl<'graph, S: BuildHasher, A: Iterator<Item = NodeId>, N: Iterator<Item = NodeId>>
TarjanScc<'graph, S, A, N>
{
/// Compute the next *strongly connected component* using Algorithm 3 in
/// [A Space-Efficient Algorithm for Finding Strongly Connected Components][1] by David J. Pierce,
/// which is a memory-efficient variation of [Tarjan's algorithm][2].
///
///
/// [1]: https://homepages.ecs.vuw.ac.nz/~djp/files/P05.pdf
/// [2]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
///
/// Returns `Some` for each strongly strongly connected component (scc).
/// The order of node ids within each scc is arbitrary, but the order of
/// the sccs is their postorder (reverse topological sort).
fn next_scc(&mut self) -> Option<&[NodeId]> {
// Cleanup from possible previous iteration
if let (Some(start), Some(index_adjustment)) =
(self.start.take(), self.index_adjustment.take())
{
self.stack.truncate(start);
self.index -= index_adjustment; // Backtrack index back to where it was before we ever encountered the component.
self.component_count -= 1;
}
loop {
// If there are items on the visitation stack, then we haven't finished visiting
// the node at the bottom of the stack yet.
// Must visit all nodes in the stack from top to bottom before visiting the next node.
while let Some((v, v_is_local_root)) = self.visitation_stack.pop() {
// If this visitation finds a complete SCC, return it immediately.
if let Some(start) = self.visit_once(v, v_is_local_root) {
return Some(&self.stack[start..]);
};
}
// Get the next node to check, otherwise we're done and can return None.
let Some(node) = self.unchecked_nodes.next() else {
break None;
};
let visited = self.nodes[self.graph.to_index(node)].root_index.is_some();
// If this node hasn't already been visited (e.g., it was the neighbor of a previously checked node)
// add it to the visitation stack.
if !visited {
self.visitation_stack.push((node, true));
}
}
}
/// Attempt to find the starting point on the stack for a new SCC without visiting neighbors.
/// If a visitation is required, this will return `None` and mark the required neighbor and the
/// current node as in need of visitation again.
/// If no SCC can be found in the current visitation stack, returns `None`.
fn visit_once(&mut self, v: NodeId, mut v_is_local_root: bool) -> Option<usize> {
let node_v = &mut self.nodes[self.graph.to_index(v)];
if node_v.root_index.is_none() {
let v_index = self.index;
node_v.root_index = NonZeroUsize::new(v_index);
self.index += 1;
}
while let Some(w) = self.nodes[self.graph.to_index(v)].neighbors.next() {
// If a neighbor hasn't been visited yet...
if self.nodes[self.graph.to_index(w)].root_index.is_none() {
// Push the current node and the neighbor back onto the visitation stack.
// On the next execution of `visit_once`, the neighbor will be visited.
self.visitation_stack.push((v, v_is_local_root));
self.visitation_stack.push((w, true));
return None;
}
if self.nodes[self.graph.to_index(w)].root_index
< self.nodes[self.graph.to_index(v)].root_index
{
self.nodes[self.graph.to_index(v)].root_index =
self.nodes[self.graph.to_index(w)].root_index;
v_is_local_root = false;
}
}
if !v_is_local_root {
self.stack.push(v); // Stack is filled up when backtracking, unlike in Tarjans original algorithm.
return None;
}
// Pop the stack and generate an SCC.
let mut index_adjustment = 1;
let c = NonZeroUsize::new(self.component_count);
let nodes = &mut self.nodes;
let start = self
.stack
.iter()
.rposition(|&w| {
if nodes[self.graph.to_index(v)].root_index
> nodes[self.graph.to_index(w)].root_index
{
true
} else {
nodes[self.graph.to_index(w)].root_index = c;
index_adjustment += 1;
false
}
})
.map(|x| x + 1)
.unwrap_or_default();
nodes[self.graph.to_index(v)].root_index = c;
self.stack.push(v); // Pushing the component root to the back right before getting rid of it is somewhat ugly, but it lets it be included in f.
self.start = Some(start);
self.index_adjustment = Some(index_adjustment);
Some(start)
}
}
impl<'graph, S: BuildHasher, A: Iterator<Item = NodeId>, N: Iterator<Item = NodeId>> Iterator
for TarjanScc<'graph, S, A, N>
{
// It is expected that the `DiGraph` is sparse, and as such wont have many large SCCs.
// Returning a `SmallVec` allows this iterator to skip allocation in cases where that
// assumption holds.
type Item = SmallVec<[NodeId; 4]>;
fn next(&mut self) -> Option<Self::Item> {
let next = SmallVec::from_slice(self.next_scc()?);
Some(next)
}
fn size_hint(&self) -> (usize, Option<usize>) {
// There can be no more than the number of nodes in a graph worth of SCCs
(0, Some(self.nodes.len()))
}
}

1256
vendor/bevy_ecs/src/schedule/mod.rs vendored Normal file

File diff suppressed because it is too large Load Diff

79
vendor/bevy_ecs/src/schedule/pass.rs vendored Normal file
View File

@@ -0,0 +1,79 @@
use alloc::{boxed::Box, vec::Vec};
use core::any::{Any, TypeId};
use super::{DiGraph, NodeId, ScheduleBuildError, ScheduleGraph};
use crate::world::World;
use bevy_utils::TypeIdMap;
use core::fmt::Debug;
/// A pass for modular modification of the dependency graph.
pub trait ScheduleBuildPass: Send + Sync + Debug + 'static {
/// Custom options for dependencies between sets or systems.
type EdgeOptions: 'static;
/// Called when a dependency between sets or systems was explicitly added to the graph.
fn add_dependency(&mut self, from: NodeId, to: NodeId, options: Option<&Self::EdgeOptions>);
/// Called while flattening the dependency graph. For each `set`, this method is called
/// with the `systems` associated with the set as well as an immutable reference to the current graph.
/// Instead of modifying the graph directly, this method should return an iterator of edges to add to the graph.
fn collapse_set(
&mut self,
set: NodeId,
systems: &[NodeId],
dependency_flattened: &DiGraph,
) -> impl Iterator<Item = (NodeId, NodeId)>;
/// The implementation will be able to modify the `ScheduleGraph` here.
fn build(
&mut self,
world: &mut World,
graph: &mut ScheduleGraph,
dependency_flattened: &mut DiGraph,
) -> Result<(), ScheduleBuildError>;
}
/// Object safe version of [`ScheduleBuildPass`].
pub(super) trait ScheduleBuildPassObj: Send + Sync + Debug {
fn build(
&mut self,
world: &mut World,
graph: &mut ScheduleGraph,
dependency_flattened: &mut DiGraph,
) -> Result<(), ScheduleBuildError>;
fn collapse_set(
&mut self,
set: NodeId,
systems: &[NodeId],
dependency_flattened: &DiGraph,
dependencies_to_add: &mut Vec<(NodeId, NodeId)>,
);
fn add_dependency(&mut self, from: NodeId, to: NodeId, all_options: &TypeIdMap<Box<dyn Any>>);
}
impl<T: ScheduleBuildPass> ScheduleBuildPassObj for T {
fn build(
&mut self,
world: &mut World,
graph: &mut ScheduleGraph,
dependency_flattened: &mut DiGraph,
) -> Result<(), ScheduleBuildError> {
self.build(world, graph, dependency_flattened)
}
fn collapse_set(
&mut self,
set: NodeId,
systems: &[NodeId],
dependency_flattened: &DiGraph,
dependencies_to_add: &mut Vec<(NodeId, NodeId)>,
) {
let iter = self.collapse_set(set, systems, dependency_flattened);
dependencies_to_add.extend(iter);
}
fn add_dependency(&mut self, from: NodeId, to: NodeId, all_options: &TypeIdMap<Box<dyn Any>>) {
let option = all_options
.get(&TypeId::of::<T::EdgeOptions>())
.and_then(|x| x.downcast_ref::<T::EdgeOptions>());
self.add_dependency(from, to, option);
}
}

2864
vendor/bevy_ecs/src/schedule/schedule.rs vendored Normal file

File diff suppressed because it is too large Load Diff

448
vendor/bevy_ecs/src/schedule/set.rs vendored Normal file
View File

@@ -0,0 +1,448 @@
use alloc::boxed::Box;
use core::{
any::TypeId,
fmt::Debug,
hash::{Hash, Hasher},
marker::PhantomData,
};
pub use crate::label::DynEq;
pub use bevy_ecs_macros::{ScheduleLabel, SystemSet};
use crate::{
define_label,
intern::Interned,
system::{
ExclusiveFunctionSystem, ExclusiveSystemParamFunction, FunctionSystem,
IsExclusiveFunctionSystem, IsFunctionSystem, SystemParamFunction,
},
};
define_label!(
/// A strongly-typed class of labels used to identify a [`Schedule`](crate::schedule::Schedule).
#[diagnostic::on_unimplemented(
note = "consider annotating `{Self}` with `#[derive(ScheduleLabel)]`"
)]
ScheduleLabel,
SCHEDULE_LABEL_INTERNER
);
define_label!(
/// Types that identify logical groups of systems.
#[diagnostic::on_unimplemented(
note = "consider annotating `{Self}` with `#[derive(SystemSet)]`"
)]
SystemSet,
SYSTEM_SET_INTERNER,
extra_methods: {
/// Returns `Some` if this system set is a [`SystemTypeSet`].
fn system_type(&self) -> Option<TypeId> {
None
}
/// Returns `true` if this system set is an [`AnonymousSet`].
fn is_anonymous(&self) -> bool {
false
}
},
extra_methods_impl: {
fn system_type(&self) -> Option<TypeId> {
(**self).system_type()
}
fn is_anonymous(&self) -> bool {
(**self).is_anonymous()
}
}
);
/// A shorthand for `Interned<dyn SystemSet>`.
pub type InternedSystemSet = Interned<dyn SystemSet>;
/// A shorthand for `Interned<dyn ScheduleLabel>`.
pub type InternedScheduleLabel = Interned<dyn ScheduleLabel>;
/// A [`SystemSet`] grouping instances of the same function.
///
/// This kind of set is automatically populated and thus has some special rules:
/// - You cannot manually add members.
/// - You cannot configure them.
/// - You cannot order something relative to one if it has more than one member.
pub struct SystemTypeSet<T: 'static>(PhantomData<fn() -> T>);
impl<T: 'static> SystemTypeSet<T> {
pub(crate) fn new() -> Self {
Self(PhantomData)
}
}
impl<T> Debug for SystemTypeSet<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("SystemTypeSet")
.field(&format_args!("fn {}()", &core::any::type_name::<T>()))
.finish()
}
}
impl<T> Hash for SystemTypeSet<T> {
fn hash<H: Hasher>(&self, _state: &mut H) {
// all systems of a given type are the same
}
}
impl<T> Clone for SystemTypeSet<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for SystemTypeSet<T> {}
impl<T> PartialEq for SystemTypeSet<T> {
#[inline]
fn eq(&self, _other: &Self) -> bool {
// all systems of a given type are the same
true
}
}
impl<T> Eq for SystemTypeSet<T> {}
impl<T> SystemSet for SystemTypeSet<T> {
fn system_type(&self) -> Option<TypeId> {
Some(TypeId::of::<T>())
}
fn dyn_clone(&self) -> Box<dyn SystemSet> {
Box::new(*self)
}
fn as_dyn_eq(&self) -> &dyn DynEq {
self
}
fn dyn_hash(&self, mut state: &mut dyn Hasher) {
TypeId::of::<Self>().hash(&mut state);
self.hash(&mut state);
}
}
/// A [`SystemSet`] implicitly created when using
/// [`Schedule::add_systems`](super::Schedule::add_systems) or
/// [`Schedule::configure_sets`](super::Schedule::configure_sets).
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub struct AnonymousSet(usize);
impl AnonymousSet {
pub(crate) fn new(id: usize) -> Self {
Self(id)
}
}
impl SystemSet for AnonymousSet {
fn is_anonymous(&self) -> bool {
true
}
fn dyn_clone(&self) -> Box<dyn SystemSet> {
Box::new(*self)
}
fn as_dyn_eq(&self) -> &dyn DynEq {
self
}
fn dyn_hash(&self, mut state: &mut dyn Hasher) {
TypeId::of::<Self>().hash(&mut state);
self.hash(&mut state);
}
}
/// Types that can be converted into a [`SystemSet`].
///
/// # Usage notes
///
/// This trait should only be used as a bound for trait implementations or as an
/// argument to a function. If a system set needs to be returned from a function
/// or stored somewhere, use [`SystemSet`] instead of this trait.
#[diagnostic::on_unimplemented(
message = "`{Self}` is not a system set",
label = "invalid system set"
)]
pub trait IntoSystemSet<Marker>: Sized {
/// The type of [`SystemSet`] this instance converts into.
type Set: SystemSet;
/// Converts this instance to its associated [`SystemSet`] type.
fn into_system_set(self) -> Self::Set;
}
// systems sets
impl<S: SystemSet> IntoSystemSet<()> for S {
type Set = Self;
#[inline]
fn into_system_set(self) -> Self::Set {
self
}
}
// systems
impl<Marker, F> IntoSystemSet<(IsFunctionSystem, Marker)> for F
where
Marker: 'static,
F: SystemParamFunction<Marker>,
{
type Set = SystemTypeSet<FunctionSystem<Marker, F>>;
#[inline]
fn into_system_set(self) -> Self::Set {
SystemTypeSet::<FunctionSystem<Marker, F>>::new()
}
}
// exclusive systems
impl<Marker, F> IntoSystemSet<(IsExclusiveFunctionSystem, Marker)> for F
where
Marker: 'static,
F: ExclusiveSystemParamFunction<Marker>,
{
type Set = SystemTypeSet<ExclusiveFunctionSystem<Marker, F>>;
#[inline]
fn into_system_set(self) -> Self::Set {
SystemTypeSet::<ExclusiveFunctionSystem<Marker, F>>::new()
}
}
#[cfg(test)]
mod tests {
use crate::{
resource::Resource,
schedule::{tests::ResMut, Schedule},
};
use super::*;
#[test]
fn test_schedule_label() {
use crate::world::World;
#[derive(Resource)]
struct Flag(bool);
#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct A;
#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct B;
let mut world = World::new();
let mut schedule = Schedule::new(A);
schedule.add_systems(|mut flag: ResMut<Flag>| flag.0 = true);
world.add_schedule(schedule);
let interned = A.intern();
world.insert_resource(Flag(false));
world.run_schedule(interned);
assert!(world.resource::<Flag>().0);
world.insert_resource(Flag(false));
world.run_schedule(interned);
assert!(world.resource::<Flag>().0);
assert_ne!(A.intern(), B.intern());
}
#[test]
fn test_derive_schedule_label() {
#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct UnitLabel;
#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct TupleLabel(u32, u32);
#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct StructLabel {
a: u32,
b: u32,
}
#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct EmptyTupleLabel();
#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct EmptyStructLabel {}
#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
enum EnumLabel {
#[default]
Unit,
Tuple(u32, u32),
Struct {
a: u32,
b: u32,
},
}
#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct GenericLabel<T>(PhantomData<T>);
assert_eq!(UnitLabel.intern(), UnitLabel.intern());
assert_eq!(EnumLabel::Unit.intern(), EnumLabel::Unit.intern());
assert_ne!(UnitLabel.intern(), EnumLabel::Unit.intern());
assert_ne!(UnitLabel.intern(), TupleLabel(0, 0).intern());
assert_ne!(EnumLabel::Unit.intern(), EnumLabel::Tuple(0, 0).intern());
assert_eq!(TupleLabel(0, 0).intern(), TupleLabel(0, 0).intern());
assert_eq!(
EnumLabel::Tuple(0, 0).intern(),
EnumLabel::Tuple(0, 0).intern()
);
assert_ne!(TupleLabel(0, 0).intern(), TupleLabel(0, 1).intern());
assert_ne!(
EnumLabel::Tuple(0, 0).intern(),
EnumLabel::Tuple(0, 1).intern()
);
assert_ne!(TupleLabel(0, 0).intern(), EnumLabel::Tuple(0, 0).intern());
assert_ne!(
TupleLabel(0, 0).intern(),
StructLabel { a: 0, b: 0 }.intern()
);
assert_ne!(
EnumLabel::Tuple(0, 0).intern(),
EnumLabel::Struct { a: 0, b: 0 }.intern()
);
assert_eq!(
StructLabel { a: 0, b: 0 }.intern(),
StructLabel { a: 0, b: 0 }.intern()
);
assert_eq!(
EnumLabel::Struct { a: 0, b: 0 }.intern(),
EnumLabel::Struct { a: 0, b: 0 }.intern()
);
assert_ne!(
StructLabel { a: 0, b: 0 }.intern(),
StructLabel { a: 0, b: 1 }.intern()
);
assert_ne!(
EnumLabel::Struct { a: 0, b: 0 }.intern(),
EnumLabel::Struct { a: 0, b: 1 }.intern()
);
assert_ne!(
StructLabel { a: 0, b: 0 }.intern(),
EnumLabel::Struct { a: 0, b: 0 }.intern()
);
assert_ne!(
StructLabel { a: 0, b: 0 }.intern(),
EnumLabel::Struct { a: 0, b: 0 }.intern()
);
assert_ne!(StructLabel { a: 0, b: 0 }.intern(), UnitLabel.intern(),);
assert_ne!(
EnumLabel::Struct { a: 0, b: 0 }.intern(),
EnumLabel::Unit.intern()
);
assert_eq!(
GenericLabel::<u32>(PhantomData).intern(),
GenericLabel::<u32>(PhantomData).intern()
);
assert_ne!(
GenericLabel::<u32>(PhantomData).intern(),
GenericLabel::<u64>(PhantomData).intern()
);
}
#[test]
fn test_derive_system_set() {
#[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct UnitSet;
#[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct TupleSet(u32, u32);
#[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct StructSet {
a: u32,
b: u32,
}
#[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct EmptyTupleSet();
#[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct EmptyStructSet {}
#[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
enum EnumSet {
#[default]
Unit,
Tuple(u32, u32),
Struct {
a: u32,
b: u32,
},
}
#[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct GenericSet<T>(PhantomData<T>);
assert_eq!(UnitSet.intern(), UnitSet.intern());
assert_eq!(EnumSet::Unit.intern(), EnumSet::Unit.intern());
assert_ne!(UnitSet.intern(), EnumSet::Unit.intern());
assert_ne!(UnitSet.intern(), TupleSet(0, 0).intern());
assert_ne!(EnumSet::Unit.intern(), EnumSet::Tuple(0, 0).intern());
assert_eq!(TupleSet(0, 0).intern(), TupleSet(0, 0).intern());
assert_eq!(EnumSet::Tuple(0, 0).intern(), EnumSet::Tuple(0, 0).intern());
assert_ne!(TupleSet(0, 0).intern(), TupleSet(0, 1).intern());
assert_ne!(EnumSet::Tuple(0, 0).intern(), EnumSet::Tuple(0, 1).intern());
assert_ne!(TupleSet(0, 0).intern(), EnumSet::Tuple(0, 0).intern());
assert_ne!(TupleSet(0, 0).intern(), StructSet { a: 0, b: 0 }.intern());
assert_ne!(
EnumSet::Tuple(0, 0).intern(),
EnumSet::Struct { a: 0, b: 0 }.intern()
);
assert_eq!(
StructSet { a: 0, b: 0 }.intern(),
StructSet { a: 0, b: 0 }.intern()
);
assert_eq!(
EnumSet::Struct { a: 0, b: 0 }.intern(),
EnumSet::Struct { a: 0, b: 0 }.intern()
);
assert_ne!(
StructSet { a: 0, b: 0 }.intern(),
StructSet { a: 0, b: 1 }.intern()
);
assert_ne!(
EnumSet::Struct { a: 0, b: 0 }.intern(),
EnumSet::Struct { a: 0, b: 1 }.intern()
);
assert_ne!(
StructSet { a: 0, b: 0 }.intern(),
EnumSet::Struct { a: 0, b: 0 }.intern()
);
assert_ne!(
StructSet { a: 0, b: 0 }.intern(),
EnumSet::Struct { a: 0, b: 0 }.intern()
);
assert_ne!(StructSet { a: 0, b: 0 }.intern(), UnitSet.intern(),);
assert_ne!(
EnumSet::Struct { a: 0, b: 0 }.intern(),
EnumSet::Unit.intern()
);
assert_eq!(
GenericSet::<u32>(PhantomData).intern(),
GenericSet::<u32>(PhantomData).intern()
);
assert_ne!(
GenericSet::<u32>(PhantomData).intern(),
GenericSet::<u64>(PhantomData).intern()
);
}
}

1560
vendor/bevy_ecs/src/schedule/stepping.rs vendored Normal file

File diff suppressed because it is too large Load Diff

361
vendor/bevy_ecs/src/spawn.rs vendored Normal file
View File

@@ -0,0 +1,361 @@
//! Entity spawning abstractions, largely focused on spawning related hierarchies of entities. See [`related`](crate::related) and [`SpawnRelated`]
//! for the best entry points into these APIs and examples of how to use them.
use crate::{
bundle::{Bundle, BundleEffect, DynamicBundle, NoBundleEffect},
entity::Entity,
relationship::{RelatedSpawner, Relationship, RelationshipTarget},
world::{EntityWorldMut, World},
};
use alloc::vec::Vec;
use core::marker::PhantomData;
use variadics_please::all_tuples;
/// A wrapper over a [`Bundle`] indicating that an entity should be spawned with that [`Bundle`].
/// This is intended to be used for hierarchical spawning via traits like [`SpawnableList`] and [`SpawnRelated`].
///
/// Also see the [`children`](crate::children) and [`related`](crate::related) macros that abstract over the [`Spawn`] API.
///
/// ```
/// # use bevy_ecs::hierarchy::Children;
/// # use bevy_ecs::spawn::{Spawn, SpawnRelated};
/// # use bevy_ecs::name::Name;
/// # use bevy_ecs::world::World;
/// let mut world = World::new();
/// world.spawn((
/// Name::new("Root"),
/// Children::spawn((
/// Spawn(Name::new("Child1")),
/// Spawn((
/// Name::new("Child2"),
/// Children::spawn(Spawn(Name::new("Grandchild"))),
/// ))
/// )),
/// ));
/// ```
pub struct Spawn<B: Bundle>(pub B);
/// A spawn-able list of changes to a given [`World`] and relative to a given [`Entity`]. This is generally used
/// for spawning "related" entities, such as children.
pub trait SpawnableList<R> {
/// Spawn this list of changes in a given [`World`] and relative to a given [`Entity`]. This is generally used
/// for spawning "related" entities, such as children.
fn spawn(self, world: &mut World, entity: Entity);
/// Returns a size hint, which is used to reserve space for this list in a [`RelationshipTarget`]. This should be
/// less than or equal to the actual size of the list. When in doubt, just use 0.
fn size_hint(&self) -> usize;
}
impl<R: Relationship, B: Bundle<Effect: NoBundleEffect>> SpawnableList<R> for Vec<B> {
fn spawn(self, world: &mut World, entity: Entity) {
let mapped_bundles = self.into_iter().map(|b| (R::from(entity), b));
world.spawn_batch(mapped_bundles);
}
fn size_hint(&self) -> usize {
self.len()
}
}
impl<R: Relationship, B: Bundle> SpawnableList<R> for Spawn<B> {
fn spawn(self, world: &mut World, entity: Entity) {
world.spawn((R::from(entity), self.0));
}
fn size_hint(&self) -> usize {
1
}
}
/// A [`SpawnableList`] that spawns entities using an iterator of a given [`Bundle`]:
///
/// ```
/// # use bevy_ecs::hierarchy::Children;
/// # use bevy_ecs::spawn::{Spawn, SpawnIter, SpawnRelated};
/// # use bevy_ecs::name::Name;
/// # use bevy_ecs::world::World;
/// let mut world = World::new();
/// world.spawn((
/// Name::new("Root"),
/// Children::spawn((
/// Spawn(Name::new("Child1")),
/// SpawnIter(["Child2", "Child3"].into_iter().map(Name::new)),
/// )),
/// ));
/// ```
pub struct SpawnIter<I>(pub I);
impl<R: Relationship, I: Iterator<Item = B> + Send + Sync + 'static, B: Bundle> SpawnableList<R>
for SpawnIter<I>
{
fn spawn(self, world: &mut World, entity: Entity) {
for bundle in self.0 {
world.spawn((R::from(entity), bundle));
}
}
fn size_hint(&self) -> usize {
self.0.size_hint().0
}
}
/// A [`SpawnableList`] that spawns entities using a [`FnOnce`] with a [`RelatedSpawner`] as an argument:
///
/// ```
/// # use bevy_ecs::hierarchy::{Children, ChildOf};
/// # use bevy_ecs::spawn::{Spawn, SpawnWith, SpawnRelated};
/// # use bevy_ecs::name::Name;
/// # use bevy_ecs::relationship::RelatedSpawner;
/// # use bevy_ecs::world::World;
/// let mut world = World::new();
/// world.spawn((
/// Name::new("Root"),
/// Children::spawn((
/// Spawn(Name::new("Child1")),
/// SpawnWith(|parent: &mut RelatedSpawner<ChildOf>| {
/// parent.spawn(Name::new("Child2"));
/// parent.spawn(Name::new("Child3"));
/// }),
/// )),
/// ));
/// ```
pub struct SpawnWith<F>(pub F);
impl<R: Relationship, F: FnOnce(&mut RelatedSpawner<R>) + Send + Sync + 'static> SpawnableList<R>
for SpawnWith<F>
{
fn spawn(self, world: &mut World, entity: Entity) {
world.entity_mut(entity).with_related_entities(self.0);
}
fn size_hint(&self) -> usize {
1
}
}
macro_rules! spawnable_list_impl {
($($list: ident),*) => {
#[expect(
clippy::allow_attributes,
reason = "This is a tuple-related macro; as such, the lints below may not always apply."
)]
impl<R: Relationship, $($list: SpawnableList<R>),*> SpawnableList<R> for ($($list,)*) {
fn spawn(self, _world: &mut World, _entity: Entity) {
#[allow(
non_snake_case,
reason = "The names of these variables are provided by the caller, not by us."
)]
let ($($list,)*) = self;
$($list.spawn(_world, _entity);)*
}
fn size_hint(&self) -> usize {
#[allow(
non_snake_case,
reason = "The names of these variables are provided by the caller, not by us."
)]
let ($($list,)*) = self;
0 $(+ $list.size_hint())*
}
}
}
}
all_tuples!(spawnable_list_impl, 0, 12, P);
/// A [`Bundle`] that:
/// 1. Contains a [`RelationshipTarget`] component (associated with the given [`Relationship`]). This reserves space for the [`SpawnableList`].
/// 2. Spawns a [`SpawnableList`] of related entities with a given [`Relationship`].
///
/// This is intended to be created using [`SpawnRelated`].
pub struct SpawnRelatedBundle<R: Relationship, L: SpawnableList<R>> {
list: L,
marker: PhantomData<R>,
}
impl<R: Relationship, L: SpawnableList<R>> BundleEffect for SpawnRelatedBundle<R, L> {
fn apply(self, entity: &mut EntityWorldMut) {
let id = entity.id();
entity.world_scope(|world: &mut World| {
self.list.spawn(world, id);
});
}
}
// SAFETY: This internally relies on the RelationshipTarget's Bundle implementation, which is sound.
unsafe impl<R: Relationship, L: SpawnableList<R> + Send + Sync + 'static> Bundle
for SpawnRelatedBundle<R, L>
{
fn component_ids(
components: &mut crate::component::ComponentsRegistrator,
ids: &mut impl FnMut(crate::component::ComponentId),
) {
<R::RelationshipTarget as Bundle>::component_ids(components, ids);
}
fn get_component_ids(
components: &crate::component::Components,
ids: &mut impl FnMut(Option<crate::component::ComponentId>),
) {
<R::RelationshipTarget as Bundle>::get_component_ids(components, ids);
}
fn register_required_components(
components: &mut crate::component::ComponentsRegistrator,
required_components: &mut crate::component::RequiredComponents,
) {
<R::RelationshipTarget as Bundle>::register_required_components(
components,
required_components,
);
}
}
impl<R: Relationship, L: SpawnableList<R>> DynamicBundle for SpawnRelatedBundle<R, L> {
type Effect = Self;
fn get_components(
self,
func: &mut impl FnMut(crate::component::StorageType, bevy_ptr::OwningPtr<'_>),
) -> Self::Effect {
<R::RelationshipTarget as RelationshipTarget>::with_capacity(self.list.size_hint())
.get_components(func);
self
}
}
/// A [`Bundle`] that:
/// 1. Contains a [`RelationshipTarget`] component (associated with the given [`Relationship`]). This reserves space for a single entity.
/// 2. Spawns a single related entity containing the given `B` [`Bundle`] and the given [`Relationship`].
///
/// This is intended to be created using [`SpawnRelated`].
pub struct SpawnOneRelated<R: Relationship, B: Bundle> {
bundle: B,
marker: PhantomData<R>,
}
impl<R: Relationship, B: Bundle> BundleEffect for SpawnOneRelated<R, B> {
fn apply(self, entity: &mut EntityWorldMut) {
entity.with_related::<R>(self.bundle);
}
}
impl<R: Relationship, B: Bundle> DynamicBundle for SpawnOneRelated<R, B> {
type Effect = Self;
fn get_components(
self,
func: &mut impl FnMut(crate::component::StorageType, bevy_ptr::OwningPtr<'_>),
) -> Self::Effect {
<R::RelationshipTarget as RelationshipTarget>::with_capacity(1).get_components(func);
self
}
}
// SAFETY: This internally relies on the RelationshipTarget's Bundle implementation, which is sound.
unsafe impl<R: Relationship, B: Bundle> Bundle for SpawnOneRelated<R, B> {
fn component_ids(
components: &mut crate::component::ComponentsRegistrator,
ids: &mut impl FnMut(crate::component::ComponentId),
) {
<R::RelationshipTarget as Bundle>::component_ids(components, ids);
}
fn get_component_ids(
components: &crate::component::Components,
ids: &mut impl FnMut(Option<crate::component::ComponentId>),
) {
<R::RelationshipTarget as Bundle>::get_component_ids(components, ids);
}
fn register_required_components(
components: &mut crate::component::ComponentsRegistrator,
required_components: &mut crate::component::RequiredComponents,
) {
<R::RelationshipTarget as Bundle>::register_required_components(
components,
required_components,
);
}
}
/// [`RelationshipTarget`] methods that create a [`Bundle`] with a [`DynamicBundle::Effect`] that:
///
/// 1. Contains the [`RelationshipTarget`] component, pre-allocated with the necessary space for spawned entities.
/// 2. Spawns an entity (or a list of entities) that relate to the entity the [`Bundle`] is added to via the [`RelationshipTarget::Relationship`].
pub trait SpawnRelated: RelationshipTarget {
/// Returns a [`Bundle`] containing this [`RelationshipTarget`] component. It also spawns a [`SpawnableList`] of entities, each related to the bundle's entity
/// via [`RelationshipTarget::Relationship`]. The [`RelationshipTarget`] (when possible) will pre-allocate space for the related entities.
///
/// See [`Spawn`], [`SpawnIter`], and [`SpawnWith`] for usage examples.
fn spawn<L: SpawnableList<Self::Relationship>>(
list: L,
) -> SpawnRelatedBundle<Self::Relationship, L>;
/// Returns a [`Bundle`] containing this [`RelationshipTarget`] component. It also spawns a single entity containing [`Bundle`] that is related to the bundle's entity
/// via [`RelationshipTarget::Relationship`].
///
/// ```
/// # use bevy_ecs::hierarchy::Children;
/// # use bevy_ecs::spawn::SpawnRelated;
/// # use bevy_ecs::name::Name;
/// # use bevy_ecs::world::World;
/// let mut world = World::new();
/// world.spawn((
/// Name::new("Root"),
/// Children::spawn_one(Name::new("Child")),
/// ));
/// ```
fn spawn_one<B: Bundle>(bundle: B) -> SpawnOneRelated<Self::Relationship, B>;
}
impl<T: RelationshipTarget> SpawnRelated for T {
fn spawn<L: SpawnableList<Self::Relationship>>(
list: L,
) -> SpawnRelatedBundle<Self::Relationship, L> {
SpawnRelatedBundle {
list,
marker: PhantomData,
}
}
fn spawn_one<B: Bundle>(bundle: B) -> SpawnOneRelated<Self::Relationship, B> {
SpawnOneRelated {
bundle,
marker: PhantomData,
}
}
}
/// Returns a [`SpawnRelatedBundle`] that will insert the given [`RelationshipTarget`], spawn a [`SpawnableList`] of entities with given bundles that
/// relate to the [`RelationshipTarget`] entity via the [`RelationshipTarget::Relationship`] component, and reserve space in the [`RelationshipTarget`] for each spawned entity.
///
/// The first argument is the [`RelationshipTarget`] type. Any additional arguments will be interpreted as bundles to be spawned.
///
/// Also see [`children`](crate::children) for a [`Children`](crate::hierarchy::Children)-specific equivalent.
///
/// ```
/// # use bevy_ecs::hierarchy::Children;
/// # use bevy_ecs::name::Name;
/// # use bevy_ecs::world::World;
/// # use bevy_ecs::related;
/// # use bevy_ecs::spawn::{Spawn, SpawnRelated};
/// let mut world = World::new();
/// world.spawn((
/// Name::new("Root"),
/// related!(Children[
/// Name::new("Child1"),
/// (
/// Name::new("Child2"),
/// related!(Children[
/// Name::new("Grandchild"),
/// ])
/// )
/// ])
/// ));
/// ```
#[macro_export]
macro_rules! related {
($relationship_target:ty [$($child:expr),*$(,)?]) => {
<$relationship_target>::spawn(($($crate::spawn::Spawn($child)),*))
};
}

View File

@@ -0,0 +1,500 @@
use super::blob_vec::array_layout;
use crate::storage::blob_vec::array_layout_unchecked;
use alloc::alloc::handle_alloc_error;
use bevy_ptr::{OwningPtr, Ptr, PtrMut};
use bevy_utils::OnDrop;
use core::{alloc::Layout, cell::UnsafeCell, num::NonZeroUsize, ptr::NonNull};
/// A flat, type-erased data storage type similar to a [`BlobVec`](super::blob_vec::BlobVec), but with the length and capacity cut out
/// for performance reasons. This type is reliant on its owning type to store the capacity and length information.
///
/// Used to densely store homogeneous ECS data. A blob is usually just an arbitrary block of contiguous memory without any identity, and
/// could be used to represent any arbitrary data (i.e. string, arrays, etc). This type only stores meta-data about the Blob that it stores,
/// and a pointer to the location of the start of the array, similar to a C array.
pub(super) struct BlobArray {
item_layout: Layout,
// the `data` ptr's layout is always `array_layout(item_layout, capacity)`
data: NonNull<u8>,
// None if the underlying type doesn't need to be dropped
pub drop: Option<unsafe fn(OwningPtr<'_>)>,
#[cfg(debug_assertions)]
capacity: usize,
}
impl BlobArray {
/// Create a new [`BlobArray`] with a specified `capacity`.
/// If `capacity` is 0, no allocations will be made.
///
/// `drop` is an optional function pointer that is meant to be invoked when any element in the [`BlobArray`]
/// should be dropped. For all Rust-based types, this should match 1:1 with the implementation of [`Drop`]
/// if present, and should be `None` if `T: !Drop`. For non-Rust based types, this should match any cleanup
/// processes typically associated with the stored element.
///
/// # Safety
/// `drop` should be safe to call with an [`OwningPtr`] pointing to any item that's been placed into this [`BlobArray`].
/// If `drop` is `None`, the items will be leaked. This should generally be set as None based on [`needs_drop`].
///
/// [`needs_drop`]: std::mem::needs_drop
pub unsafe fn with_capacity(
item_layout: Layout,
drop_fn: Option<unsafe fn(OwningPtr<'_>)>,
capacity: usize,
) -> Self {
if capacity == 0 {
let align = NonZeroUsize::new(item_layout.align()).expect("alignment must be > 0");
let data = bevy_ptr::dangling_with_align(align);
Self {
item_layout,
drop: drop_fn,
data,
#[cfg(debug_assertions)]
capacity,
}
} else {
let mut arr = Self::with_capacity(item_layout, drop_fn, 0);
// SAFETY: `capacity` > 0
unsafe { arr.alloc(NonZeroUsize::new_unchecked(capacity)) }
arr
}
}
/// Returns the [`Layout`] of the element type stored in the vector.
#[inline]
pub fn layout(&self) -> Layout {
self.item_layout
}
/// Return `true` if this [`BlobArray`] stores `ZSTs`.
pub fn is_zst(&self) -> bool {
self.item_layout.size() == 0
}
/// Returns a reference to the element at `index`, without doing bounds checking.
///
/// *`len` refers to the length of the array, the number of elements that have been initialized, and are safe to read.
/// Just like [`Vec::len`], or [`BlobVec::len`](super::blob_vec::BlobVec::len).*
///
/// # Safety
/// - The element at index `index` is safe to access.
/// (If the safety requirements of every method that has been used on `Self` have been fulfilled, the caller just needs to ensure that `index` < `len`)
///
/// [`Vec::len`]: alloc::vec::Vec::len
#[inline]
pub unsafe fn get_unchecked(&self, index: usize) -> Ptr<'_> {
#[cfg(debug_assertions)]
debug_assert!(index < self.capacity);
let size = self.item_layout.size();
// SAFETY:
// - The caller ensures that `index` fits in this array,
// so this operation will not overflow the original allocation.
// - `size` is a multiple of the erased type's alignment,
// so adding a multiple of `size` will preserve alignment.
unsafe { self.get_ptr().byte_add(index * size) }
}
/// Returns a mutable reference to the element at `index`, without doing bounds checking.
///
/// *`len` refers to the length of the array, the number of elements that have been initialized, and are safe to read.
/// Just like [`Vec::len`], or [`BlobVec::len`](super::blob_vec::BlobVec::len).*
///
/// # Safety
/// - The element with at index `index` is safe to access.
/// (If the safety requirements of every method that has been used on `Self` have been fulfilled, the caller just needs to ensure that `index` < `len`)
///
/// [`Vec::len`]: alloc::vec::Vec::len
#[inline]
pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> PtrMut<'_> {
#[cfg(debug_assertions)]
debug_assert!(index < self.capacity);
let size = self.item_layout.size();
// SAFETY:
// - The caller ensures that `index` fits in this vector,
// so this operation will not overflow the original allocation.
// - `size` is a multiple of the erased type's alignment,
// so adding a multiple of `size` will preserve alignment.
unsafe { self.get_ptr_mut().byte_add(index * size) }
}
/// Gets a [`Ptr`] to the start of the array
#[inline]
pub fn get_ptr(&self) -> Ptr<'_> {
// SAFETY: the inner data will remain valid for as long as 'self.
unsafe { Ptr::new(self.data) }
}
/// Gets a [`PtrMut`] to the start of the array
#[inline]
pub fn get_ptr_mut(&mut self) -> PtrMut<'_> {
// SAFETY: the inner data will remain valid for as long as 'self.
unsafe { PtrMut::new(self.data) }
}
/// Get a slice of the first `slice_len` elements in [`BlobArray`] as if it were an array with elements of type `T`
/// To get a slice to the entire array, the caller must plug `len` in `slice_len`.
///
/// *`len` refers to the length of the array, the number of elements that have been initialized, and are safe to read.
/// Just like [`Vec::len`], or [`BlobVec::len`](super::blob_vec::BlobVec::len).*
///
/// # Safety
/// - The type `T` must be the type of the items in this [`BlobArray`].
/// - `slice_len` <= `len`
///
/// [`Vec::len`]: alloc::vec::Vec::len
pub unsafe fn get_sub_slice<T>(&self, slice_len: usize) -> &[UnsafeCell<T>] {
#[cfg(debug_assertions)]
debug_assert!(slice_len <= self.capacity);
// SAFETY: the inner data will remain valid for as long as 'self.
unsafe {
core::slice::from_raw_parts(self.data.as_ptr() as *const UnsafeCell<T>, slice_len)
}
}
/// Clears the array, i.e. removing (and dropping) all of the elements.
/// Note that this method has no effect on the allocated capacity of the vector.
///
/// Note that this method will behave exactly the same as [`Vec::clear`].
///
/// # Safety
/// - For every element with index `i`, if `i` < `len`: It must be safe to call [`Self::get_unchecked_mut`] with `i`.
/// (If the safety requirements of every method that has been used on `Self` have been fulfilled, the caller just needs to ensure that `len` is correct.)
///
/// [`Vec::clear`]: alloc::vec::Vec::clear
pub unsafe fn clear(&mut self, len: usize) {
#[cfg(debug_assertions)]
debug_assert!(self.capacity >= len);
if let Some(drop) = self.drop {
// We set `self.drop` to `None` before dropping elements for unwind safety. This ensures we don't
// accidentally drop elements twice in the event of a drop impl panicking.
self.drop = None;
let size = self.item_layout.size();
for i in 0..len {
// SAFETY:
// * 0 <= `i` < `len`, so `i * size` must be in bounds for the allocation.
// * `size` is a multiple of the erased type's alignment,
// so adding a multiple of `size` will preserve alignment.
// * The item is left unreachable so it can be safely promoted to an `OwningPtr`.
let item = unsafe { self.get_ptr_mut().byte_add(i * size).promote() };
// SAFETY: `item` was obtained from this `BlobArray`, so its underlying type must match `drop`.
unsafe { drop(item) };
}
self.drop = Some(drop);
}
}
/// Because this method needs parameters, it can't be the implementation of the `Drop` trait.
/// The owner of this [`BlobArray`] must call this method with the correct information.
///
/// # Safety
/// - `cap` and `len` are indeed the capacity and length of this [`BlobArray`]
/// - This [`BlobArray`] mustn't be used after calling this method.
pub unsafe fn drop(&mut self, cap: usize, len: usize) {
#[cfg(debug_assertions)]
debug_assert_eq!(self.capacity, cap);
if cap != 0 {
self.clear(len);
if !self.is_zst() {
let layout =
array_layout(&self.item_layout, cap).expect("array layout should be valid");
alloc::alloc::dealloc(self.data.as_ptr().cast(), layout);
}
#[cfg(debug_assertions)]
{
self.capacity = 0;
}
}
}
/// Drops the last element in this [`BlobArray`].
///
/// # Safety
// - `last_element_index` must correspond to the last element in the array.
// - After this method is called, the last element must not be used
// unless [`Self::initialize_unchecked`] is called to set the value of the last element.
pub unsafe fn drop_last_element(&mut self, last_element_index: usize) {
#[cfg(debug_assertions)]
debug_assert!(self.capacity > last_element_index);
if let Some(drop) = self.drop {
// We set `self.drop` to `None` before dropping elements for unwind safety. This ensures we don't
// accidentally drop elements twice in the event of a drop impl panicking.
self.drop = None;
// SAFETY:
let item = self.get_unchecked_mut(last_element_index).promote();
// SAFETY:
unsafe { drop(item) };
self.drop = Some(drop);
}
}
/// Allocate a block of memory for the array. This should be used to initialize the array, do not use this
/// method if there are already elements stored in the array - use [`Self::realloc`] instead.
pub(super) fn alloc(&mut self, capacity: NonZeroUsize) {
#[cfg(debug_assertions)]
debug_assert_eq!(self.capacity, 0);
if !self.is_zst() {
let new_layout = array_layout(&self.item_layout, capacity.get())
.expect("array layout should be valid");
// SAFETY: layout has non-zero size because capacity > 0, and the blob isn't ZST (`self.is_zst` == false)
let new_data = unsafe { alloc::alloc::alloc(new_layout) };
self.data = NonNull::new(new_data).unwrap_or_else(|| handle_alloc_error(new_layout));
}
#[cfg(debug_assertions)]
{
self.capacity = capacity.into();
}
}
/// Reallocate memory for this array.
/// For example, if the length (number of stored elements) reached the capacity (number of elements the current allocation can store),
/// you might want to use this method to increase the allocation, so more data can be stored in the array.
///
/// # Safety
/// - `current_capacity` is indeed the current capacity of this array.
/// - After calling this method, the caller must update their saved capacity to reflect the change.
pub(super) unsafe fn realloc(
&mut self,
current_capacity: NonZeroUsize,
new_capacity: NonZeroUsize,
) {
#[cfg(debug_assertions)]
debug_assert_eq!(self.capacity, current_capacity.get());
if !self.is_zst() {
// SAFETY: `new_capacity` can't overflow usize
let new_layout =
unsafe { array_layout_unchecked(&self.item_layout, new_capacity.get()) };
// SAFETY:
// - ptr was be allocated via this allocator
// - the layout used to previously allocate this array is equivalent to `array_layout(&self.item_layout, current_capacity.get())`
// - `item_layout.size() > 0` (`self.is_zst`==false) and `new_capacity > 0`, so the layout size is non-zero
// - "new_size, when rounded up to the nearest multiple of layout.align(), must not overflow (i.e., the rounded value must be less than usize::MAX)",
// since the item size is always a multiple of its align, the rounding cannot happen
// here and the overflow is handled in `array_layout`
let new_data = unsafe {
alloc::alloc::realloc(
self.get_ptr_mut().as_ptr(),
// SAFETY: This is the Layout of the current array, it must be valid, if it hadn't have been, there would have been a panic on a previous allocation
array_layout_unchecked(&self.item_layout, current_capacity.get()),
new_layout.size(),
)
};
self.data = NonNull::new(new_data).unwrap_or_else(|| handle_alloc_error(new_layout));
}
#[cfg(debug_assertions)]
{
self.capacity = new_capacity.into();
}
}
/// Initializes the value at `index` to `value`. This function does not do any bounds checking.
///
/// # Safety
/// - `index` must be in bounds (`index` < capacity)
/// - The [`Layout`] of the value must match the layout of the blobs stored in this array,
/// and it must be safe to use the `drop` function of this [`BlobArray`] to drop `value`.
/// - `value` must not point to the same value that is being initialized.
#[inline]
pub unsafe fn initialize_unchecked(&mut self, index: usize, value: OwningPtr<'_>) {
#[cfg(debug_assertions)]
debug_assert!(self.capacity > index);
let size = self.item_layout.size();
let dst = self.get_unchecked_mut(index);
core::ptr::copy::<u8>(value.as_ptr(), dst.as_ptr(), size);
}
/// Replaces the value at `index` with `value`. This function does not do any bounds checking.
///
/// # Safety
/// - Index must be in-bounds (`index` < `len`)
/// - `value`'s [`Layout`] must match this [`BlobArray`]'s `item_layout`,
/// and it must be safe to use the `drop` function of this [`BlobArray`] to drop `value`.
/// - `value` must not point to the same value that is being replaced.
pub unsafe fn replace_unchecked(&mut self, index: usize, value: OwningPtr<'_>) {
#[cfg(debug_assertions)]
debug_assert!(self.capacity > index);
// Pointer to the value in the vector that will get replaced.
// SAFETY: The caller ensures that `index` fits in this vector.
let destination = NonNull::from(unsafe { self.get_unchecked_mut(index) });
let source = value.as_ptr();
if let Some(drop) = self.drop {
// We set `self.drop` to `None` before dropping elements for unwind safety. This ensures we don't
// accidentally drop elements twice in the event of a drop impl panicking.
self.drop = None;
// Transfer ownership of the old value out of the vector, so it can be dropped.
// SAFETY:
// - `destination` was obtained from a `PtrMut` in this vector, which ensures it is non-null,
// well-aligned for the underlying type, and has proper provenance.
// - The storage location will get overwritten with `value` later, which ensures
// that the element will not get observed or double dropped later.
// - If a panic occurs, `self.len` will remain `0`, which ensures a double-drop
// does not occur. Instead, all elements will be forgotten.
let old_value = unsafe { OwningPtr::new(destination) };
// This closure will run in case `drop()` panics,
// which ensures that `value` does not get forgotten.
let on_unwind = OnDrop::new(|| drop(value));
drop(old_value);
// If the above code does not panic, make sure that `value` doesn't get dropped.
core::mem::forget(on_unwind);
self.drop = Some(drop);
}
// Copy the new value into the vector, overwriting the previous value.
// SAFETY:
// - `source` and `destination` were obtained from `OwningPtr`s, which ensures they are
// valid for both reads and writes.
// - The value behind `source` will only be dropped if the above branch panics,
// so it must still be initialized and it is safe to transfer ownership into the vector.
// - `source` and `destination` were obtained from different memory locations,
// both of which we have exclusive access to, so they are guaranteed not to overlap.
unsafe {
core::ptr::copy_nonoverlapping::<u8>(
source,
destination.as_ptr(),
self.item_layout.size(),
);
}
}
/// This method will swap two elements in the array, and return the one at `index_to_remove`.
/// It is the caller's responsibility to drop the returned pointer, if that is desirable.
///
/// # Safety
/// - `index_to_keep` must be safe to access (within the bounds of the length of the array).
/// - `index_to_remove` must be safe to access (within the bounds of the length of the array).
/// - `index_to_remove` != `index_to_keep`
/// - The caller should address the inconsistent state of the array that has occurred after the swap, either:
/// 1) initialize a different value in `index_to_keep`
/// 2) update the saved length of the array if `index_to_keep` was the last element.
#[inline]
#[must_use = "The returned pointer should be used to drop the removed element"]
pub unsafe fn swap_remove_unchecked(
&mut self,
index_to_remove: usize,
index_to_keep: usize,
) -> OwningPtr<'_> {
#[cfg(debug_assertions)]
{
debug_assert!(self.capacity > index_to_keep);
debug_assert!(self.capacity > index_to_remove);
}
if index_to_remove != index_to_keep {
return self.swap_remove_unchecked_nonoverlapping(index_to_remove, index_to_keep);
}
// Now the element that used to be in index `index_to_remove` is now in index `index_to_keep` (after swap)
// If we are storing ZSTs than the index doesn't actually matter because the size is 0.
self.get_unchecked_mut(index_to_keep).promote()
}
/// The same as [`Self::swap_remove_unchecked`] but the two elements must non-overlapping.
///
/// # Safety
/// - `index_to_keep` must be safe to access (within the bounds of the length of the array).
/// - `index_to_remove` must be safe to access (within the bounds of the length of the array).
/// - `index_to_remove` != `index_to_keep`
/// - The caller should address the inconsistent state of the array that has occurred after the swap, either:
/// 1) initialize a different value in `index_to_keep`
/// 2) update the saved length of the array if `index_to_keep` was the last element.
#[inline]
pub unsafe fn swap_remove_unchecked_nonoverlapping(
&mut self,
index_to_remove: usize,
index_to_keep: usize,
) -> OwningPtr<'_> {
#[cfg(debug_assertions)]
{
debug_assert!(self.capacity > index_to_keep);
debug_assert!(self.capacity > index_to_remove);
debug_assert_ne!(index_to_keep, index_to_remove);
}
debug_assert_ne!(index_to_keep, index_to_remove);
core::ptr::swap_nonoverlapping::<u8>(
self.get_unchecked_mut(index_to_keep).as_ptr(),
self.get_unchecked_mut(index_to_remove).as_ptr(),
self.item_layout.size(),
);
// Now the element that used to be in index `index_to_remove` is now in index `index_to_keep` (after swap)
// If we are storing ZSTs than the index doesn't actually matter because the size is 0.
self.get_unchecked_mut(index_to_keep).promote()
}
/// This method will call [`Self::swap_remove_unchecked`] and drop the result.
///
/// # Safety
/// - `index_to_keep` must be safe to access (within the bounds of the length of the array).
/// - `index_to_remove` must be safe to access (within the bounds of the length of the array).
/// - `index_to_remove` != `index_to_keep`
/// - The caller should address the inconsistent state of the array that has occurred after the swap, either:
/// 1) initialize a different value in `index_to_keep`
/// 2) update the saved length of the array if `index_to_keep` was the last element.
#[inline]
pub unsafe fn swap_remove_and_drop_unchecked(
&mut self,
index_to_remove: usize,
index_to_keep: usize,
) {
#[cfg(debug_assertions)]
{
debug_assert!(self.capacity > index_to_keep);
debug_assert!(self.capacity > index_to_remove);
}
let drop = self.drop;
let value = self.swap_remove_unchecked(index_to_remove, index_to_keep);
if let Some(drop) = drop {
drop(value);
}
}
/// The same as [`Self::swap_remove_and_drop_unchecked`] but the two elements must non-overlapping.
///
/// # Safety
/// - `index_to_keep` must be safe to access (within the bounds of the length of the array).
/// - `index_to_remove` must be safe to access (within the bounds of the length of the array).
/// - `index_to_remove` != `index_to_keep`
/// - The caller should address the inconsistent state of the array that has occurred after the swap, either:
/// 1) initialize a different value in `index_to_keep`
/// 2) update the saved length of the array if `index_to_keep` was the last element.
#[inline]
pub unsafe fn swap_remove_and_drop_unchecked_nonoverlapping(
&mut self,
index_to_remove: usize,
index_to_keep: usize,
) {
#[cfg(debug_assertions)]
{
debug_assert!(self.capacity > index_to_keep);
debug_assert!(self.capacity > index_to_remove);
debug_assert_ne!(index_to_keep, index_to_remove);
}
let drop = self.drop;
let value = self.swap_remove_unchecked_nonoverlapping(index_to_remove, index_to_keep);
if let Some(drop) = drop {
drop(value);
}
}
}
#[cfg(test)]
mod tests {
use bevy_ecs::prelude::*;
#[derive(Component)]
struct PanicOnDrop;
impl Drop for PanicOnDrop {
fn drop(&mut self) {
panic!("PanicOnDrop is being Dropped");
}
}
#[test]
#[should_panic(expected = "PanicOnDrop is being Dropped")]
fn make_sure_zst_components_get_dropped() {
let mut world = World::new();
world.spawn(PanicOnDrop);
}
}

724
vendor/bevy_ecs/src/storage/blob_vec.rs vendored Normal file
View File

@@ -0,0 +1,724 @@
use alloc::alloc::handle_alloc_error;
use bevy_ptr::{OwningPtr, Ptr, PtrMut};
use bevy_utils::OnDrop;
use core::{alloc::Layout, cell::UnsafeCell, num::NonZero, ptr::NonNull};
/// A flat, type-erased data storage type
///
/// Used to densely store homogeneous ECS data. A blob is usually just an arbitrary block of contiguous memory without any identity, and
/// could be used to represent any arbitrary data (i.e. string, arrays, etc). This type is an extendable and re-allocatable blob, which makes
/// it a blobby Vec, a `BlobVec`.
pub(super) struct BlobVec {
item_layout: Layout,
capacity: usize,
/// Number of elements, not bytes
len: usize,
// the `data` ptr's layout is always `array_layout(item_layout, capacity)`
data: NonNull<u8>,
// None if the underlying type doesn't need to be dropped
drop: Option<unsafe fn(OwningPtr<'_>)>,
}
// We want to ignore the `drop` field in our `Debug` impl
impl core::fmt::Debug for BlobVec {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("BlobVec")
.field("item_layout", &self.item_layout)
.field("capacity", &self.capacity)
.field("len", &self.len)
.field("data", &self.data)
.finish()
}
}
impl BlobVec {
/// Creates a new [`BlobVec`] with the specified `capacity`.
///
/// `drop` is an optional function pointer that is meant to be invoked when any element in the [`BlobVec`]
/// should be dropped. For all Rust-based types, this should match 1:1 with the implementation of [`Drop`]
/// if present, and should be `None` if `T: !Drop`. For non-Rust based types, this should match any cleanup
/// processes typically associated with the stored element.
///
/// # Safety
///
/// `drop` should be safe to call with an [`OwningPtr`] pointing to any item that's been pushed into this [`BlobVec`].
///
/// If `drop` is `None`, the items will be leaked. This should generally be set as None based on [`needs_drop`].
///
/// [`needs_drop`]: std::mem::needs_drop
pub unsafe fn new(
item_layout: Layout,
drop: Option<unsafe fn(OwningPtr<'_>)>,
capacity: usize,
) -> BlobVec {
let align = NonZero::<usize>::new(item_layout.align()).expect("alignment must be > 0");
let data = bevy_ptr::dangling_with_align(align);
if item_layout.size() == 0 {
BlobVec {
data,
// ZST `BlobVec` max size is `usize::MAX`, and `reserve_exact` for ZST assumes
// the capacity is always `usize::MAX` and panics if it overflows.
capacity: usize::MAX,
len: 0,
item_layout,
drop,
}
} else {
let mut blob_vec = BlobVec {
data,
capacity: 0,
len: 0,
item_layout,
drop,
};
blob_vec.reserve_exact(capacity);
blob_vec
}
}
/// Returns the number of elements in the vector.
#[inline]
pub fn len(&self) -> usize {
self.len
}
/// Returns `true` if the vector contains no elements.
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
/// Returns the [`Layout`] of the element type stored in the vector.
#[inline]
pub fn layout(&self) -> Layout {
self.item_layout
}
/// Reserves the minimum capacity for at least `additional` more elements to be inserted in the given `BlobVec`.
/// After calling `reserve_exact`, capacity will be greater than or equal to `self.len() + additional`. Does nothing if
/// the capacity is already sufficient.
///
/// Note that the allocator may give the collection more space than it requests. Therefore, capacity can not be relied upon
/// to be precisely minimal.
///
/// # Panics
///
/// Panics if new capacity overflows `usize`.
pub fn reserve_exact(&mut self, additional: usize) {
let available_space = self.capacity - self.len;
if available_space < additional {
// SAFETY: `available_space < additional`, so `additional - available_space > 0`
let increment =
unsafe { NonZero::<usize>::new_unchecked(additional - available_space) };
self.grow_exact(increment);
}
}
/// Reserves the minimum capacity for at least `additional` more elements to be inserted in the given `BlobVec`.
#[inline]
pub fn reserve(&mut self, additional: usize) {
/// Similar to `reserve_exact`. This method ensures that the capacity will grow at least `self.capacity()` if there is no
/// enough space to hold `additional` more elements.
#[cold]
fn do_reserve(slf: &mut BlobVec, additional: usize) {
let increment = slf.capacity.max(additional - (slf.capacity - slf.len));
let increment = NonZero::<usize>::new(increment).unwrap();
slf.grow_exact(increment);
}
if self.capacity - self.len < additional {
do_reserve(self, additional);
}
}
/// Grows the capacity by `increment` elements.
///
/// # Panics
///
/// Panics if the new capacity overflows `usize`.
/// For ZST it panics unconditionally because ZST `BlobVec` capacity
/// is initialized to `usize::MAX` and always stays that way.
fn grow_exact(&mut self, increment: NonZero<usize>) {
let new_capacity = self
.capacity
.checked_add(increment.get())
.expect("capacity overflow");
let new_layout =
array_layout(&self.item_layout, new_capacity).expect("array layout should be valid");
let new_data = if self.capacity == 0 {
// SAFETY:
// - layout has non-zero size as per safety requirement
unsafe { alloc::alloc::alloc(new_layout) }
} else {
// SAFETY:
// - ptr was be allocated via this allocator
// - the layout of the ptr was `array_layout(self.item_layout, self.capacity)`
// - `item_layout.size() > 0` and `new_capacity > 0`, so the layout size is non-zero
// - "new_size, when rounded up to the nearest multiple of layout.align(), must not overflow (i.e., the rounded value must be less than usize::MAX)",
// since the item size is always a multiple of its alignment, the rounding cannot happen
// here and the overflow is handled in `array_layout`
unsafe {
alloc::alloc::realloc(
self.get_ptr_mut().as_ptr(),
array_layout(&self.item_layout, self.capacity)
.expect("array layout should be valid"),
new_layout.size(),
)
}
};
self.data = NonNull::new(new_data).unwrap_or_else(|| handle_alloc_error(new_layout));
self.capacity = new_capacity;
}
/// Initializes the value at `index` to `value`. This function does not do any bounds checking.
///
/// # Safety
/// - index must be in bounds
/// - the memory in the [`BlobVec`] starting at index `index`, of a size matching this [`BlobVec`]'s
/// `item_layout`, must have been previously allocated.
#[inline]
pub unsafe fn initialize_unchecked(&mut self, index: usize, value: OwningPtr<'_>) {
debug_assert!(index < self.len());
let ptr = self.get_unchecked_mut(index);
core::ptr::copy_nonoverlapping::<u8>(value.as_ptr(), ptr.as_ptr(), self.item_layout.size());
}
/// Replaces the value at `index` with `value`. This function does not do any bounds checking.
///
/// # Safety
/// - index must be in-bounds
/// - the memory in the [`BlobVec`] starting at index `index`, of a size matching this
/// [`BlobVec`]'s `item_layout`, must have been previously initialized with an item matching
/// this [`BlobVec`]'s `item_layout`
/// - the memory at `*value` must also be previously initialized with an item matching this
/// [`BlobVec`]'s `item_layout`
pub unsafe fn replace_unchecked(&mut self, index: usize, value: OwningPtr<'_>) {
debug_assert!(index < self.len());
// Pointer to the value in the vector that will get replaced.
// SAFETY: The caller ensures that `index` fits in this vector.
let destination = NonNull::from(unsafe { self.get_unchecked_mut(index) });
let source = value.as_ptr();
if let Some(drop) = self.drop {
// Temporarily set the length to zero, so that if `drop` panics the caller
// will not be left with a `BlobVec` containing a dropped element within
// its initialized range.
let old_len = self.len;
self.len = 0;
// Transfer ownership of the old value out of the vector, so it can be dropped.
// SAFETY:
// - `destination` was obtained from a `PtrMut` in this vector, which ensures it is non-null,
// well-aligned for the underlying type, and has proper provenance.
// - The storage location will get overwritten with `value` later, which ensures
// that the element will not get observed or double dropped later.
// - If a panic occurs, `self.len` will remain `0`, which ensures a double-drop
// does not occur. Instead, all elements will be forgotten.
let old_value = unsafe { OwningPtr::new(destination) };
// This closure will run in case `drop()` panics,
// which ensures that `value` does not get forgotten.
let on_unwind = OnDrop::new(|| drop(value));
drop(old_value);
// If the above code does not panic, make sure that `value` doesn't get dropped.
core::mem::forget(on_unwind);
// Make the vector's contents observable again, since panics are no longer possible.
self.len = old_len;
}
// Copy the new value into the vector, overwriting the previous value.
// SAFETY:
// - `source` and `destination` were obtained from `OwningPtr`s, which ensures they are
// valid for both reads and writes.
// - The value behind `source` will only be dropped if the above branch panics,
// so it must still be initialized and it is safe to transfer ownership into the vector.
// - `source` and `destination` were obtained from different memory locations,
// both of which we have exclusive access to, so they are guaranteed not to overlap.
unsafe {
core::ptr::copy_nonoverlapping::<u8>(
source,
destination.as_ptr(),
self.item_layout.size(),
);
}
}
/// Appends an element to the back of the vector.
///
/// # Safety
/// The `value` must match the [`layout`](`BlobVec::layout`) of the elements in the [`BlobVec`].
#[inline]
pub unsafe fn push(&mut self, value: OwningPtr<'_>) {
self.reserve(1);
let index = self.len;
self.len += 1;
self.initialize_unchecked(index, value);
}
/// Performs a "swap remove" at the given `index`, which removes the item at `index` and moves
/// the last item in the [`BlobVec`] to `index` (if `index` is not the last item). It is the
/// caller's responsibility to drop the returned pointer, if that is desirable.
///
/// # Safety
/// It is the caller's responsibility to ensure that `index` is less than `self.len()`.
#[must_use = "The returned pointer should be used to dropped the removed element"]
pub unsafe fn swap_remove_and_forget_unchecked(&mut self, index: usize) -> OwningPtr<'_> {
debug_assert!(index < self.len());
// Since `index` must be strictly less than `self.len` and `index` is at least zero,
// `self.len` must be at least one. Thus, this cannot underflow.
let new_len = self.len - 1;
let size = self.item_layout.size();
if index != new_len {
core::ptr::swap_nonoverlapping::<u8>(
self.get_unchecked_mut(index).as_ptr(),
self.get_unchecked_mut(new_len).as_ptr(),
size,
);
}
self.len = new_len;
// Cannot use get_unchecked here as this is technically out of bounds after changing len.
// SAFETY:
// - `new_len` is less than the old len, so it must fit in this vector's allocation.
// - `size` is a multiple of the erased type's alignment,
// so adding a multiple of `size` will preserve alignment.
// - The removed element lives as long as this vector's mutable reference.
let p = unsafe { self.get_ptr_mut().byte_add(new_len * size) };
// SAFETY: The removed element is unreachable by this vector so it's safe to promote the
// `PtrMut` to an `OwningPtr`.
unsafe { p.promote() }
}
/// Removes the value at `index` and drops it.
/// Does not do any bounds checking on `index`.
/// The removed element is replaced by the last element of the `BlobVec`.
///
/// # Safety
/// It is the caller's responsibility to ensure that `index` is `< self.len()`.
#[inline]
pub unsafe fn swap_remove_and_drop_unchecked(&mut self, index: usize) {
debug_assert!(index < self.len());
let drop = self.drop;
let value = self.swap_remove_and_forget_unchecked(index);
if let Some(drop) = drop {
drop(value);
}
}
/// Returns a reference to the element at `index`, without doing bounds checking.
///
/// # Safety
/// It is the caller's responsibility to ensure that `index < self.len()`.
#[inline]
pub unsafe fn get_unchecked(&self, index: usize) -> Ptr<'_> {
debug_assert!(index < self.len());
let size = self.item_layout.size();
// SAFETY:
// - The caller ensures that `index` fits in this vector,
// so this operation will not overflow the original allocation.
// - `size` is a multiple of the erased type's alignment,
// so adding a multiple of `size` will preserve alignment.
// - The element at `index` outlives this vector's reference.
unsafe { self.get_ptr().byte_add(index * size) }
}
/// Returns a mutable reference to the element at `index`, without doing bounds checking.
///
/// # Safety
/// It is the caller's responsibility to ensure that `index < self.len()`.
#[inline]
pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> PtrMut<'_> {
debug_assert!(index < self.len());
let size = self.item_layout.size();
// SAFETY:
// - The caller ensures that `index` fits in this vector,
// so this operation will not overflow the original allocation.
// - `size` is a multiple of the erased type's alignment,
// so adding a multiple of `size` will preserve alignment.
// - The element at `index` outlives this vector's mutable reference.
unsafe { self.get_ptr_mut().byte_add(index * size) }
}
/// Gets a [`Ptr`] to the start of the vec
#[inline]
pub fn get_ptr(&self) -> Ptr<'_> {
// SAFETY: the inner data will remain valid for as long as 'self.
unsafe { Ptr::new(self.data) }
}
/// Gets a [`PtrMut`] to the start of the vec
#[inline]
pub fn get_ptr_mut(&mut self) -> PtrMut<'_> {
// SAFETY: the inner data will remain valid for as long as 'self.
unsafe { PtrMut::new(self.data) }
}
/// Get a reference to the entire [`BlobVec`] as if it were an array with elements of type `T`
///
/// # Safety
/// The type `T` must be the type of the items in this [`BlobVec`].
pub unsafe fn get_slice<T>(&self) -> &[UnsafeCell<T>] {
// SAFETY: the inner data will remain valid for as long as 'self.
unsafe { core::slice::from_raw_parts(self.data.as_ptr() as *const UnsafeCell<T>, self.len) }
}
/// Returns the drop function for values stored in the vector,
/// or `None` if they don't need to be dropped.
#[inline]
pub fn get_drop(&self) -> Option<unsafe fn(OwningPtr<'_>)> {
self.drop
}
/// Clears the vector, removing (and dropping) all values.
///
/// Note that this method has no effect on the allocated capacity of the vector.
pub fn clear(&mut self) {
let len = self.len;
// We set len to 0 _before_ dropping elements for unwind safety. This ensures we don't
// accidentally drop elements twice in the event of a drop impl panicking.
self.len = 0;
if let Some(drop) = self.drop {
let size = self.item_layout.size();
for i in 0..len {
// SAFETY:
// * 0 <= `i` < `len`, so `i * size` must be in bounds for the allocation.
// * `size` is a multiple of the erased type's alignment,
// so adding a multiple of `size` will preserve alignment.
// * The item lives until it's dropped.
// * The item is left unreachable so it can be safely promoted to an `OwningPtr`.
// NOTE: `self.get_unchecked_mut(i)` cannot be used here, since the `debug_assert`
// would panic due to `self.len` being set to 0.
let item = unsafe { self.get_ptr_mut().byte_add(i * size).promote() };
// SAFETY: `item` was obtained from this `BlobVec`, so its underlying type must match `drop`.
unsafe { drop(item) };
}
}
}
}
impl Drop for BlobVec {
fn drop(&mut self) {
self.clear();
let array_layout =
array_layout(&self.item_layout, self.capacity).expect("array layout should be valid");
if array_layout.size() > 0 {
// SAFETY: data ptr layout is correct, swap_scratch ptr layout is correct
unsafe {
alloc::alloc::dealloc(self.get_ptr_mut().as_ptr(), array_layout);
}
}
}
}
/// From <https://doc.rust-lang.org/beta/src/core/alloc/layout.rs.html>
pub(super) fn array_layout(layout: &Layout, n: usize) -> Option<Layout> {
let (array_layout, offset) = repeat_layout(layout, n)?;
debug_assert_eq!(layout.size(), offset);
Some(array_layout)
}
// TODO: replace with `Layout::repeat` if/when it stabilizes
/// From <https://doc.rust-lang.org/beta/src/core/alloc/layout.rs.html>
fn repeat_layout(layout: &Layout, n: usize) -> Option<(Layout, usize)> {
// This cannot overflow. Quoting from the invariant of Layout:
// > `size`, when rounded up to the nearest multiple of `align`,
// > must not overflow (i.e., the rounded value must be less than
// > `usize::MAX`)
let padded_size = layout.size() + padding_needed_for(layout, layout.align());
let alloc_size = padded_size.checked_mul(n)?;
// SAFETY: self.align is already known to be valid and alloc_size has been
// padded already.
unsafe {
Some((
Layout::from_size_align_unchecked(alloc_size, layout.align()),
padded_size,
))
}
}
/// From <https://doc.rust-lang.org/beta/src/core/alloc/layout.rs.html>
/// # Safety
/// The caller must ensure that:
/// - The resulting [`Layout`] is valid, by ensuring that `(layout.size() + padding_needed_for(layout, layout.align())) * n` doesn't overflow.
pub(super) unsafe fn array_layout_unchecked(layout: &Layout, n: usize) -> Layout {
let (array_layout, offset) = repeat_layout_unchecked(layout, n);
debug_assert_eq!(layout.size(), offset);
array_layout
}
// TODO: replace with `Layout::repeat` if/when it stabilizes
/// From <https://doc.rust-lang.org/beta/src/core/alloc/layout.rs.html>
/// # Safety
/// The caller must ensure that:
/// - The resulting [`Layout`] is valid, by ensuring that `(layout.size() + padding_needed_for(layout, layout.align())) * n` doesn't overflow.
unsafe fn repeat_layout_unchecked(layout: &Layout, n: usize) -> (Layout, usize) {
// This cannot overflow. Quoting from the invariant of Layout:
// > `size`, when rounded up to the nearest multiple of `align`,
// > must not overflow (i.e., the rounded value must be less than
// > `usize::MAX`)
let padded_size = layout.size() + padding_needed_for(layout, layout.align());
// This may overflow in release builds, that's why this function is unsafe.
let alloc_size = padded_size * n;
// SAFETY: self.align is already known to be valid and alloc_size has been
// padded already.
unsafe {
(
Layout::from_size_align_unchecked(alloc_size, layout.align()),
padded_size,
)
}
}
/// From <https://doc.rust-lang.org/beta/src/core/alloc/layout.rs.html>
const fn padding_needed_for(layout: &Layout, align: usize) -> usize {
let len = layout.size();
// Rounded up value is:
// len_rounded_up = (len + align - 1) & !(align - 1);
// and then we return the padding difference: `len_rounded_up - len`.
//
// We use modular arithmetic throughout:
//
// 1. align is guaranteed to be > 0, so align - 1 is always
// valid.
//
// 2. `len + align - 1` can overflow by at most `align - 1`,
// so the &-mask with `!(align - 1)` will ensure that in the
// case of overflow, `len_rounded_up` will itself be 0.
// Thus the returned padding, when added to `len`, yields 0,
// which trivially satisfies the alignment `align`.
//
// (Of course, attempts to allocate blocks of memory whose
// size and padding overflow in the above manner should cause
// the allocator to yield an error anyway.)
let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
len_rounded_up.wrapping_sub(len)
}
#[cfg(test)]
mod tests {
use super::BlobVec;
use crate::{component::Component, ptr::OwningPtr, world::World};
use alloc::{
rc::Rc,
string::{String, ToString},
};
use core::{alloc::Layout, cell::RefCell};
/// # Safety
///
/// The pointer `x` must point to a valid value of type `T` and it must be safe to drop this value.
unsafe fn drop_ptr<T>(x: OwningPtr<'_>) {
// SAFETY: It is guaranteed by the caller that `x` points to a
// valid value of type `T` and it is safe to drop this value.
unsafe {
x.drop_as::<T>();
}
}
/// # Safety
///
/// `blob_vec` must have a layout that matches `Layout::new::<T>()`
unsafe fn push<T>(blob_vec: &mut BlobVec, value: T) {
OwningPtr::make(value, |ptr| {
blob_vec.push(ptr);
});
}
/// # Safety
///
/// `blob_vec` must have a layout that matches `Layout::new::<T>()`
unsafe fn swap_remove<T>(blob_vec: &mut BlobVec, index: usize) -> T {
assert!(index < blob_vec.len());
let value = blob_vec.swap_remove_and_forget_unchecked(index);
value.read::<T>()
}
/// # Safety
///
/// `blob_vec` must have a layout that matches `Layout::new::<T>()`, it most store a valid `T`
/// value at the given `index`
unsafe fn get_mut<T>(blob_vec: &mut BlobVec, index: usize) -> &mut T {
assert!(index < blob_vec.len());
blob_vec.get_unchecked_mut(index).deref_mut::<T>()
}
#[test]
fn resize_test() {
let item_layout = Layout::new::<usize>();
// SAFETY: `drop` fn is `None`, usize doesn't need dropping
let mut blob_vec = unsafe { BlobVec::new(item_layout, None, 64) };
// SAFETY: `i` is a usize, i.e. the type corresponding to `item_layout`
unsafe {
for i in 0..1_000 {
push(&mut blob_vec, i as usize);
}
}
assert_eq!(blob_vec.len(), 1_000);
assert_eq!(blob_vec.capacity, 1_024);
}
#[derive(Debug, Eq, PartialEq, Clone)]
struct Foo {
a: u8,
b: String,
drop_counter: Rc<RefCell<usize>>,
}
impl Drop for Foo {
fn drop(&mut self) {
*self.drop_counter.borrow_mut() += 1;
}
}
#[test]
fn blob_vec() {
let drop_counter = Rc::new(RefCell::new(0));
{
let item_layout = Layout::new::<Foo>();
let drop = drop_ptr::<Foo>;
// SAFETY: drop is able to drop a value of its `item_layout`
let mut blob_vec = unsafe { BlobVec::new(item_layout, Some(drop), 2) };
assert_eq!(blob_vec.capacity, 2);
// SAFETY: the following code only deals with values of type `Foo`, which satisfies the safety requirement of `push`, `get_mut` and `swap_remove` that the
// values have a layout compatible to the blob vec's `item_layout`.
// Every index is in range.
unsafe {
let foo1 = Foo {
a: 42,
b: "abc".to_string(),
drop_counter: drop_counter.clone(),
};
push(&mut blob_vec, foo1.clone());
assert_eq!(blob_vec.len(), 1);
assert_eq!(get_mut::<Foo>(&mut blob_vec, 0), &foo1);
let mut foo2 = Foo {
a: 7,
b: "xyz".to_string(),
drop_counter: drop_counter.clone(),
};
push::<Foo>(&mut blob_vec, foo2.clone());
assert_eq!(blob_vec.len(), 2);
assert_eq!(blob_vec.capacity, 2);
assert_eq!(get_mut::<Foo>(&mut blob_vec, 0), &foo1);
assert_eq!(get_mut::<Foo>(&mut blob_vec, 1), &foo2);
get_mut::<Foo>(&mut blob_vec, 1).a += 1;
assert_eq!(get_mut::<Foo>(&mut blob_vec, 1).a, 8);
let foo3 = Foo {
a: 16,
b: "123".to_string(),
drop_counter: drop_counter.clone(),
};
push(&mut blob_vec, foo3.clone());
assert_eq!(blob_vec.len(), 3);
assert_eq!(blob_vec.capacity, 4);
let last_index = blob_vec.len() - 1;
let value = swap_remove::<Foo>(&mut blob_vec, last_index);
assert_eq!(foo3, value);
assert_eq!(blob_vec.len(), 2);
assert_eq!(blob_vec.capacity, 4);
let value = swap_remove::<Foo>(&mut blob_vec, 0);
assert_eq!(foo1, value);
assert_eq!(blob_vec.len(), 1);
assert_eq!(blob_vec.capacity, 4);
foo2.a = 8;
assert_eq!(get_mut::<Foo>(&mut blob_vec, 0), &foo2);
}
}
assert_eq!(*drop_counter.borrow(), 6);
}
#[test]
fn blob_vec_drop_empty_capacity() {
let item_layout = Layout::new::<Foo>();
let drop = drop_ptr::<Foo>;
// SAFETY: drop is able to drop a value of its `item_layout`
let _ = unsafe { BlobVec::new(item_layout, Some(drop), 0) };
}
#[test]
#[should_panic(expected = "capacity overflow")]
fn blob_vec_zst_size_overflow() {
// SAFETY: no drop is correct drop for `()`.
let mut blob_vec = unsafe { BlobVec::new(Layout::new::<()>(), None, 0) };
assert_eq!(usize::MAX, blob_vec.capacity, "Self-check");
// SAFETY: Because `()` is a ZST trivial drop type, and because `BlobVec` capacity
// is always `usize::MAX` for ZSTs, we can arbitrarily set the length
// and still be sound.
blob_vec.len = usize::MAX;
// SAFETY: `BlobVec` was initialized for `()`, so it is safe to push `()` to it.
unsafe {
OwningPtr::make((), |ptr| {
// This should panic because len is usize::MAX, remaining capacity is 0.
blob_vec.push(ptr);
});
}
}
#[test]
#[should_panic(expected = "capacity overflow")]
fn blob_vec_capacity_overflow() {
// SAFETY: no drop is correct drop for `u32`.
let mut blob_vec = unsafe { BlobVec::new(Layout::new::<u32>(), None, 0) };
assert_eq!(0, blob_vec.capacity, "Self-check");
OwningPtr::make(17u32, |ptr| {
// SAFETY: we push the value of correct type.
unsafe {
blob_vec.push(ptr);
}
});
blob_vec.reserve_exact(usize::MAX);
}
#[test]
fn aligned_zst() {
// NOTE: This test is explicitly for uncovering potential UB with miri.
#[derive(Component)]
#[repr(align(32))]
struct Zst;
let mut world = World::default();
world.spawn(Zst);
world.spawn(Zst);
world.spawn(Zst);
world.spawn_empty();
let mut count = 0;
let mut q = world.query::<&Zst>();
for zst in q.iter(&world) {
// Ensure that the references returned are properly aligned.
assert_eq!(
core::ptr::from_ref::<Zst>(zst) as usize % align_of::<Zst>(),
0
);
count += 1;
}
assert_eq!(count, 3);
}
}

62
vendor/bevy_ecs/src/storage/mod.rs vendored Normal file
View File

@@ -0,0 +1,62 @@
//! Storage layouts for ECS data.
//!
//! This module implements the low-level collections that store data in a [`World`]. These all offer minimal and often
//! unsafe APIs, and have been made `pub` primarily for debugging and monitoring purposes.
//!
//! # Fetching Storages
//! Each of the below data stores can be fetched via [`Storages`], which can be fetched from a
//! [`World`] via [`World::storages`]. It exposes a top level container for each class of storage within
//! ECS:
//!
//! - [`Tables`] - columnar contiguous blocks of memory, optimized for fast iteration.
//! - [`SparseSets`] - sparse `HashMap`-like mappings from entities to components, optimized for random
//! lookup and regular insertion/removal of components.
//! - [`Resources`] - singleton storage for the resources in the world
//!
//! # Safety
//! To avoid trivially unsound use of the APIs in this module, it is explicitly impossible to get a mutable
//! reference to [`Storages`] from [`World`], and none of the types publicly expose a mutable interface.
//!
//! [`World`]: crate::world::World
//! [`World::storages`]: crate::world::World::storages
mod blob_array;
mod blob_vec;
mod resource;
mod sparse_set;
mod table;
mod thin_array_ptr;
pub use resource::*;
pub use sparse_set::*;
pub use table::*;
use crate::component::{ComponentInfo, StorageType};
/// The raw data stores of a [`World`](crate::world::World)
#[derive(Default)]
pub struct Storages {
/// Backing storage for [`SparseSet`] components.
/// Note that sparse sets are only present for components that have been spawned or have had a relevant bundle registered.
pub sparse_sets: SparseSets,
/// Backing storage for [`Table`] components.
pub tables: Tables,
/// Backing storage for resources.
pub resources: Resources<true>,
/// Backing storage for `!Send` resources.
pub non_send_resources: Resources<false>,
}
impl Storages {
/// ensures that the component has its necessary storage initialize.
pub fn prepare_component(&mut self, component: &ComponentInfo) {
match component.storage_type() {
StorageType::Table => {
// table needs no preparation
}
StorageType::SparseSet => {
self.sparse_sets.get_or_insert(component);
}
}
}
}

403
vendor/bevy_ecs/src/storage/resource.rs vendored Normal file
View File

@@ -0,0 +1,403 @@
use crate::{
archetype::ArchetypeComponentId,
change_detection::{MaybeLocation, MutUntyped, TicksMut},
component::{ComponentId, ComponentTicks, Components, Tick, TickCells},
storage::{blob_vec::BlobVec, SparseSet},
};
use alloc::string::String;
use bevy_ptr::{OwningPtr, Ptr, UnsafeCellDeref};
use core::{cell::UnsafeCell, mem::ManuallyDrop, panic::Location};
#[cfg(feature = "std")]
use std::thread::ThreadId;
/// The type-erased backing storage and metadata for a single resource within a [`World`].
///
/// If `SEND` is false, values of this type will panic if dropped from a different thread.
///
/// [`World`]: crate::world::World
pub struct ResourceData<const SEND: bool> {
data: ManuallyDrop<BlobVec>,
added_ticks: UnsafeCell<Tick>,
changed_ticks: UnsafeCell<Tick>,
#[cfg_attr(
not(feature = "std"),
expect(dead_code, reason = "currently only used with the std feature")
)]
type_name: String,
id: ArchetypeComponentId,
#[cfg(feature = "std")]
origin_thread_id: Option<ThreadId>,
changed_by: MaybeLocation<UnsafeCell<&'static Location<'static>>>,
}
impl<const SEND: bool> Drop for ResourceData<SEND> {
fn drop(&mut self) {
// For Non Send resources we need to validate that correct thread
// is dropping the resource. This validation is not needed in case
// of SEND resources. Or if there is no data.
if !SEND && self.is_present() {
// If this thread is already panicking, panicking again will cause
// the entire process to abort. In this case we choose to avoid
// dropping or checking this altogether and just leak the column.
#[cfg(feature = "std")]
if std::thread::panicking() {
return;
}
self.validate_access();
}
// SAFETY: Drop is only called once upon dropping the ResourceData
// and is inaccessible after this as the parent ResourceData has
// been dropped. The validate_access call above will check that the
// data is dropped on the thread it was inserted from.
unsafe {
ManuallyDrop::drop(&mut self.data);
}
}
}
impl<const SEND: bool> ResourceData<SEND> {
/// The only row in the underlying `BlobVec`.
const ROW: usize = 0;
/// Validates the access to `!Send` resources is only done on the thread they were created from.
///
/// # Panics
/// If `SEND` is false, this will panic if called from a different thread than the one it was inserted from.
#[inline]
fn validate_access(&self) {
if SEND {
return;
}
#[cfg(feature = "std")]
if self.origin_thread_id != Some(std::thread::current().id()) {
// Panic in tests, as testing for aborting is nearly impossible
panic!(
"Attempted to access or drop non-send resource {} from thread {:?} on a thread {:?}. This is not allowed. Aborting.",
self.type_name,
self.origin_thread_id,
std::thread::current().id()
);
}
// TODO: Handle no_std non-send.
// Currently, no_std is single-threaded only, so this is safe to ignore.
// To support no_std multithreading, an alternative will be required.
}
/// Returns true if the resource is populated.
#[inline]
pub fn is_present(&self) -> bool {
!self.data.is_empty()
}
/// Gets the [`ArchetypeComponentId`] for the resource.
#[inline]
pub fn id(&self) -> ArchetypeComponentId {
self.id
}
/// Returns a reference to the resource, if it exists.
///
/// # Panics
/// If `SEND` is false, this will panic if a value is present and is not accessed from the
/// original thread it was inserted from.
#[inline]
pub fn get_data(&self) -> Option<Ptr<'_>> {
self.is_present().then(|| {
self.validate_access();
// SAFETY: We've already checked if a value is present, and there should only be one.
unsafe { self.data.get_unchecked(Self::ROW) }
})
}
/// Returns a reference to the resource's change ticks, if it exists.
#[inline]
pub fn get_ticks(&self) -> Option<ComponentTicks> {
// SAFETY: This is being fetched through a read-only reference to Self, so no other mutable references
// to the ticks can exist.
unsafe {
self.is_present().then(|| ComponentTicks {
added: self.added_ticks.read(),
changed: self.changed_ticks.read(),
})
}
}
/// Returns references to the resource and its change ticks, if it exists.
///
/// # Panics
/// If `SEND` is false, this will panic if a value is present and is not accessed from the
/// original thread it was inserted in.
#[inline]
pub(crate) fn get_with_ticks(
&self,
) -> Option<(
Ptr<'_>,
TickCells<'_>,
MaybeLocation<&UnsafeCell<&'static Location<'static>>>,
)> {
self.is_present().then(|| {
self.validate_access();
(
// SAFETY: We've already checked if a value is present, and there should only be one.
unsafe { self.data.get_unchecked(Self::ROW) },
TickCells {
added: &self.added_ticks,
changed: &self.changed_ticks,
},
self.changed_by.as_ref(),
)
})
}
/// Returns a mutable reference to the resource, if it exists.
///
/// # Panics
/// If `SEND` is false, this will panic if a value is present and is not accessed from the
/// original thread it was inserted in.
pub(crate) fn get_mut(&mut self, last_run: Tick, this_run: Tick) -> Option<MutUntyped<'_>> {
let (ptr, ticks, caller) = self.get_with_ticks()?;
Some(MutUntyped {
// SAFETY: We have exclusive access to the underlying storage.
value: unsafe { ptr.assert_unique() },
// SAFETY: We have exclusive access to the underlying storage.
ticks: unsafe { TicksMut::from_tick_cells(ticks, last_run, this_run) },
// SAFETY: We have exclusive access to the underlying storage.
changed_by: unsafe { caller.map(|caller| caller.deref_mut()) },
})
}
/// Inserts a value into the resource. If a value is already present
/// it will be replaced.
///
/// # Panics
/// If `SEND` is false, this will panic if a value is present and is not replaced from
/// the original thread it was inserted in.
///
/// # Safety
/// - `value` must be valid for the underlying type for the resource.
#[inline]
pub(crate) unsafe fn insert(
&mut self,
value: OwningPtr<'_>,
change_tick: Tick,
caller: MaybeLocation,
) {
if self.is_present() {
self.validate_access();
// SAFETY: The caller ensures that the provided value is valid for the underlying type and
// is properly initialized. We've ensured that a value is already present and previously
// initialized.
unsafe {
self.data.replace_unchecked(Self::ROW, value);
}
} else {
#[cfg(feature = "std")]
if !SEND {
self.origin_thread_id = Some(std::thread::current().id());
}
self.data.push(value);
*self.added_ticks.deref_mut() = change_tick;
}
*self.changed_ticks.deref_mut() = change_tick;
self.changed_by
.as_ref()
.map(|changed_by| changed_by.deref_mut())
.assign(caller);
}
/// Inserts a value into the resource with a pre-existing change tick. If a
/// value is already present it will be replaced.
///
/// # Panics
/// If `SEND` is false, this will panic if a value is present and is not replaced from
/// the original thread it was inserted in.
///
/// # Safety
/// - `value` must be valid for the underlying type for the resource.
#[inline]
pub(crate) unsafe fn insert_with_ticks(
&mut self,
value: OwningPtr<'_>,
change_ticks: ComponentTicks,
caller: MaybeLocation,
) {
if self.is_present() {
self.validate_access();
// SAFETY: The caller ensures that the provided value is valid for the underlying type and
// is properly initialized. We've ensured that a value is already present and previously
// initialized.
unsafe {
self.data.replace_unchecked(Self::ROW, value);
}
} else {
#[cfg(feature = "std")]
if !SEND {
self.origin_thread_id = Some(std::thread::current().id());
}
self.data.push(value);
}
*self.added_ticks.deref_mut() = change_ticks.added;
*self.changed_ticks.deref_mut() = change_ticks.changed;
self.changed_by
.as_ref()
.map(|changed_by| changed_by.deref_mut())
.assign(caller);
}
/// Removes a value from the resource, if present.
///
/// # Panics
/// If `SEND` is false, this will panic if a value is present and is not removed from the
/// original thread it was inserted from.
#[inline]
#[must_use = "The returned pointer to the removed component should be used or dropped"]
pub(crate) fn remove(&mut self) -> Option<(OwningPtr<'_>, ComponentTicks, MaybeLocation)> {
if !self.is_present() {
return None;
}
if !SEND {
self.validate_access();
}
// SAFETY: We've already validated that the row is present.
let res = unsafe { self.data.swap_remove_and_forget_unchecked(Self::ROW) };
let caller = self
.changed_by
.as_ref()
// SAFETY: This function is being called through an exclusive mutable reference to Self
.map(|changed_by| unsafe { *changed_by.deref_mut() });
// SAFETY: This function is being called through an exclusive mutable reference to Self, which
// makes it sound to read these ticks.
unsafe {
Some((
res,
ComponentTicks {
added: self.added_ticks.read(),
changed: self.changed_ticks.read(),
},
caller,
))
}
}
/// Removes a value from the resource, if present, and drops it.
///
/// # Panics
/// If `SEND` is false, this will panic if a value is present and is not
/// accessed from the original thread it was inserted in.
#[inline]
pub(crate) fn remove_and_drop(&mut self) {
if self.is_present() {
self.validate_access();
self.data.clear();
}
}
pub(crate) fn check_change_ticks(&mut self, change_tick: Tick) {
self.added_ticks.get_mut().check_tick(change_tick);
self.changed_ticks.get_mut().check_tick(change_tick);
}
}
/// The backing store for all [`Resource`]s stored in the [`World`].
///
/// [`Resource`]: crate::resource::Resource
/// [`World`]: crate::world::World
#[derive(Default)]
pub struct Resources<const SEND: bool> {
resources: SparseSet<ComponentId, ResourceData<SEND>>,
}
impl<const SEND: bool> Resources<SEND> {
/// The total number of resources stored in the [`World`]
///
/// [`World`]: crate::world::World
#[inline]
pub fn len(&self) -> usize {
self.resources.len()
}
/// Iterate over all resources that have been initialized, i.e. given a [`ComponentId`]
pub fn iter(&self) -> impl Iterator<Item = (ComponentId, &ResourceData<SEND>)> {
self.resources.iter().map(|(id, data)| (*id, data))
}
/// Returns true if there are no resources stored in the [`World`],
/// false otherwise.
///
/// [`World`]: crate::world::World
#[inline]
pub fn is_empty(&self) -> bool {
self.resources.is_empty()
}
/// Gets read-only access to a resource, if it exists.
#[inline]
pub fn get(&self, component_id: ComponentId) -> Option<&ResourceData<SEND>> {
self.resources.get(component_id)
}
/// Clears all resources.
#[inline]
pub fn clear(&mut self) {
self.resources.clear();
}
/// Gets mutable access to a resource, if it exists.
#[inline]
pub(crate) fn get_mut(&mut self, component_id: ComponentId) -> Option<&mut ResourceData<SEND>> {
self.resources.get_mut(component_id)
}
/// Fetches or initializes a new resource and returns back its underlying column.
///
/// # Panics
/// Will panic if `component_id` is not valid for the provided `components`
/// If `SEND` is true, this will panic if `component_id`'s `ComponentInfo` is not registered as being `Send` + `Sync`.
pub(crate) fn initialize_with(
&mut self,
component_id: ComponentId,
components: &Components,
f: impl FnOnce() -> ArchetypeComponentId,
) -> &mut ResourceData<SEND> {
self.resources.get_or_insert_with(component_id, || {
let component_info = components.get_info(component_id).unwrap();
if SEND {
assert!(
component_info.is_send_and_sync(),
"Send + Sync resource {} initialized as non_send. It may have been inserted via World::insert_non_send_resource by accident. Try using World::insert_resource instead.",
component_info.name(),
);
}
// SAFETY: component_info.drop() is valid for the types that will be inserted.
let data = unsafe {
BlobVec::new(
component_info.layout(),
component_info.drop(),
1
)
};
ResourceData {
data: ManuallyDrop::new(data),
added_ticks: UnsafeCell::new(Tick::new(0)),
changed_ticks: UnsafeCell::new(Tick::new(0)),
type_name: String::from(component_info.name()),
id: f(),
#[cfg(feature = "std")]
origin_thread_id: None,
changed_by: MaybeLocation::caller().map(UnsafeCell::new),
}
})
}
pub(crate) fn check_change_ticks(&mut self, change_tick: Tick) {
for info in self.resources.values_mut() {
info.check_change_ticks(change_tick);
}
}
}

Some files were not shown because too many files have changed in this diff Show More