Bug 996831. Add a ToJSValue overload for nsresult, to allow rejecting promises from C++ more easily. r=bholley
☠☠ backed out by 5b54654e26cd ☠ ☠
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 16 Apr 2014 15:13:41 -0400
changeset 179248 7acce569bd84bc5b264c28df67c6066f527a27fb
parent 179247 1845b09c7578b57d8c16f7fa4a82f4a26b23557e
child 179249 c60b059c47ca40af1e2f21aaaa23da263ed0a39b
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersbholley
bugs996831
milestone31.0a1
Bug 996831. Add a ToJSValue overload for nsresult, to allow rejecting promises from C++ more easily. r=bholley
dom/bindings/Exceptions.cpp
dom/bindings/Exceptions.h
dom/bindings/ToJSValue.cpp
dom/bindings/ToJSValue.h
dom/promise/Promise.h
--- a/dom/bindings/Exceptions.cpp
+++ b/dom/bindings/Exceptions.cpp
@@ -126,49 +126,51 @@ Throw(JSContext* aCx, nsresult aRv, cons
         // If we weren't able to throw an exception we're
         // most likely out of memory
         JS_ReportOutOfMemory(aCx);
       }
       return false;
     }
   }
 
-  nsRefPtr<Exception> finalException;
-
-  // Do we use DOM exceptions for this error code?
-  switch (NS_ERROR_GET_MODULE(aRv)) {
-  case NS_ERROR_MODULE_DOM:
-  case NS_ERROR_MODULE_SVG:
-  case NS_ERROR_MODULE_DOM_XPATH:
-  case NS_ERROR_MODULE_DOM_INDEXEDDB:
-  case NS_ERROR_MODULE_DOM_FILEHANDLE:
-    finalException = DOMException::Create(aRv);
-    break;
-
-  default:
-      break;
-  }
-
-  // If not, use the default.
-  if (!finalException) {
-    // aMessage can be null.
-    finalException = new Exception(nsCString(aMessage), aRv,
-                                   EmptyCString(), nullptr, nullptr);
-  }
+  nsRefPtr<Exception> finalException = CreateException(aCx, aRv, aMessage);
 
   MOZ_ASSERT(finalException);
   if (!ThrowExceptionObject(aCx, finalException)) {
     // If we weren't able to throw an exception we're
     // most likely out of memory
     JS_ReportOutOfMemory(aCx);
   }
 
   return false;
 }
 
