Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / dom / promise / Promise.h
blob426fda7143bb240be49a07d832d593acb5306b87
1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_dom_Promise_h
8 #define mozilla_dom_Promise_h
10 #include "mozilla/Attributes.h"
11 #include "mozilla/ErrorResult.h"
12 #include "mozilla/TypeTraits.h"
13 #include "mozilla/dom/BindingDeclarations.h"
14 #include "nsCycleCollectionParticipant.h"
15 #include "mozilla/dom/PromiseBinding.h"
16 #include "mozilla/dom/ToJSValue.h"
17 #include "mozilla/WeakPtr.h"
18 #include "nsWrapperCache.h"
19 #include "nsAutoPtr.h"
20 #include "js/TypeDecls.h"
22 #include "mozilla/dom/workers/bindings/WorkerFeature.h"
24 class nsIGlobalObject;
26 namespace mozilla {
27 namespace dom {
29 class AnyCallback;
30 class DOMError;
31 class PromiseCallback;
32 class PromiseInit;
33 class PromiseNativeHandler;
34 class PromiseDebugging;
36 class Promise;
37 class PromiseReportRejectFeature : public workers::WorkerFeature
39 // The Promise that owns this feature.
40 Promise* mPromise;
42 public:
43 explicit PromiseReportRejectFeature(Promise* aPromise)
44 : mPromise(aPromise)
46 MOZ_ASSERT(mPromise);
49 virtual bool
50 Notify(JSContext* aCx, workers::Status aStatus) MOZ_OVERRIDE;
53 class Promise MOZ_FINAL : public nsISupports,
54 public nsWrapperCache,
55 public SupportsWeakPtr<Promise>
57 friend class NativePromiseCallback;
58 friend class PromiseResolverTask;
59 friend class PromiseTask;
60 friend class PromiseReportRejectFeature;
61 friend class PromiseWorkerProxy;
62 friend class PromiseWorkerProxyRunnable;
63 friend class RejectPromiseCallback;
64 friend class ResolvePromiseCallback;
65 friend class ThenableResolverTask;
66 friend class WrapperPromiseCallback;
68 ~Promise();
70 public:
71 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
72 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Promise)
73 MOZ_DECLARE_REFCOUNTED_TYPENAME(Promise)
75 // Promise creation tries to create a JS reflector for the Promise, so is
76 // fallible. Furthermore, we don't want to do JS-wrapping on a 0-refcount
77 // object, so we addref before doing that and return the addrefed pointer
78 // here.
79 static already_AddRefed<Promise>
80 Create(nsIGlobalObject* aGlobal, ErrorResult& aRv);
82 typedef void (Promise::*MaybeFunc)(JSContext* aCx,
83 JS::Handle<JS::Value> aValue);
85 void MaybeResolve(JSContext* aCx,
86 JS::Handle<JS::Value> aValue);
87 void MaybeReject(JSContext* aCx,
88 JS::Handle<JS::Value> aValue);
90 // Helpers for using Promise from C++.
91 // Most DOM objects are handled already. To add a new type T, add a
92 // ToJSValue overload in ToJSValue.h.
93 // aArg is a const reference so we can pass rvalues like integer constants
94 template <typename T>
95 void MaybeResolve(const T& aArg) {
96 MaybeSomething(aArg, &Promise::MaybeResolve);
99 inline void MaybeReject(nsresult aArg) {
100 MOZ_ASSERT(NS_FAILED(aArg));
101 MaybeSomething(aArg, &Promise::MaybeReject);
103 // DO NOT USE MaybeRejectBrokenly with in new code. Promises should be
104 // rejected with Error instances.
105 // Note: MaybeRejectBrokenly is a template so we can use it with DOMError
106 // without instantiating the DOMError specialization of MaybeSomething in
107 // every translation unit that includes this header, because that would
108 // require use to include DOMError.h either here or in all those translation
109 // units.
110 template<typename T>
111 void MaybeRejectBrokenly(const T& aArg); // Not implemented by default; see
112 // specializations in the .cpp for
113 // the T values we support.
115 // WebIDL
117 nsIGlobalObject* GetParentObject() const
119 return mGlobal;
122 virtual JSObject*
123 WrapObject(JSContext* aCx) MOZ_OVERRIDE;
125 static already_AddRefed<Promise>
126 Constructor(const GlobalObject& aGlobal, PromiseInit& aInit,
127 ErrorResult& aRv);
129 static already_AddRefed<Promise>
130 Resolve(const GlobalObject& aGlobal,
131 JS::Handle<JS::Value> aValue, ErrorResult& aRv);
133 static already_AddRefed<Promise>
134 Resolve(nsIGlobalObject* aGlobal, JSContext* aCx,
135 JS::Handle<JS::Value> aValue, ErrorResult& aRv);
137 static already_AddRefed<Promise>
138 Reject(const GlobalObject& aGlobal,
139 JS::Handle<JS::Value> aValue, ErrorResult& aRv);
141 static already_AddRefed<Promise>
142 Reject(nsIGlobalObject* aGlobal, JSContext* aCx,
143 JS::Handle<JS::Value> aValue, ErrorResult& aRv);
145 already_AddRefed<Promise>
146 Then(JSContext* aCx, AnyCallback* aResolveCallback,
147 AnyCallback* aRejectCallback, ErrorResult& aRv);
149 already_AddRefed<Promise>
150 Catch(JSContext* aCx, AnyCallback* aRejectCallback, ErrorResult& aRv);
152 static already_AddRefed<Promise>
153 All(const GlobalObject& aGlobal,
154 const Sequence<JS::Value>& aIterable, ErrorResult& aRv);
156 static already_AddRefed<Promise>
157 Race(const GlobalObject& aGlobal,
158 const Sequence<JS::Value>& aIterable, ErrorResult& aRv);
160 void AppendNativeHandler(PromiseNativeHandler* aRunnable);
162 private:
163 // Do NOT call this unless you're Promise::Create. I wish we could enforce
164 // that from inside this class too, somehow.
165 explicit Promise(nsIGlobalObject* aGlobal);
167 friend class PromiseDebugging;
169 enum PromiseState {
170 Pending,
171 Resolved,
172 Rejected
175 enum PromiseTaskSync {
176 SyncTask,
177 AsyncTask
180 void SetState(PromiseState aState)
182 MOZ_ASSERT(mState == Pending);
183 MOZ_ASSERT(aState != Pending);
184 mState = aState;
187 void SetResult(JS::Handle<JS::Value> aValue)
189 mResult = aValue;
192 // Queue an async task to current main or worker thread.
193 static void
194 DispatchToMainOrWorkerThread(nsIRunnable* aRunnable);
196 // This method processes promise's resolve/reject callbacks with promise's
197 // result. It's executed when the resolver.resolve() or resolver.reject() is
198 // called or when the promise already has a result and new callbacks are
199 // appended by then(), catch() or done().
200 void RunTask();
202 void RunResolveTask(JS::Handle<JS::Value> aValue,
203 Promise::PromiseState aState,
204 PromiseTaskSync aAsynchronous);
206 void AppendCallbacks(PromiseCallback* aResolveCallback,
207 PromiseCallback* aRejectCallback);
209 // If we have been rejected and our mResult is a JS exception,
210 // report it to the error console.
211 // Use MaybeReportRejectedOnce() for actual calls.
212 void MaybeReportRejected();
214 void MaybeReportRejectedOnce() {
215 MaybeReportRejected();
216 RemoveFeature();
217 mResult = JS::UndefinedValue();
220 void MaybeResolveInternal(JSContext* aCx,
221 JS::Handle<JS::Value> aValue,
222 PromiseTaskSync aSync = AsyncTask);
223 void MaybeRejectInternal(JSContext* aCx,
224 JS::Handle<JS::Value> aValue,
225 PromiseTaskSync aSync = AsyncTask);
227 void ResolveInternal(JSContext* aCx,
228 JS::Handle<JS::Value> aValue,
229 PromiseTaskSync aSync = AsyncTask);
231 void RejectInternal(JSContext* aCx,
232 JS::Handle<JS::Value> aValue,
233 PromiseTaskSync aSync = AsyncTask);
235 template <typename T>
236 void MaybeSomething(T& aArgument, MaybeFunc aFunc) {
237 ThreadsafeAutoJSContext cx;
238 JSObject* wrapper = GetWrapper();
239 MOZ_ASSERT(wrapper); // We preserved it!
241 JSAutoCompartment ac(cx, wrapper);
242 JS::Rooted<JS::Value> val(cx);
243 if (!ToJSValue(cx, aArgument, &val)) {
244 HandleException(cx);
245 return;
248 (this->*aFunc)(cx, val);
251 // Static methods for the PromiseInit functions.
252 static bool
253 JSCallback(JSContext *aCx, unsigned aArgc, JS::Value *aVp);
255 static bool
256 ThenableResolverCommon(JSContext* aCx, uint32_t /* PromiseCallback::Task */ aTask,
257 unsigned aArgc, JS::Value* aVp);
258 static bool
259 JSCallbackThenableResolver(JSContext *aCx, unsigned aArgc, JS::Value *aVp);
260 static bool
261 JSCallbackThenableRejecter(JSContext *aCx, unsigned aArgc, JS::Value *aVp);
263 static JSObject*
264 CreateFunction(JSContext* aCx, JSObject* aParent, Promise* aPromise,
265 int32_t aTask);
267 static JSObject*
268 CreateThenableFunction(JSContext* aCx, Promise* aPromise, uint32_t aTask);
270 void HandleException(JSContext* aCx);
272 void RemoveFeature();
274 nsRefPtr<nsIGlobalObject> mGlobal;
276 nsTArray<nsRefPtr<PromiseCallback> > mResolveCallbacks;
277 nsTArray<nsRefPtr<PromiseCallback> > mRejectCallbacks;
279 JS::Heap<JS::Value> mResult;
280 PromiseState mState;
281 bool mTaskPending;
282 bool mHadRejectCallback;
284 bool mResolvePending;
286 // If a rejected promise on a worker has no reject callbacks attached, it
287 // needs to know when the worker is shutting down, to report the error on the
288 // console before the worker's context is deleted. This feature is used for
289 // that purpose.
290 nsAutoPtr<PromiseReportRejectFeature> mFeature;
293 } // namespace dom
294 } // namespace mozilla
296 #endif // mozilla_dom_Promise_h