From 27d44c8d1042e5705853b272fc340c76c4d02785 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Tue, 6 Sep 2016 19:58:26 -0400 Subject: [PATCH] Add a simple API to reject promises with DOM error values. --- components/script/dom/bindings/error.rs | 12 ++++++++++++ components/script/dom/promise.rs | 11 ++++++++++- components/script/dom/testbinding.rs | 6 +++++- components/script/dom/webidls/TestBinding.webidl | 1 + tests/wpt/mozilla/tests/mozilla/promise.html | 7 +++++++ 5 files changed, 35 insertions(+), 2 deletions(-) diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs index c9cbeb09f21..1c0d49c4976 100644 --- a/components/script/dom/bindings/error.rs +++ b/components/script/dom/bindings/error.rs @@ -19,6 +19,7 @@ use js::jsapi::JS_ErrorFromException; use js::jsapi::JS_GetPendingException; use js::jsapi::JS_IsExceptionPending; use js::jsapi::JS_SetPendingException; +use js::jsapi::MutableHandleValue; use js::jsval::UndefinedValue; use libc::c_uint; use std::slice::from_raw_parts; @@ -266,3 +267,14 @@ pub unsafe fn throw_invalid_this(cx: *mut JSContext, proto_id: u16) { proto_id_to_name(proto_id)); throw_type_error(cx, &error); } + +impl Error { + /// Convert this error value to a JS value, consuming it in the process. + pub unsafe fn to_jsval(self, cx: *mut JSContext, global: GlobalRef, rval: MutableHandleValue) { + assert!(!JS_IsExceptionPending(cx)); + throw_dom_exception(cx, global, self); + assert!(JS_IsExceptionPending(cx)); + assert!(JS_GetPendingException(cx, rval)); + JS_ClearPendingException(cx); + } +} diff --git a/components/script/dom/promise.rs b/components/script/dom/promise.rs index 6dd45d05219..f167d95bfd2 100644 --- a/components/script/dom/promise.rs +++ b/components/script/dom/promise.rs @@ -14,7 +14,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::error::{Error, Fallible}; use dom::bindings::global::GlobalRef; use dom::bindings::js::MutHeapJSVal; use dom::bindings::reflector::{Reflectable, MutReflectable, Reflector}; @@ -156,6 +156,15 @@ impl Promise { self.maybe_reject(cx, v.handle()); } + #[allow(unsafe_code)] + pub fn maybe_reject_error(&self, cx: *mut JSContext, error: Error) { + rooted!(in(cx) let mut v = UndefinedValue()); + unsafe { + error.maybe_to_jsval(cx, self.global().r(), v.handle_mut()); + } + self.maybe_reject(cx, v.handle()); + } + #[allow(unrooted_must_root, unsafe_code)] pub fn maybe_reject(&self, cx: *mut JSContext, diff --git a/components/script/dom/testbinding.rs b/components/script/dom/testbinding.rs index c318badc1ba..a9df0a3a9d2 100644 --- a/components/script/dom/testbinding.rs +++ b/components/script/dom/testbinding.rs @@ -20,7 +20,7 @@ use dom::bindings::codegen::UnionTypes::{EventOrUSVString, HTMLElementOrLong, Lo use dom::bindings::codegen::UnionTypes::{HTMLElementOrUnsignedLongOrStringOrBoolean, LongSequenceOrBoolean}; use dom::bindings::codegen::UnionTypes::{StringOrLongSequence, StringOrStringSequence, StringSequenceOrUnsignedLong}; use dom::bindings::codegen::UnionTypes::{StringOrUnsignedLong, StringOrBoolean, UnsignedLongOrBoolean}; -use dom::bindings::error::Fallible; +use dom::bindings::error::{Error, Fallible}; use dom::bindings::global::{GlobalRef, global_root_from_context}; use dom::bindings::js::Root; use dom::bindings::mozmap::MozMap; @@ -668,6 +668,10 @@ impl TestBindingMethods for TestBinding { p.maybe_reject(cx, v); } + fn PromiseRejectWithTypeError(&self, p: &Promise, s: USVString) { + p.maybe_reject_error(self.global().r().get_cx(), Error::Type(s.0)); + } + #[allow(unrooted_must_root)] fn PromiseNativeHandler(&self, resolve: Option>, diff --git a/components/script/dom/webidls/TestBinding.webidl b/components/script/dom/webidls/TestBinding.webidl index 65c68514895..54e54f27c77 100644 --- a/components/script/dom/webidls/TestBinding.webidl +++ b/components/script/dom/webidls/TestBinding.webidl @@ -518,6 +518,7 @@ interface TestBinding { Promise promiseNativeHandler(SimpleCallback? resolve, SimpleCallback? reject); void promiseResolveNative(Promise p, any value); void promiseRejectNative(Promise p, any value); + void promiseRejectWithTypeError(Promise p, USVString message); void panic(); }; diff --git a/tests/wpt/mozilla/tests/mozilla/promise.html b/tests/wpt/mozilla/tests/mozilla/promise.html index 9e5175ec57a..79a0a5578a9 100644 --- a/tests/wpt/mozilla/tests/mozilla/promise.html +++ b/tests/wpt/mozilla/tests/mozilla/promise.html @@ -21,6 +21,13 @@ }); }, 'Reject callback gets argument'); + promise_test(function(test) { + var t = new TestBinding; + var p = new Promise(function() {}); + t.promiseRejectWithTypeError(p, "success"); + return promise_rejects(test, new TypeError("success"), p, "TypeError should be instantiated"); + }, 'Native code rejects with exception'); + promise_test(function(test) { var t = new TestBinding; var resolved;