Skip to content

Instantly share code, notes, and snippets.

@gterzian
Last active September 27, 2024 07:35
Show Gist options
  • Save gterzian/1b333fccf42fbb3d8decad6294b8985d to your computer and use it in GitHub Desktop.
Save gterzian/1b333fccf42fbb3d8decad6294b8985d to your computer and use it in GitHub Desktop.

Conversation in the context of servo/servo#32898

In this issue, how can I do the " Handle fufillment of pull algo promise" part?

The details of issue #32898 in the servo/servo repository include a task to handle the fulfillment of the pull algorithm promise.

Steps to handle the fulfillment:

  1. Locate the Relevant Code: The task is related to the PullAlgorithmFulfillmentHandler in the ReadableStreamDefaultController. You can find it in the file readablestream.rs.

  2. Analyze the Code for PullAlgorithmFulfillmentHandler: Review its current implementation and understand how promises are being handled.

  3. Update the Code: Implement the logic to fulfill the promise when the pull algorithm completes. Make sure to handle both success and error cases.

  4. 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.

Do you have examples of other similar code?

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.

I want a more specific example of a native promise fulfillment handler

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.

I want an example of the handling code inside a handler

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.

This is an event handler. I want a promise fufillment handler

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.

I dont want to resovle the promise, I want an example of the native handler for the resolve

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)
    }
}

How can I impl Callback for PullAlgorithmFulfillmentHandler

To implement the Callback trait for PullAlgorithmFulfillmentHandler in the servo/servo repository, you can follow these steps:

  1. 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 the components/script or similar directories if it's part of the DOM or networking code.

  2. Understand the Callback trait: The Callback trait is defined in components/script/dom/bindings/callback.rs. It includes methods to create and manage callback objects.

  3. Implement the Callback trait: Use the Callback trait's methods and ensure that PullAlgorithmFulfillmentHandler implements all the required methods from the trait. Here's a basic example based on the CallbackContainer 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.

Do you have an example of a similar handler?

I found several examples of handlers within the servo/servo repository. Here are some relevant files that include handler implementations:

  1. Event Listeners and Handlers:

  2. 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:

  1. Promise Fulfillment and Rejection Handlers:

These files include implementations of promise fulfillment and rejection handlers which may serve as useful references for your implementation.

In components/script/body.rs, where is the native promise handler?

This response could not be shown as it violates GitHub’s content policies.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment