@@ -61,6 +61,8 @@ pub(crate) struct OperateScope<Request, Response, Streams> {
61
61
exit_scope : Option < Entity > ,
62
62
/// Cancellation finishes at this node
63
63
finish_cancel : Entity ,
64
+ /// Settings for the scope
65
+ settings : ScopeSettings ,
64
66
_ignore : std:: marker:: PhantomData < ( Request , Response , Streams ) > ,
65
67
}
66
68
@@ -71,13 +73,12 @@ impl<Request, Response, Streams> Clone for OperateScope<Request, Response, Strea
71
73
terminal : self . terminal ,
72
74
exit_scope : self . exit_scope ,
73
75
finish_cancel : self . finish_cancel ,
76
+ settings : self . settings . clone ( ) ,
74
77
_ignore : Default :: default ( ) ,
75
78
}
76
79
}
77
80
}
78
81
79
- impl < Request , Response , Streams > Copy for OperateScope < Request , Response , Streams > { }
80
-
81
82
impl < Request , Response , Streams > OperateScope < Request , Response , Streams > {
82
83
pub ( crate ) fn terminal ( & self ) -> Entity {
83
84
self . terminal
@@ -107,22 +108,35 @@ impl ScopedSession {
107
108
}
108
109
}
109
110
111
+ #[ derive( Component ) ]
112
+ struct ScopeSettingsStorage ( ScopeSettings ) ;
113
+
110
114
#[ derive( Component ) ]
111
115
pub ( crate ) enum ScopedSessionStatus {
112
116
Ongoing ,
113
117
Finished ,
118
+ /// The scope was asked to cleanup from an external source, but it has an
119
+ /// uninterruptible setting. We are waiting for a termination or internal
120
+ /// cancel to trigger before doing a cleanup.
121
+ DeferredCleanup ,
122
+ /// The scope has already begun the cleanup process
114
123
Cleanup ,
115
124
Cancelled ( Cancellation ) ,
116
125
}
117
126
118
127
impl ScopedSessionStatus {
119
- fn to_cleanup ( & mut self ) -> bool {
128
+ fn to_cleanup ( & mut self , uninterruptible : bool ) -> bool {
120
129
if matches ! ( self , Self :: Cleanup ) {
121
130
return false ;
122
131
}
123
132
124
- * self = Self :: Cleanup ;
125
- true
133
+ if uninterruptible {
134
+ * self = Self :: DeferredCleanup ;
135
+ return false ;
136
+ } else {
137
+ * self = Self :: Cleanup ;
138
+ return true ;
139
+ }
126
140
}
127
141
128
142
pub ( crate ) fn to_finished ( & mut self ) -> bool {
@@ -132,11 +146,19 @@ impl ScopedSessionStatus {
132
146
* self = Self :: Finished ;
133
147
return true ;
134
148
}
149
+
150
+ if matches ! ( self , Self :: DeferredCleanup ) {
151
+ // We've been waiting for the scope to finish before beginning
152
+ // cleanup because the scope is uninterruptible.
153
+ * self = Self :: Cleanup ;
154
+ return true ;
155
+ }
156
+
135
157
false
136
158
}
137
159
138
160
fn to_cancelled ( & mut self , cancellation : Cancellation ) -> bool {
139
- if matches ! ( self , Self :: Ongoing ) {
161
+ if matches ! ( self , Self :: Ongoing | Self :: DeferredCleanup ) {
140
162
* self = Self :: Cancelled ( cancellation) ;
141
163
return true ;
142
164
}
@@ -169,7 +191,6 @@ where
169
191
source_mut. insert ( (
170
192
InputBundle :: < Request > :: new ( ) ,
171
193
ScopeEntryStorage ( self . enter_scope ) ,
172
- FinishedStagingStorage ( self . terminal ) ,
173
194
ScopeContents :: new ( ) ,
174
195
ScopedSessionStorage :: default ( ) ,
175
196
TerminalStorage ( self . terminal ) ,
@@ -178,6 +199,7 @@ where
178
199
FinalizeScopeCleanup ( Self :: finalize_scope_cleanup) ,
179
200
BeginCancelStorage :: default ( ) ,
180
201
FinishCancelStorage ( self . finish_cancel ) ,
202
+ ScopeSettingsStorage ( self . settings ) ,
181
203
) ) ;
182
204
183
205
if let Some ( exit_scope) = self . exit_scope {
@@ -218,14 +240,17 @@ where
218
240
OperationCleanup { source, session, world, roster } : OperationCleanup
219
241
) -> OperationResult {
220
242
let mut source_mut = world. get_entity_mut ( source) . or_broken ( ) ?;
243
+ let uninterruptible = source_mut. get :: < ScopeSettingsStorage > ( ) . or_broken ( ) ?. 0
244
+ . is_uninterruptible ( ) ;
245
+
221
246
let pairs: SmallVec < [ _ ; 16 ] > = source_mut
222
247
. get_mut :: < ScopedSessionStorage > ( )
223
248
. or_broken ( ) ?
224
249
. 0
225
250
. iter_mut ( )
226
251
. filter ( |pair| pair. parent_session == session)
227
252
. filter_map ( |p| {
228
- if p. status . to_cleanup ( ) {
253
+ if p. status . to_cleanup ( uninterruptible ) {
229
254
Some ( p. scoped_session )
230
255
} else {
231
256
None
@@ -241,15 +266,15 @@ where
241
266
242
267
for scoped_session in pairs {
243
268
let source_ref = world. get_entity ( source) . or_broken ( ) ?;
244
- let staging_node = source_ref. get :: < FinishedStagingStorage > ( ) . or_broken ( ) ?. 0 ;
269
+ let terminal = source_ref. get :: < TerminalStorage > ( ) . or_broken ( ) ?. 0 ;
245
270
let nodes = source_ref. get :: < ScopeContents > ( ) . or_broken ( ) ?. nodes ( ) . clone ( ) ;
246
271
for node in nodes {
247
272
OperationCleanup { source : node, session : scoped_session, world, roster } . clean ( ) ;
248
273
}
249
274
250
275
// OperateScope::cleanup gets called when the entire scope is being cancelled
251
276
// so we need to clear out the staging node as well.
252
- OperationCleanup { source : staging_node , session : scoped_session, world, roster } . clean ( ) ;
277
+ OperationCleanup { source : terminal , session : scoped_session, world, roster } . clean ( ) ;
253
278
}
254
279
255
280
Ok ( ( ) )
@@ -261,7 +286,6 @@ where
261
286
}
262
287
263
288
let source_ref = reachability. world . get_entity ( reachability. source ) . or_broken ( ) ?;
264
- let staging = source_ref. get :: < FinishedStagingStorage > ( ) . or_broken ( ) ?. 0 ;
265
289
266
290
if let Some ( pair) = source_ref
267
291
. get :: < ScopedSessionStorage > ( ) . or_broken ( ) ?
@@ -272,13 +296,9 @@ where
272
296
pair. scoped_session ,
273
297
reachability. source ,
274
298
reachability. world ,
275
- & mut visited
299
+ & mut visited,
276
300
) ;
277
301
278
- if scoped_reachability. check_upstream ( staging) ? {
279
- return Ok ( true ) ;
280
- }
281
-
282
302
let terminal = source_ref. get :: < TerminalStorage > ( ) . or_broken ( ) ?. 0 ;
283
303
if scoped_reachability. check_upstream ( terminal) ? {
284
304
return Ok ( true ) ;
@@ -343,6 +363,7 @@ where
343
363
terminal,
344
364
exit_scope,
345
365
finish_cancel,
366
+ settings,
346
367
_ignore : Default :: default ( ) ,
347
368
} ;
348
369
@@ -478,8 +499,14 @@ where
478
499
// so we'll return a broken error here.
479
500
None . or_broken ( ) ?;
480
501
}
502
+ ScopedSessionStatus :: DeferredCleanup => {
503
+ // We shouldn't be in this function if the session is in a
504
+ // deferred cleanup state. We should be waiting for a finish
505
+ // or a cancellation to occur.
506
+ None . or_broken ( ) ?;
507
+ }
481
508
ScopedSessionStatus :: Finished => {
482
- let staging = source_mut. get :: < FinishedStagingStorage > ( ) . or_broken ( ) ?. 0 ;
509
+ let terminal = source_mut. get :: < TerminalStorage > ( ) . or_broken ( ) ?. 0 ;
483
510
let ( target, blocker) = source_mut. get_mut :: < ExitTargetStorage > ( )
484
511
. and_then ( |mut storage| storage. map . remove ( & scoped_session) )
485
512
. map ( |exit| ( exit. target , exit. blocker ) )
@@ -491,7 +518,7 @@ where
491
518
. or_broken ( ) ?;
492
519
493
520
let response = clean. world
494
- . get_mut :: < Staging < Response > > ( staging ) . or_broken ( ) ?. 0
521
+ . get_mut :: < Staging < Response > > ( terminal ) . or_broken ( ) ?. 0
495
522
. remove ( & clean. session ) . or_broken ( ) ?;
496
523
clean. world . get_entity_mut ( target) . or_broken ( ) ?. give_input (
497
524
pair. parent_session , response, clean. roster ,
@@ -564,15 +591,6 @@ pub struct FinalizeScopeCleanup(pub(crate) fn(OperationCleanup) -> OperationResu
564
591
#[ derive( Component ) ]
565
592
struct ScopeEntryStorage ( Entity ) ;
566
593
567
- #[ derive( Component ) ]
568
- pub struct FinishedStagingStorage ( Entity ) ;
569
-
570
- impl FinishedStagingStorage {
571
- pub fn get ( & self ) -> Entity {
572
- self . 0
573
- }
574
- }
575
-
576
594
pub ( crate ) struct Terminate < T > {
577
595
_ignore : std:: marker:: PhantomData < T > ,
578
596
}
@@ -600,6 +618,7 @@ where
600
618
fn setup ( self , OperationSetup { source, world } : OperationSetup ) -> OperationResult {
601
619
world. entity_mut ( source) . insert ( (
602
620
InputBundle :: < T > :: new ( ) ,
621
+ SingleInputStorage :: empty ( ) ,
603
622
Staging :: < T > :: new ( ) ,
604
623
) ) ;
605
624
Ok ( ( ) )
@@ -651,13 +670,17 @@ where
651
670
Ok ( ( ) )
652
671
}
653
672
654
- fn is_reachable ( reachability : OperationReachability ) -> ReachabilityResult {
673
+ fn is_reachable ( mut reachability : OperationReachability ) -> ReachabilityResult {
655
674
if reachability. has_input :: < T > ( ) ? {
656
675
return Ok ( true ) ;
657
676
}
658
677
659
678
let staging = reachability. world . get :: < Staging < T > > ( reachability. source ) . or_broken ( ) ?;
660
- Ok ( staging. 0 . contains_key ( & reachability. session ) )
679
+ if staging. 0 . contains_key ( & reachability. session ) {
680
+ return Ok ( true ) ;
681
+ }
682
+
683
+ SingleInputStorage :: is_reachable ( & mut reachability)
661
684
}
662
685
}
663
686
0 commit comments