Support native promise callbacks.

This commit is contained in:
Josh Matthews 2016-08-12 11:44:56 -04:00
parent 7ba3172ce0
commit ab168204ed
5 changed files with 138 additions and 3 deletions

View file

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