+already_AddRefed<Exception>
+CreateException(JSContext* aCx, nsresult aRv, const char* aMessage)
+{
+  // Do we use DOM exceptions for this error code?
+  switch (NS_ERROR_GET_MODULE(aRv)) {
+  case NS_ERROR_MODULE_DOM:
+  case NS_ERROR_MODULE_SVG:
+  case NS_ERROR_MODULE_DOM_XPATH:
+  case NS_ERROR_MODULE_DOM_INDEXEDDB:
+  case NS_ERROR_MODULE_DOM_FILEHANDLE:
+    return DOMException::Create(aRv);
+  default:
+    break;
+  }
+
+  // If not, use the default.
+  // aMessage can be null, so we can't use nsDependentCString on it.
+  nsRefPtr<Exception> exception =
+    new Exception(nsCString(aMessage), aRv,
+                  EmptyCString(), nullptr, nullptr);
+  return exception.forget();
+}
+
 already_AddRefed<nsIStackFrame>
 GetCurrentJSStack()
 {
   // is there a current context available?
   JSContext* cx = nullptr;
 
   if (NS_IsMainThread()) {
     // Note, in xpcshell nsContentUtils is never initialized, but we still need
--- a/dom/bindings/Exceptions.h
+++ b/dom/bindings/Exceptions.h
@@ -25,16 +25,21 @@ bool
 Throw(JSContext* cx, nsresult rv, const char* sz = nullptr);
 
 bool
 ThrowExceptionObject(JSContext* aCx, Exception* aException);
 
 bool
 ThrowExceptionObject(JSContext* aCx, nsIException* aException);
 
+// Create an exception object for the given nsresult and message but
+// don't set it pending on aCx.  This never returns null.
+already_AddRefed<Exception>
+CreateException(JSContext* aCx, nsresult aRv, const char* aMessage = nullptr);
+
 already_AddRefed<nsIStackFrame>
 GetCurrentJSStack();
 
 // Internal stuff not intended to be widely used.
 namespace exceptions {
 
 // aMaxDepth can be used to define a maximal depth for the stack trace. If the
 // value is -1, a default maximal depth will be selected.
--- a/dom/bindings/ToJSValue.cpp
+++ b/dom/bindings/ToJSValue.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
 /* vim: set ts=2 sw=2 et tw=79: */
 /* 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/. */
 
 #include "mozilla/dom/ToJSValue.h"
+#include "mozilla/dom/Exceptions.h"
 #include "nsAString.h"
 #include "nsContentUtils.h"
 #include "nsStringBuffer.h"
 #include "xpcpublic.h"
 
 namespace mozilla {
 namespace dom {
 
@@ -44,10 +45,19 @@ ISupportsToJSValue(JSContext* aCx,
                    JS::MutableHandle<JS::Value> aValue)
 {
   nsresult rv = nsContentUtils::WrapNative(aCx, aArgument, aValue);
   return NS_SUCCEEDED(rv);
 }
 
 } // namespace tojsvalue_detail
 
+bool
+ToJSValue(JSContext* aCx,
+          nsresult aArgument,
+          JS::MutableHandle<JS::Value> aValue)
+{
+  nsRefPtr<Exception> exception = CreateException(aCx, aArgument);
+  return ToJSValue(aCx, exception, aValue);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/bindings/ToJSValue.h
+++ b/dom/bindings/ToJSValue.h
@@ -207,16 +207,23 @@ ToJSValue(JSContext* aCx,
 inline bool
 ToJSValue(JSContext* aCx, JS::Handle<JS::Value> aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   aValue.set(aArgument);
   return MaybeWrapValue(aCx, aValue);
 }
 
+// Accept nsresult, for use in rejections, and create an XPCOM
+// exception object representing that nsresult.
+bool
+ToJSValue(JSContext* aCx,
+          nsresult aArgument,
+          JS::MutableHandle<JS::Value> aValue);
+
 // Accept arrays of other things we accept
 template <typename T>
 bool
 ToJSValue(JSContext* aCx,
           T* aArguments,
           size_t aLength,
           JS::MutableHandle<JS::Value> aValue)
 {
--- a/dom/promise/Promise.h
+++ b/dom/promise/Promise.h
@@ -73,25 +73,27 @@ public:
                                      JS::Handle<JS::Value> aValue);
 
   void MaybeResolve(JSContext* aCx,
                     JS::Handle<JS::Value> aValue);
   void MaybeReject(JSContext* aCx,
                    JS::Handle<JS::Value> aValue);
 
   // Helpers for using Promise from C++.
-  // Most DOM objects are handled already.  To add a new type T, such as ints,
-  // or dictionaries, add a ToJSValue overload in ToJSValue.h.
+  // Most DOM objects are handled already.  To add a new type T, add a
+  // ToJSValue overload in ToJSValue.h.
+  // aArg is a const reference so we can pass rvalues like integer constants
   template <typename T>
-  void MaybeResolve(T& aArg) {
+  void MaybeResolve(const T& aArg) {
     MaybeSomething(aArg, &Promise::MaybeResolve);
   }
 
+  // aArg is a const reference so we can pass rvalues like NS_ERROR_*
   template <typename T>
-  void MaybeReject(T& aArg) {
+  void MaybeReject(const T& aArg) {
     MaybeSomething(aArg, &Promise::MaybeReject);
   }
 
   // WebIDL
 
   nsIGlobalObject* GetParentObject() const
   {
     return mGlobal;