summaryrefslogtreecommitdiffstats
path: root/dom/base/DOMMozPromiseRequestHolder.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base/DOMMozPromiseRequestHolder.h')
-rw-r--r--dom/base/DOMMozPromiseRequestHolder.h112
1 files changed, 112 insertions, 0 deletions
diff --git a/dom/base/DOMMozPromiseRequestHolder.h b/dom/base/DOMMozPromiseRequestHolder.h
new file mode 100644
index 0000000000..0f0fc29d4d
--- /dev/null
+++ b/dom/base/DOMMozPromiseRequestHolder.h
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef mozilla_dom_DOMMozPromiseRequestHolder_h
+#define mozilla_dom_DOMMozPromiseRequestHolder_h
+
+#include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/MozPromise.h"
+
+namespace mozilla::dom {
+
+/**
+ * This is a helper class that can be used when MozPromises are
+ * being consumed by binding layer code. It effectively creates
+ * a MozPromiseRequestHolder that auto-disconnects when the binding's
+ * global is disconnected.
+ *
+ * It can be used like this:
+ *
+ * RefPtr<Promise>
+ * SomeAsyncAPI(Args& aArgs, ErrorResult& aRv)
+ * {
+ * nsIGlobalObject* global = GetParentObject();
+ * if (!global) {
+ * aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+ * return nullptr;
+ * }
+ *
+ * RefPtr<Promise> outer = Promise::Create(global, aRv);
+ * if (aRv.Failed()) {
+ * return nullptr;
+ * }
+ *
+ * RefPtr<DOMMozPromiseRequestHolder> holder =
+ * new DOMMozPromiseRequestHolder(global);
+ *
+ * DoAsyncStuff()->Then(
+ * global->EventTargetFor(TaskCategory::Other), __func__,
+ * [holder, outer] (const Result& aResult) {
+ * holder->Complete();
+ *
+ * // Note, you can access the holder's bound global in
+ * // your reaction handler. Its mostly likely set if
+ * // the handler fires, but you still must check for
+ * // its existence since something could disconnect
+ * // the global between when the MozPromise reaction
+ * // runnable is queued and when it actually runs.
+ * nsIGlobalObject* global = holder->GetParentObject();
+ * NS_ENSURE_TRUE_VOID(global);
+ *
+ * outer->MaybeResolve(aResult);
+ * }, [holder, outer] (nsresult aRv) {
+ * holder->Complete();
+ * outer->MaybeReject(aRv);
+ * })->Track(*holder);
+ *
+ * return outer.forget();
+ * }
+ *
+ * NOTE: Currently this helper class extends DETH. This is only
+ * so that it can bind to the global and receive the
+ * DisconnectFromOwner() method call. In this future the
+ * binding code should be factored out so DETH is not
+ * needed here. See bug 1456893.
+ */
+template <typename PromiseType>
+class DOMMozPromiseRequestHolder final : public DOMEventTargetHelper {
+ MozPromiseRequestHolder<PromiseType> mHolder;
+
+ ~DOMMozPromiseRequestHolder() = default;
+
+ void DisconnectFromOwner() override {
+ mHolder.DisconnectIfExists();
+ DOMEventTargetHelper::DisconnectFromOwner();
+ }
+
+ JSObject* WrapObject(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto) override {
+ // We are extending DETH to get notified when the global goes
+ // away, but this object should never actually be exposed to
+ // script.
+ MOZ_CRASH("illegal method");
+ }
+
+ public:
+ explicit DOMMozPromiseRequestHolder(nsIGlobalObject* aGlobal)
+ : DOMEventTargetHelper(aGlobal) {
+ MOZ_DIAGNOSTIC_ASSERT(aGlobal);
+ }
+
+ operator MozPromiseRequestHolder<PromiseType>&() { return mHolder; }
+
+ operator const MozPromiseRequestHolder<PromiseType>&() const {
+ return mHolder;
+ }
+
+ void Complete() { mHolder.Complete(); }
+
+ void DisconnectIfExists() { mHolder.DisconnectIfExists(); }
+
+ bool Exists() const { return mHolder.Exists(); }
+
+ NS_INLINE_DECL_REFCOUNTING_INHERITED(DOMMozPromiseRequestHolder,
+ DOMEventTargetHelper)
+};
+
+} // namespace mozilla::dom
+
+#endif // mozilla_dom_DOMMozPromiseRequestHolder_h