@@ -50,18 +50,38 @@ impl AbortController {
50
50
}
51
51
}
52
52
53
- pub fn abort ( & self , reason : impl Into < String > ) {
54
- let inner = & * self . inner ;
55
- let mutex = inner. state ;
56
-
57
- let mutex. lock( ) . abort( reason) ;
58
- }
59
-
53
+ /// Get an associated `AbortSignal` object for this controller. This method can
54
+ /// be called at any time (i.e. even after the controller has been cancelled),
55
+ /// any number of times (i.e. to pass a same signal to multiple JS functions),
56
+ /// and from any thread.
60
57
pub fn signal ( & self ) -> AbortSignal {
61
58
AbortSignal {
62
59
inner : self . inner . clone ( ) ,
63
60
}
64
61
}
62
+
63
+ /// Abort the controller, causing the JS side `signal` to fire.
64
+ ///
65
+ /// This method can be called at any time (i.e. even before the controller has been armed,
66
+ /// or after it has been disarmed), and from any thread.
67
+ pub fn abort ( & self , reason : impl Into < String > ) {
68
+ let call_abort = self . inner . lock ( ) . abort ( reason) ;
69
+ if let Some ( call_abort) = call_abort {
70
+ call_abort
71
+ . abort_cb
72
+ . call_on_js_thread ( ( call_abort. abort_reason , ) ) ;
73
+ }
74
+ }
75
+
76
+ /// Disarm the controller, so that it can no longer be aborted.
77
+ ///
78
+ /// Once a controller has been disarmed, it's abort status will not change anymore. It is
79
+ /// recommended to call this method once it is known that the signal is no longer needed
80
+ /// on the JS side, e.g. when the called JS function has returned, as this will prevent the
81
+ /// overhead of implicit abortion when the controller is dropped.
82
+ pub fn disarm ( & self ) {
83
+ self . inner . lock ( ) . disarm ( ) ;
84
+ }
65
85
}
66
86
67
87
impl Drop for AbortController {
@@ -118,7 +138,7 @@ impl AbortControllerInner {
118
138
// immediately and synchronously propagate the abort to the JS controller object.
119
139
120
140
// ... but let's not hold on to the state mutex while calling the abort callback
121
- * state = AbortControllerInnerState :: Disabled ;
141
+ * state = AbortControllerInnerState :: Disarmed ;
122
142
mem:: drop ( state) ;
123
143
124
144
// Call the abort callback
@@ -207,18 +227,88 @@ enum AbortControllerInnerState {
207
227
/// Transitions:
208
228
/// - Calling `abort()` will result in calling the abort callback, and move to the `Disabled` state
209
229
/// - Calling `disable()` is a no-op
210
- Armed ( JsCallback < ( String , ) , ( ) > ) ,
230
+ Armed ( Root < JsAbortController > , JsCallback < ( String , ) , ( ) > ) ,
231
+
232
+ /// The `AbortController` has been disarmed, though it was actually never armed.
233
+ ///
234
+ /// Transitions:
235
+ /// - Calling `abort()` is a no-op
236
+ /// - Initializing the JS counterpart will move to the `Disarmed` state
237
+ UninitializedDisarmed ,
211
238
212
239
/// The `AbortController` has been disabled, either by being aborted or by calling `disable()`.
213
240
/// It is still possible to obtain a `signal` from the controller, but it's abort status
214
241
/// will not change anymore.
215
242
///
216
243
/// Any transitions from this state is a no-op.
217
- Disabled ,
244
+ Disarmed ( Root < JsAbortController > ) ,
218
245
}
219
246
220
247
impl AbortControllerInnerState {
221
- fn abort ( self , reason : impl Into < String > ) -> Self {
222
- todo ! ( )
248
+ fn arm (
249
+ & mut self ,
250
+ js_controller : Root < JsAbortController > ,
251
+ abort_cb : JsCallback < ( String , ) , ( ) > ,
252
+ ) -> Option < CallAbortDetails > {
253
+ match self {
254
+ Self :: Uninitialized => {
255
+ * self = Self :: Armed ( js_controller, abort_cb) ;
256
+ None
257
+ }
258
+ Self :: AbortedBeforeArmed ( abort_reason) => {
259
+ let abort_reason = abort_reason. clone ( ) ;
260
+ * self = Self :: Disarmed ( js_controller) ;
261
+ Some ( CallAbortDetails {
262
+ abort_reason,
263
+ abort_cb,
264
+ } )
265
+ }
266
+ Self :: UninitializedDisarmed => {
267
+ * self = Self :: Disarmed ( js_controller) ;
268
+ None
269
+ }
270
+ _ => None ,
271
+ }
272
+ }
273
+
274
+ fn abort ( & mut self , reason : impl Into < String > ) -> Option < CallAbortDetails > {
275
+ let current = mem:: replace ( self , Self :: Uninitialized ) ;
276
+ match current {
277
+ Self :: Uninitialized => {
278
+ * self = Self :: AbortedBeforeArmed ( reason. into ( ) ) ;
279
+ None
280
+ }
281
+ Self :: Armed ( js_controller, abort_cb) => {
282
+ * self = Self :: Disarmed ( js_controller) ;
283
+ Some ( CallAbortDetails {
284
+ abort_reason : reason. into ( ) ,
285
+ abort_cb,
286
+ } )
287
+ }
288
+ other => {
289
+ * self = other;
290
+ None
291
+ }
292
+ }
223
293
}
294
+
295
+ fn disarm ( & mut self ) {
296
+ let current = mem:: replace ( self , Self :: Uninitialized ) ;
297
+ match current {
298
+ Self :: Uninitialized => {
299
+ * self = Self :: UninitializedDisarmed ;
300
+ }
301
+ Self :: Armed ( js_controller, _) => {
302
+ * self = Self :: Disarmed ( js_controller) ;
303
+ }
304
+ other => {
305
+ * self = other;
306
+ }
307
+ }
308
+ }
309
+ }
310
+
311
+ struct CallAbortDetails {
312
+ abort_reason : String ,
313
+ abort_cb : JsCallback < ( String , ) , ( ) > ,
224
314
}
0 commit comments