Skip to content

Commit 6fa3d40

Browse files
committed
stash
1 parent 2b867a0 commit 6fa3d40

File tree

1 file changed

+102
-12
lines changed

1 file changed

+102
-12
lines changed

packages/core-bridge/src/helpers/abort_controller.rs

Lines changed: 102 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,18 +50,38 @@ impl AbortController {
5050
}
5151
}
5252

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.
6057
pub fn signal(&self) -> AbortSignal {
6158
AbortSignal {
6259
inner: self.inner.clone(),
6360
}
6461
}
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+
}
6585
}
6686

6787
impl Drop for AbortController {
@@ -118,7 +138,7 @@ impl AbortControllerInner {
118138
// immediately and synchronously propagate the abort to the JS controller object.
119139

120140
// ... but let's not hold on to the state mutex while calling the abort callback
121-
*state = AbortControllerInnerState::Disabled;
141+
*state = AbortControllerInnerState::Disarmed;
122142
mem::drop(state);
123143

124144
// Call the abort callback
@@ -207,18 +227,88 @@ enum AbortControllerInnerState {
207227
/// Transitions:
208228
/// - Calling `abort()` will result in calling the abort callback, and move to the `Disabled` state
209229
/// - 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,
211238

212239
/// The `AbortController` has been disabled, either by being aborted or by calling `disable()`.
213240
/// It is still possible to obtain a `signal` from the controller, but it's abort status
214241
/// will not change anymore.
215242
///
216243
/// Any transitions from this state is a no-op.
217-
Disabled,
244+
Disarmed(Root<JsAbortController>),
218245
}
219246

220247
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+
}
223293
}
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,), ()>,
224314
}

0 commit comments

Comments
 (0)