@@ -2,8 +2,11 @@ use alloc::{boxed::Box, collections::BTreeSet, vec::Vec};
2
2
3
3
use bevy_platform:: collections:: HashMap ;
4
4
5
- use crate :: system:: IntoSystem ;
6
- use crate :: world:: World ;
5
+ use crate :: {
6
+ schedule:: { SystemKey , SystemSetKey } ,
7
+ system:: IntoSystem ,
8
+ world:: World ,
9
+ } ;
7
10
8
11
use super :: {
9
12
is_apply_deferred, ApplyDeferred , DiGraph , Direction , NodeId , ReportCycles , ScheduleBuildError ,
@@ -36,29 +39,26 @@ impl AutoInsertApplyDeferredPass {
36
39
self . auto_sync_node_ids
37
40
. get ( & distance)
38
41
. copied ( )
39
- . or_else ( || {
40
- let node_id = self . add_auto_sync ( graph) ;
42
+ . unwrap_or_else ( || {
43
+ let node_id = NodeId :: System ( self . add_auto_sync ( graph) ) ;
41
44
self . auto_sync_node_ids . insert ( distance, node_id) ;
42
- Some ( node_id)
45
+ node_id
43
46
} )
44
- . unwrap ( )
45
47
}
46
48
/// add an [`ApplyDeferred`] system with no config
47
- fn add_auto_sync ( & mut self , graph : & mut ScheduleGraph ) -> NodeId {
48
- let id = NodeId :: System ( graph. systems . len ( ) ) ;
49
-
50
- graph
49
+ fn add_auto_sync ( & mut self , graph : & mut ScheduleGraph ) -> SystemKey {
50
+ let key = graph
51
51
. systems
52
- . push ( SystemNode :: new ( Box :: new ( IntoSystem :: into_system (
52
+ . insert ( SystemNode :: new ( Box :: new ( IntoSystem :: into_system (
53
53
ApplyDeferred ,
54
54
) ) ) ) ;
55
- graph. system_conditions . push ( Vec :: new ( ) ) ;
55
+ graph. system_conditions . insert ( key , Vec :: new ( ) ) ;
56
56
57
57
// ignore ambiguities with auto sync points
58
58
// They aren't under user control, so no one should know or care.
59
- graph. ambiguous_with_all . insert ( id ) ;
59
+ graph. ambiguous_with_all . insert ( NodeId :: System ( key ) ) ;
60
60
61
- id
61
+ key
62
62
}
63
63
}
64
64
@@ -80,84 +80,90 @@ impl ScheduleBuildPass for AutoInsertApplyDeferredPass {
80
80
let mut sync_point_graph = dependency_flattened. clone ( ) ;
81
81
let topo = graph. topsort_graph ( dependency_flattened, ReportCycles :: Dependency ) ?;
82
82
83
- fn set_has_conditions ( graph : & ScheduleGraph , node : NodeId ) -> bool {
84
- !graph. set_conditions_at ( node ) . is_empty ( )
83
+ fn set_has_conditions ( graph : & ScheduleGraph , set : SystemSetKey ) -> bool {
84
+ !graph. set_conditions_at ( set ) . is_empty ( )
85
85
|| graph
86
86
. hierarchy ( )
87
87
. graph ( )
88
- . edges_directed ( node, Direction :: Incoming )
89
- . any ( |( parent, _) | set_has_conditions ( graph, parent) )
88
+ . edges_directed ( NodeId :: Set ( set) , Direction :: Incoming )
89
+ . any ( |( parent, _) | {
90
+ parent
91
+ . as_set ( )
92
+ . is_some_and ( |p| set_has_conditions ( graph, p) )
93
+ } )
90
94
}
91
95
92
- fn system_has_conditions ( graph : & ScheduleGraph , node : NodeId ) -> bool {
93
- assert ! ( node. is_system( ) ) ;
94
- !graph. system_conditions [ node. index ( ) ] . is_empty ( )
96
+ fn system_has_conditions ( graph : & ScheduleGraph , key : SystemKey ) -> bool {
97
+ !graph. system_conditions [ key] . is_empty ( )
95
98
|| graph
96
99
. hierarchy ( )
97
100
. graph ( )
98
- . edges_directed ( node, Direction :: Incoming )
99
- . any ( |( parent, _) | set_has_conditions ( graph, parent) )
101
+ . edges_directed ( NodeId :: System ( key) , Direction :: Incoming )
102
+ . any ( |( parent, _) | {
103
+ parent
104
+ . as_set ( )
105
+ . is_some_and ( |p| set_has_conditions ( graph, p) )
106
+ } )
100
107
}
101
108
102
- let mut system_has_conditions_cache = HashMap :: < usize , bool > :: default ( ) ;
103
- let mut is_valid_explicit_sync_point = |system : NodeId | {
104
- let index = system. index ( ) ;
105
- is_apply_deferred ( & graph. systems [ index] . get ( ) . unwrap ( ) . system )
109
+ let mut system_has_conditions_cache = HashMap :: < SystemKey , bool > :: default ( ) ;
110
+ let mut is_valid_explicit_sync_point = |key : SystemKey | {
111
+ is_apply_deferred ( & graph. systems [ key] . get ( ) . unwrap ( ) . system )
106
112
&& !* system_has_conditions_cache
107
- . entry ( index )
108
- . or_insert_with ( || system_has_conditions ( graph, system ) )
113
+ . entry ( key )
114
+ . or_insert_with ( || system_has_conditions ( graph, key ) )
109
115
} ;
110
116
111
117
// Calculate the distance for each node.
112
118
// The "distance" is the number of sync points between a node and the beginning of the graph.
113
119
// Also store if a preceding edge would have added a sync point but was ignored to add it at
114
120
// a later edge that is not ignored.
115
- let mut distances_and_pending_sync: HashMap < usize , ( u32 , bool ) > =
121
+ let mut distances_and_pending_sync: HashMap < SystemKey , ( u32 , bool ) > =
116
122
HashMap :: with_capacity_and_hasher ( topo. len ( ) , Default :: default ( ) ) ;
117
123
118
124
// Keep track of any explicit sync nodes for a specific distance.
119
125
let mut distance_to_explicit_sync_node: HashMap < u32 , NodeId > = HashMap :: default ( ) ;
120
126
121
127
// Determine the distance for every node and collect the explicit sync points.
122
128
for node in & topo {
129
+ let & NodeId :: System ( key) = node else {
130
+ panic ! ( "Encountered a non-system node in the flattened dependency graph: {node:?}" ) ;
131
+ } ;
132
+
123
133
let ( node_distance, mut node_needs_sync) = distances_and_pending_sync
124
- . get ( & node . index ( ) )
134
+ . get ( & key )
125
135
. copied ( )
126
136
. unwrap_or_default ( ) ;
127
137
128
- if is_valid_explicit_sync_point ( * node ) {
138
+ if is_valid_explicit_sync_point ( key ) {
129
139
// The distance of this sync point does not change anymore as the iteration order
130
140
// makes sure that this node is no unvisited target of another node.
131
141
// Because of this, the sync point can be stored for this distance to be reused as
132
142
// automatically added sync points later.
133
- distance_to_explicit_sync_node. insert ( node_distance, * node ) ;
143
+ distance_to_explicit_sync_node. insert ( node_distance, NodeId :: System ( key ) ) ;
134
144
135
145
// This node just did a sync, so the only reason to do another sync is if one was
136
146
// explicitly scheduled afterwards.
137
147
node_needs_sync = false ;
138
148
} else if !node_needs_sync {
139
149
// No previous node has postponed sync points to add so check if the system itself
140
150
// has deferred params that require a sync point to apply them.
141
- node_needs_sync = graph. systems [ node. index ( ) ]
142
- . get ( )
143
- . unwrap ( )
144
- . system
145
- . has_deferred ( ) ;
151
+ node_needs_sync = graph. systems [ key] . get ( ) . unwrap ( ) . system . has_deferred ( ) ;
146
152
}
147
153
148
154
for target in dependency_flattened. neighbors_directed ( * node, Direction :: Outgoing ) {
149
- let ( target_distance, target_pending_sync) = distances_and_pending_sync
150
- . entry ( target. index ( ) )
151
- . or_default ( ) ;
155
+ let NodeId :: System ( target) = target else {
156
+ panic ! ( "Encountered a non-system node in the flattened dependency graph: {target:?}" ) ;
157
+ } ;
158
+ let ( target_distance, target_pending_sync) =
159
+ distances_and_pending_sync. entry ( target) . or_default ( ) ;
152
160
153
161
let mut edge_needs_sync = node_needs_sync;
154
162
if node_needs_sync
155
- && !graph. systems [ target. index ( ) ]
156
- . get ( )
157
- . unwrap ( )
158
- . system
159
- . is_exclusive ( )
160
- && self . no_sync_edges . contains ( & ( * node, target) )
163
+ && !graph. systems [ target] . get ( ) . unwrap ( ) . system . is_exclusive ( )
164
+ && self
165
+ . no_sync_edges
166
+ . contains ( & ( * node, NodeId :: System ( target) ) )
161
167
{
162
168
// The node has deferred params to apply, but this edge is ignoring sync points.
163
169
// Mark the target as 'delaying' those commands to a future edge and the current
@@ -182,14 +188,20 @@ impl ScheduleBuildPass for AutoInsertApplyDeferredPass {
182
188
// Find any edges which have a different number of sync points between them and make sure
183
189
// there is a sync point between them.
184
190
for node in & topo {
191
+ let & NodeId :: System ( key) = node else {
192
+ panic ! ( "Encountered a non-system node in the flattened dependency graph: {node:?}" ) ;
193
+ } ;
185
194
let ( node_distance, _) = distances_and_pending_sync
186
- . get ( & node . index ( ) )
195
+ . get ( & key )
187
196
. copied ( )
188
197
. unwrap_or_default ( ) ;
189
198
190
199
for target in dependency_flattened. neighbors_directed ( * node, Direction :: Outgoing ) {
200
+ let NodeId :: System ( target) = target else {
201
+ panic ! ( "Encountered a non-system node in the flattened dependency graph: {target:?}" ) ;
202
+ } ;
191
203
let ( target_distance, _) = distances_and_pending_sync
192
- . get ( & target. index ( ) )
204
+ . get ( & target)
193
205
. copied ( )
194
206
. unwrap_or_default ( ) ;
195
207
@@ -198,7 +210,7 @@ impl ScheduleBuildPass for AutoInsertApplyDeferredPass {
198
210
continue ;
199
211
}
200
212
201
- if is_apply_deferred ( & graph. systems [ target. index ( ) ] . get ( ) . unwrap ( ) . system ) {
213
+ if is_apply_deferred ( & graph. systems [ target] . get ( ) . unwrap ( ) . system ) {
202
214
// We don't need to insert a sync point since ApplyDeferred is a sync point
203
215
// already!
204
216
continue ;
@@ -210,10 +222,10 @@ impl ScheduleBuildPass for AutoInsertApplyDeferredPass {
210
222
. unwrap_or_else ( || self . get_sync_point ( graph, target_distance) ) ;
211
223
212
224
sync_point_graph. add_edge ( * node, sync_point) ;
213
- sync_point_graph. add_edge ( sync_point, target) ;
225
+ sync_point_graph. add_edge ( sync_point, NodeId :: System ( target) ) ;
214
226
215
227
// The edge without the sync point is now redundant.
216
- sync_point_graph. remove_edge ( * node, target) ;
228
+ sync_point_graph. remove_edge ( * node, NodeId :: System ( target) ) ;
217
229
}
218
230
}
219
231
@@ -223,34 +235,39 @@ impl ScheduleBuildPass for AutoInsertApplyDeferredPass {
223
235
224
236
fn collapse_set (
225
237
& mut self ,
226
- set : NodeId ,
227
- systems : & [ NodeId ] ,
238
+ set : SystemSetKey ,
239
+ systems : & [ SystemKey ] ,
228
240
dependency_flattened : & DiGraph ,
229
241
) -> impl Iterator < Item = ( NodeId , NodeId ) > {
230
242
if systems. is_empty ( ) {
231
243
// collapse dependencies for empty sets
232
- for a in dependency_flattened. neighbors_directed ( set, Direction :: Incoming ) {
233
- for b in dependency_flattened. neighbors_directed ( set, Direction :: Outgoing ) {
234
- if self . no_sync_edges . contains ( & ( a, set) )
235
- && self . no_sync_edges . contains ( & ( set, b) )
244
+ for a in dependency_flattened. neighbors_directed ( NodeId :: Set ( set) , Direction :: Incoming )
245
+ {
246
+ for b in
247
+ dependency_flattened. neighbors_directed ( NodeId :: Set ( set) , Direction :: Outgoing )
248
+ {
249
+ if self . no_sync_edges . contains ( & ( a, NodeId :: Set ( set) ) )
250
+ && self . no_sync_edges . contains ( & ( NodeId :: Set ( set) , b) )
236
251
{
237
252
self . no_sync_edges . insert ( ( a, b) ) ;
238
253
}
239
254
}
240
255
}
241
256
} else {
242
- for a in dependency_flattened. neighbors_directed ( set, Direction :: Incoming ) {
257
+ for a in dependency_flattened. neighbors_directed ( NodeId :: Set ( set) , Direction :: Incoming )
258
+ {
243
259
for & sys in systems {
244
- if self . no_sync_edges . contains ( & ( a, set) ) {
245
- self . no_sync_edges . insert ( ( a, sys) ) ;
260
+ if self . no_sync_edges . contains ( & ( a, NodeId :: Set ( set) ) ) {
261
+ self . no_sync_edges . insert ( ( a, NodeId :: System ( sys) ) ) ;
246
262
}
247
263
}
248
264
}
249
265
250
- for b in dependency_flattened. neighbors_directed ( set, Direction :: Outgoing ) {
266
+ for b in dependency_flattened. neighbors_directed ( NodeId :: Set ( set) , Direction :: Outgoing )
267
+ {
251
268
for & sys in systems {
252
- if self . no_sync_edges . contains ( & ( set, b) ) {
253
- self . no_sync_edges . insert ( ( sys, b) ) ;
269
+ if self . no_sync_edges . contains ( & ( NodeId :: Set ( set) , b) ) {
270
+ self . no_sync_edges . insert ( ( NodeId :: System ( sys) , b) ) ;
254
271
}
255
272
}
256
273
}
0 commit comments