From 8a808f89fdb58c824016e31c64552e46cec3acb2 Mon Sep 17 00:00:00 2001 From: Gregory Terzian <2792687+gterzian@users.noreply.github.com> Date: Sat, 31 May 2025 14:32:46 +0800 Subject: [PATCH] dom: implement signal abort on controller and signal (#37192) Part of https://github.com/servo/servo/issues/34866 Implement signal abort, and part of running abort steps. Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com> --- components/script/dom/abortcontroller.rs | 27 ++++++- components/script/dom/abortsignal.rs | 79 +++++++++++++++++-- .../script_bindings/codegen/Bindings.conf | 4 + 3 files changed, 101 insertions(+), 9 deletions(-) diff --git a/components/script/dom/abortcontroller.rs b/components/script/dom/abortcontroller.rs index 3813cfdd51a..7911ad7cf47 100644 --- a/components/script/dom/abortcontroller.rs +++ b/components/script/dom/abortcontroller.rs @@ -3,24 +3,33 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use dom_struct::dom_struct; -use js::jsapi::Value; -use js::rust::{Handle, HandleObject}; +use js::rust::{HandleObject, HandleValue}; +use crate::dom::abortsignal::AbortSignal; use crate::dom::bindings::codegen::Bindings::AbortControllerBinding::AbortControllerMethods; use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto}; -use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::globalscope::GlobalScope; use crate::script_runtime::{CanGc, JSContext}; +/// #[dom_struct] pub(crate) struct AbortController { reflector_: Reflector, + + /// An AbortController object has an associated signal (an AbortSignal object). + signal: Dom, } impl AbortController { + /// fn new_inherited() -> AbortController { + // The new AbortController() constructor steps are: + // Let signal be a new AbortSignal object. + // Set this’s signal to signal. AbortController { reflector_: Reflector::new(), + signal: Dom::from_ref(&AbortSignal::new_inherited()), } } @@ -36,6 +45,12 @@ impl AbortController { can_gc, ) } + + /// + fn signal_abort(&self, cx: JSContext, reason: HandleValue, can_gc: CanGc) { + // signal abort on controller’s signal with reason if it is given. + self.signal.signal_abort(cx, reason, can_gc); + } } impl AbortControllerMethods for AbortController { @@ -49,5 +64,9 @@ impl AbortControllerMethods for AbortController { } /// - fn Abort(&self, _cx: JSContext, _reason: Handle<'_, Value>) {} + fn Abort(&self, cx: JSContext, reason: HandleValue, can_gc: CanGc) { + // The abort(reason) method steps are + // to signal abort on this with reason if it is given. + self.signal_abort(cx, reason, can_gc); + } } diff --git a/components/script/dom/abortsignal.rs b/components/script/dom/abortsignal.rs index 57c6e9cd67e..c714b6d7b69 100644 --- a/components/script/dom/abortsignal.rs +++ b/components/script/dom/abortsignal.rs @@ -2,18 +2,37 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +use std::cell::RefCell; +use std::mem; + use dom_struct::dom_struct; use js::jsapi::Heap; -use js::jsval::JSVal; -use js::rust::{HandleObject, MutableHandleValue}; +use js::jsval::{JSVal, UndefinedValue}; +use js::rust::{HandleObject, HandleValue, MutableHandleValue}; +use script_bindings::inheritance::Castable; use crate::dom::bindings::codegen::Bindings::AbortSignalBinding::AbortSignalMethods; -use crate::dom::bindings::reflector::reflect_dom_object_with_proto; +use crate::dom::bindings::error::{Error, ErrorToJsval}; +use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object_with_proto}; use crate::dom::bindings::root::DomRoot; use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; use crate::script_runtime::{CanGc, JSContext}; +/// +/// TODO: implement algorithms at call point, +/// in order to integrate the abort signal with its various use cases. +#[derive(JSTraceable, MallocSizeOf)] +#[allow(dead_code)] +enum AbortAlgorithm { + /// + DomEventLister, + /// + StreamPiping, + /// + Fetch, +} + /// #[dom_struct] pub(crate) struct AbortSignal { @@ -22,14 +41,17 @@ pub(crate) struct AbortSignal { /// #[ignore_malloc_size_of = "mozjs"] abort_reason: Heap, + + /// + abort_algorithms: RefCell>, } impl AbortSignal { - #[allow(dead_code)] - fn new_inherited() -> AbortSignal { + pub(crate) fn new_inherited() -> AbortSignal { AbortSignal { eventtarget: EventTarget::new_inherited(), abort_reason: Default::default(), + abort_algorithms: Default::default(), } } @@ -46,6 +68,53 @@ impl AbortSignal { can_gc, ) } + + /// + pub(crate) fn signal_abort(&self, cx: JSContext, reason: HandleValue, can_gc: CanGc) { + // If signal is aborted, then return. + if self.Aborted() { + return; + } + + let abort_reason = reason.get(); + + // Set signal’s abort reason to reason if it is given; + if !abort_reason.is_undefined() { + self.abort_reason.set(abort_reason); + } else { + // otherwise to a new "AbortError" DOMException. + rooted!(in(*cx) let mut rooted_error = UndefinedValue()); + Error::Abort.to_jsval(cx, &self.global(), rooted_error.handle_mut(), can_gc); + self.abort_reason.set(rooted_error.get()) + } + + // Let dependentSignalsToAbort be a new list. + // For each dependentSignal of signal’s dependent signals: + // TODO: #36936 + + // Run the abort steps for signal. + self.run_the_abort_steps(can_gc); + + // For each dependentSignal of dependentSignalsToAbort, run the abort steps for dependentSignal. + // TODO: #36936 + } + + /// + fn run_the_abort_steps(&self, can_gc: CanGc) { + // For each algorithm of signal’s abort algorithms: run algorithm. + let algos = mem::take(&mut *self.abort_algorithms.borrow_mut()); + for _algo in algos { + // TODO: match on variant and implement algo steps. + // See the various items of #34866 + } + + // Empty signal’s abort algorithms. + // Done above with `take`. + + // Fire an event named abort at signal. + self.upcast::() + .fire_event(atom!("abort"), can_gc); + } } impl AbortSignalMethods for AbortSignal { diff --git a/components/script_bindings/codegen/Bindings.conf b/components/script_bindings/codegen/Bindings.conf index 7cc092e574e..dd034654974 100644 --- a/components/script_bindings/codegen/Bindings.conf +++ b/components/script_bindings/codegen/Bindings.conf @@ -14,6 +14,10 @@ DOMInterfaces = { +'AbortController': { + 'canGc':['Abort'], +}, + 'AbstractRange': { 'weakReferenceable': True, },