Conversation in the context of servo/servo#32898
The details of issue #32898 in the servo/servo
repository include a task to handle the fulfillment of the pull algorithm promise.
-
Locate the Relevant Code: The task is related to the
PullAlgorithmFulfillmentHandler
in theReadableStreamDefaultController
. You can find it in the file readablestream.rs. -
Analyze the Code for
PullAlgorithmFulfillmentHandler
: Review its current implementation and understand how promises are being handled. -
Update the Code: Implement the logic to fulfill the promise when the pull algorithm completes. Make sure to handle both success and error cases.
-
Test Your Changes: Ensure that the changes fulfill the promise correctly and do not introduce any regressions.
You can refer to the spec for more detailed guidance on how promises should be handled in this context.
Here are some examples of similar code from the servo/servo
repository:
-
baseaudiocontext.rs: This file contains methods related to handling promises and managing the audio context state.
-
servoshell/desktop/protocols/servo.rs: This file demonstrates loading resources using a mapping from well-known shortcuts to resource URLs.
-
blob.rs: This file includes the implementation of a blob protocol handler, which handles the loading of blob URLs.
-
body.rs: This file contains the
TransmitBodyConnectHandler
struct and its methods, which handle streaming body chunks over IPC. -
worklet.rs: This file includes methods related to managing worklets and their execution in a dedicated thread pool.
-
servoparser/mod.rs: This file contains methods for parsing HTML documents and fragments using the Servo parser.
These examples demonstrate various handlers and promise management techniques that might be helpful for your task.
Here is a specific example of a native promise fulfillment handler from the servo/servo
repository:
File path: components/script/dom/promise.rs
This section of the code defines methods to handle native promises, including appending native handlers for resolution and rejection.
impl Promise {
#[allow(unsafe_code)]
pub fn append_native_handler(&self, handler: &PromiseNativeHandler, _comp: InRealm) {
let _ais = AutoEntryScript::new(&handler.global());
let cx = GlobalScope::get_cx();
rooted!(in(*cx) let resolve_func =
create_native_handler_function(*cx,
handler.reflector().get_jsobject(),
NativeHandlerTask::Resolve));
rooted!(in(*cx) let reject_func =
create_native_handler_function(*cx,
handler.reflector().get_jsobject(),
NativeHandlerTask::Reject));
unsafe {
let ok = AddPromiseReactions(
*cx,
self.promise_obj(),
resolve_func.handle(),
reject_func.handle(),
);
assert!(ok);
}
}
}
This code demonstrates how to append a native handler to a promise, preparing it to handle fulfillment or rejection.
Here's an example of the handling code inside a handler from the servo/servo repository:
File path: components/script/dom/eventtarget.rs
This section of the code defines how different types of event handlers are called or executed.
impl CompiledEventListener {
// https://html.spec.whatwg.org/multipage/#the-event-handler-processing-algorithm
pub fn call_or_handle_event(
&self,
object: &EventTarget,
event: &Event,
exception_handle: ExceptionHandling,
) {
// Step 3
match *self {
CompiledEventListener::Listener(ref listener) => {
let _ = listener.HandleEvent_(object, event, exception_handle);
},
CompiledEventListener::Handler(ref handler) => {
match *handler {
CommonEventHandler::ErrorEventHandler(ref handler) => {
if let Some(event) = event.downcast::<ErrorEvent>() {
if object.is::<Window>() || object.is::<WorkerGlobalScope>() {
let cx = GlobalScope::get_cx();
rooted!(in(*cx) let error = event.Error(cx));
let return_value = handler.Call_(
object,
EventOrString::String(event.Message()),
Some(event.Filename()),
Some(event.Lineno()),
Some(event.Colno()),
Some(error.handle()),
exception_handle,
);
// Step 4
if let Ok(return_value) = return_value {
rooted!(in(*cx) let return_value = return_value);
if return_value.handle().is_boolean() &&
return_value.handle().to_boolean()
{
event.upcast::<Event>().PreventDefault();
}
}
return;
}
}
let _ = handler.Call_(
object,
EventOrString::Event(DomRoot::from_ref(event)),
None,
None,
None,
None,
exception_handle,
);
},
CommonEventHandler::BeforeUnloadEventHandler(ref handler) => {
if let Some(event) = event.downcast::<BeforeUnloadEvent>() {
// Step 5
if let Ok(value) =
handler.Call_(object, event.upcast::<Event>(), exception_handle)
{
let rv = event.ReturnValue();
if let Some(v) = value {
if rv.is_empty() {
event.SetReturnValue(v);
}
event.upcast::<Event>().PreventDefault();
}
}
} else {
// Step 5, "Otherwise" clause
let _ =
handler.Call_(object, event.upcast::<Event>(), exception_handle);
}
},
CommonEventHandler::EventHandler(ref handler) => {
if let Ok(value) = handler.Call_(object, event, exception_handle) {
let cx = GlobalScope::get_cx();
rooted!(in(*cx) let value = value);
let value = value.handle();
// Step 5
let should_cancel = value.is_boolean() && !value.to_boolean();
if should_cancel {
event.PreventDefault();
}
}
}
}
}
}
}
}
This example demonstrates how different types of event handlers (e.g., error handlers, before unload handlers) are invoked and how events are processed within these handlers.
Here is an example of handling code inside a promise fulfillment handler from the servo/servo
repository:
File path: components/script/dom/promise.rs
This section demonstrates how to resolve a promise:
#[allow(unsafe_code)]
pub fn resolve_native<T>(&self, val: &T)
where
T: ToJSValConvertible,
{
let cx = GlobalScope::get_cx();
let _ac = enter_realm(self);
rooted!(in(*cx) let mut v = UndefinedValue());
unsafe {
val.to_jsval(*cx, v.handle_mut());
}
self.resolve(cx, v.handle());
}
#[allow(crown::unrooted_must_root, unsafe_code)]
pub fn resolve(&self, cx: SafeJSContext, value: HandleValue) {
unsafe {
if !ResolvePromise(*cx, self.promise_obj(), value) {
JS_ClearPendingException(*cx);
}
}
}
This code shows how a native value is converted to a JavaScript value and then used to resolve a promise.
Here is an example of a native handler for resolving a promise in the servo/servo
repository:
File path: components/script/dom/promisenativehandler.rs
This section demonstrates how to handle promise resolution and rejection using native handlers:
use dom_struct::dom_struct;
use js::jsapi::JSContext;
use js::rust::HandleValue;
use malloc_size_of::MallocSizeOf;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::trace::JSTraceable;
use crate::dom::globalscope::GlobalScope;
use crate::realms::InRealm;
use crate::script_runtime::JSContext as SafeJSContext;
pub trait Callback: JSTraceable + MallocSizeOf {
fn callback(&self, cx: SafeJSContext, v: HandleValue, realm: InRealm);
}
#[dom_struct]
pub struct PromiseNativeHandler {
reflector: Reflector,
resolve: Option<Box<dyn Callback>>,
reject: Option<Box<dyn Callback>>,
}
impl PromiseNativeHandler {
pub fn new(
global: &GlobalScope,
resolve: Option<Box<dyn Callback>>,
reject: Option<Box<dyn Callback>>,
) -> DomRoot<PromiseNativeHandler> {
reflect_dom_object(
Box::new(PromiseNativeHandler {
reflector: Reflector::new(),
resolve,
reject,
}),
global,
)
}
#[allow(unsafe_code)]
fn callback(
callback: &Option<Box<dyn Callback>>,
cx: *mut JSContext,
v: HandleValue,
realm: InRealm,
) {
let cx = unsafe { SafeJSContext::from_ptr(cx) };
if let Some(ref callback) = *callback {
callback.callback(cx, v, realm)
}
}
pub fn resolved_callback(&self, cx: *mut JSContext, v: HandleValue, realm: InRealm) {
PromiseNativeHandler::callback(&self.resolve, cx, v, realm)
}
pub fn rejected_callback(&self, cx: *mut JSContext, v: HandleValue, realm: InRealm) {
PromiseNativeHandler::callback(&self.reject, cx, v, realm)
}
}
To implement the Callback
trait for PullAlgorithmFulfillmentHandler
in the servo/servo
repository, you can follow these steps:
-
Identify the
PullAlgorithmFulfillmentHandler
structure: The structure is likely defined in the Servo codebase but wasn't directly found in the search results. You may need to look in related modules or files within thecomponents/script
or similar directories if it's part of the DOM or networking code. -
Understand the
Callback
trait: TheCallback
trait is defined incomponents/script/dom/bindings/callback.rs
. It includes methods to create and manage callback objects. -
Implement the
Callback
trait: Use theCallback
trait's methods and ensure thatPullAlgorithmFulfillmentHandler
implements all the required methods from the trait. Here's a basic example based on theCallbackContainer
trait:
use components::script::dom::bindings::callback::{CallbackContainer, CallbackObject};
pub struct PullAlgorithmFulfillmentHandler {
callback: CallbackObject,
}
impl CallbackContainer for PullAlgorithmFulfillmentHandler {
unsafe fn new(cx: JSContext, callback: *mut JSObject) -> Rc<Self> {
Rc::new(PullAlgorithmFulfillmentHandler {
callback: CallbackObject::new(),
})
}
fn callback_holder(&self) -> &CallbackObject {
&self.callback
}
}
Ensure you have relevant imports and adapt the implementation based on specific requirements and behaviors needed for PullAlgorithmFulfillmentHandler
. This is a simplified example and you may need to adjust it to fit the actual use case in the Servo codebase.
I found several examples of handlers within the servo/servo
repository. Here are some relevant files that include handler implementations:
-
Event Listeners and Handlers:
-
WebIDL Event Handlers:
These files include various implementations of event listeners and handlers that may serve as useful references for your implementation.
I mean a similar native promise fufillment handler
I found some examples of native promise fulfillment handlers in the servo/servo
repository. Here are some relevant files and sections:
- Promise Fulfillment and Rejection Handlers:
These files include implementations of promise fulfillment and rejection handlers which may serve as useful references for your implementation.
This response could not be shown as it violates GitHub’s content policies.