mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Support native promise callbacks.
This commit is contained in:
parent
7ba3172ce0
commit
ab168204ed
5 changed files with 138 additions and 3 deletions
|
@ -156,7 +156,7 @@ impl<T: JSTraceable> JSTraceable for Rc<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: JSTraceable> JSTraceable for Box<T> {
|
||||
impl<T: JSTraceable + ?Sized> JSTraceable for Box<T> {
|
||||
fn trace(&self, trc: *mut JSTracer) {
|
||||
(**self).trace(trc)
|
||||
}
|
||||
|
|
|
@ -374,6 +374,7 @@ pub mod popstateevent;
|
|||
pub mod processinginstruction;
|
||||
pub mod progressevent;
|
||||
pub mod promise;
|
||||
pub mod promisenativehandler;
|
||||
pub mod radionodelist;
|
||||
pub mod range;
|
||||
pub mod request;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
use dom::bindings::callback::CallbackContainer;
|
||||
use dom::bindings::codegen::Bindings::PromiseBinding::AnyCallback;
|
||||
use dom::bindings::conversions::root_from_object;
|
||||
use dom::bindings::error::Fallible;
|
||||
use dom::bindings::global::GlobalRef;
|
||||
use dom::bindings::reflector::{Reflectable, MutReflectable, Reflector};
|
||||
|
@ -82,7 +83,7 @@ impl Promise {
|
|||
pub fn maybe_resolve_native<T>(&self, cx: *mut JSContext, val: &T) where T: ToJSValConvertible {
|
||||
rooted!(in(cx) let mut v = UndefinedValue());
|
||||
unsafe {
|
||||
val.to_jsval(cx, m.handle_mut());
|
||||
val.to_jsval(cx, v.handle_mut());
|
||||
}
|
||||
self.maybe_resolve(cx, v.handle());
|
||||
}
|
||||
|
@ -102,7 +103,7 @@ impl Promise {
|
|||
pub fn maybe_reject_native<T>(&self, cx: *mut JSContext, val: &T) where T: ToJSValConvertible {
|
||||
rooted!(in(cx) let mut v = UndefinedValue());
|
||||
unsafe {
|
||||
val.to_jsval(cx, m.handle_mut());
|
||||
val.to_jsval(cx, v.handle_mut());
|
||||
}
|
||||
self.maybe_reject(cx, v.handle());
|
||||
}
|
||||
|
@ -143,6 +144,29 @@ impl Promise {
|
|||
}
|
||||
obj
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn append_native_handler(&self, handler: &PromiseNativeHandler) {
|
||||
let global = self.global();
|
||||
let cx = global.r().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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
|
@ -151,3 +175,51 @@ unsafe extern fn do_nothing_promise_executor(_cx: *mut JSContext, argc: u32, vp:
|
|||
*args.rval() = UndefinedValue();
|
||||
true
|
||||
}
|
||||
|
||||
const SLOT_NATIVEHANDLER: usize = 0;
|
||||
const SLOT_NATIVEHANDLER_TASK: usize = 1;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum NativeHandlerTask {
|
||||
Resolve = 0,
|
||||
Reject = 1,
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
unsafe extern fn native_handler_callback(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
|
||||
let args = CallArgs::from_vp(vp, argc);
|
||||
rooted!(in(cx) let v = *GetFunctionNativeReserved(args.callee(), SLOT_NATIVEHANDLER));
|
||||
assert!(v.get().is_object());
|
||||
|
||||
let handler = root_from_object::<PromiseNativeHandler>(v.to_object())
|
||||
.ok().expect("unexpected value for native handler in promise native handler callback");
|
||||
|
||||
rooted!(in(cx) let v = *GetFunctionNativeReserved(args.callee(), SLOT_NATIVEHANDLER_TASK));
|
||||
match v.to_int32() {
|
||||
v if v == NativeHandlerTask::Resolve as i32 => handler.resolved_callback(cx, args.get(0)),
|
||||
v if v == NativeHandlerTask::Reject as i32 => handler.rejected_callback(cx, args.get(0)),
|
||||
_ => panic!("unexpected native handler task value"),
|
||||
};
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
fn create_native_handler_function(cx: *mut JSContext,
|
||||
holder: HandleObject,
|
||||
task: NativeHandlerTask) -> *mut JSObject {
|
||||
unsafe {
|
||||
let func = NewFunctionWithReserved(cx, Some(native_handler_callback), 1, 0, ptr::null());
|
||||
assert!(!func.is_null());
|
||||
|
||||
rooted!(in(cx) let obj = JS_GetFunctionObject(func));
|
||||
assert!(!obj.is_null());
|
||||
SetFunctionNativeReserved(obj.get(),
|
||||
SLOT_NATIVEHANDLER,
|
||||
&ObjectValue(&**holder));
|
||||
SetFunctionNativeReserved(obj.get(),
|
||||
SLOT_NATIVEHANDLER_TASK,
|
||||
&Int32Value(task as i32));
|
||||
obj.get()
|
||||
}
|
||||
}
|
||||
|
|
49
components/script/dom/promisenativehandler.rs
Normal file
49
components/script/dom/promisenativehandler.rs
Normal file
|
@ -0,0 +1,49 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom::bindings::codegen::Bindings::PromiseNativeHandlerBinding;
|
||||
use dom::bindings::global::GlobalRef;
|
||||
use dom::bindings::js::Root;
|
||||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||
use dom::bindings::trace::JSTraceable;
|
||||
use heapsize::HeapSizeOf;
|
||||
use js::jsapi::{JSContext, HandleValue};
|
||||
|
||||
pub trait Callback: JSTraceable + HeapSizeOf {
|
||||
fn callback(&self, cx: *mut JSContext, v: HandleValue);
|
||||
}
|
||||
|
||||
#[dom_struct]
|
||||
pub struct PromiseNativeHandler {
|
||||
reflector: Reflector,
|
||||
resolve: Option<Box<Callback>>,
|
||||
reject: Option<Box<Callback>>,
|
||||
}
|
||||
|
||||
impl PromiseNativeHandler {
|
||||
pub fn new(global: GlobalRef,
|
||||
resolve: Option<Box<Callback>>,
|
||||
reject: Option<Box<Callback>>)
|
||||
-> Root<PromiseNativeHandler> {
|
||||
reflect_dom_object(box PromiseNativeHandler {
|
||||
reflector: Reflector::new(),
|
||||
resolve: resolve,
|
||||
reject: reject,
|
||||
}, global, PromiseNativeHandlerBinding::Wrap)
|
||||
}
|
||||
|
||||
fn callback(callback: &Option<Box<Callback>>, cx: *mut JSContext, v: HandleValue) {
|
||||
if let Some(ref callback) = *callback {
|
||||
callback.callback(cx, v)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolved_callback(&self, cx: *mut JSContext, v: HandleValue) {
|
||||
PromiseNativeHandler::callback(&self.resolve, cx, v)
|
||||
}
|
||||
|
||||
pub fn rejected_callback(&self, cx: *mut JSContext, v: HandleValue) {
|
||||
PromiseNativeHandler::callback(&self.reject, cx, v)
|
||||
}
|
||||
}
|
13
components/script/dom/webidls/PromiseNativeHandler.webidl
Normal file
13
components/script/dom/webidls/PromiseNativeHandler.webidl
Normal file
|
@ -0,0 +1,13 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This interface is entirely internal to Servo, and should not be accessible to
|
||||
// web pages.
|
||||
|
||||
// Hack to allow us to have JS owning and properly tracing/CCing/etc a
|
||||
// PromiseNativeHandler.
|
||||
[NoInterfaceObject,
|
||||
Exposed=(Window,Worker)]
|
||||
interface PromiseNativeHandler {
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue