bevy/crates/bevy_ecs/src
Chris Russell 0ee937784e
Simplify self-edge checking in schedule building (#20015)
# Objective

Make the schedule graph code more understandable, and replace some
panics with `Result`s.

I found the `check_edges` and `check_hierarchy` functions [a little
confusing](https://github.com/bevyengine/bevy/pull/19352#discussion_r2181486099),
as they combined two concerns: Initializing graph nodes for system sets,
and checking for self-edges on system sets. It was hard to understand
the self-edge checks because it wasn't clear what `NodeId` was being
checked against! So, let's separate those concerns, and move them to
more appropriate locations.

Fix a bug where `schedule.configure_sets((SameSet, SameSet).chain());`
would panic with an unhelpful message: `assertion failed: index_a <
index_b`.

## Solution

Remove the `check_edges` and `check_hierarchy` functions, separating the
initialization behavior and the checking behavior and moving them where
they are easier to understand.

For initializing graph nodes, do this on-demand using the `entry` API by
replacing later `self.system_set_ids[&set]` calls with a
`self.system_sets.get_or_add_set(set)` method. This should avoid the
need for an extra pass over the graph and an extra lookup.

Unfortunately, implementing that method directly on `ScheduleGraph`
leads to borrowing errors as it borrows the entire `struct`. So, split
out the collections managing system sets into a separate `struct`.

For checking self-edges, move this check later so that it can be
reported by returning a `Result` from `Schedule::initialize` instead of
having to panic in `configure_set_inner`. The issue was that `iter_sccs`
does not report self-edges as cycles, since the resulting components
only have one node, but that later code assumes all edges point forward.
So, check for self-edges directly, immediately before calling
`iter_sccs`.

This also ensures we catch *every* way that self-edges can be added. The
previous code missed an edge case where `chain()`ing a set to itself
would create a self-edge and would trigger a `debug_assert`.
2025-07-08 18:09:45 +00:00
..
entity Unify filtering by id in EntityClonerBuilder (#19977) 2025-07-07 20:00:37 +00:00
error Don't create errors for ignored failed commands (#19718) 2025-06-29 16:34:20 +00:00
event Rename send_event and similar methods to write_event (#20017) 2025-07-07 22:05:16 +00:00
observer Observer trigger refactor (#19935) 2025-07-04 16:27:21 +00:00
query Have System::run_unsafe return Result. (#19145) 2025-07-03 21:48:09 +00:00
reflect ECS: put strings only used for debug behind a feature (#19558) 2025-06-18 20:15:25 +00:00
relationship Avoid early function invocation in EntityEntryCommands (#19978) 2025-07-07 20:02:55 +00:00
schedule Simplify self-edge checking in schedule building (#20015) 2025-07-08 18:09:45 +00:00
storage Bump typos to 1.34.0 (#20013) 2025-07-07 20:15:06 +00:00
system Rename send_event and similar methods to write_event (#20017) 2025-07-07 22:05:16 +00:00
world Rename send_event and similar methods to write_event (#20017) 2025-07-07 22:05:16 +00:00
archetype.rs Bump typos to 1.34.0 (#20013) 2025-07-07 20:15:06 +00:00
batching.rs Nonmax all rows (#19132) 2025-05-26 17:39:55 +00:00
bundle.rs Rename send_event and similar methods to write_event (#20017) 2025-07-07 22:05:16 +00:00
change_detection.rs Have System::run_unsafe return Result. (#19145) 2025-07-03 21:48:09 +00:00
component.rs Let Component::map_entities defer to MapEntities (#19414) 2025-06-23 21:05:04 +00:00
entity_disabling.rs bevy_reflect: Add clone registrations project-wide (#18307) 2025-03-17 18:32:35 +00:00
hierarchy.rs Add parent ID to the B0004 log message (#19980) 2025-07-07 20:04:59 +00:00
intern.rs Rename bevy_platform_support to bevy_platform (#18813) 2025-04-11 23:13:28 +00:00
label.rs Remove upcasting methods + Cleanup interned label code (#18984) 2025-05-26 15:38:12 +00:00
lib.rs Observer trigger refactor (#19935) 2025-07-04 16:27:21 +00:00
lifecycle.rs Rename send_event and similar methods to write_event (#20017) 2025-07-07 22:05:16 +00:00
name.rs Add newlines before impl blocks (#19746) 2025-06-22 23:07:02 +00:00
never.rs Use never_say_never hack to work around Rust 2024 regression for fn traits (#18804) 2025-04-14 19:59:48 +00:00
resource.rs refactor(utils): move SyncCell and SyncUnsafeCell to bevy_platform (#19305) 2025-05-27 04:57:26 +00:00
spawn.rs Remove Bundle::register_required_components (#19967) 2025-07-06 18:15:28 +00:00
traversal.rs Let query items borrow from query state to avoid needing to clone (#15396) 2025-06-16 21:05:41 +00:00