dom/promise/Promise.h

branch
TOR_BUG_9701
changeset 14
925c144e1f1f
equal deleted inserted replaced
-1:000000000000 0:d1c3d6858a05
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/. */
6
7 #ifndef mozilla_dom_Promise_h
8 #define mozilla_dom_Promise_h
9
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 "nsWrapperCache.h"
18 #include "nsAutoPtr.h"
19 #include "js/TypeDecls.h"
20
21 #include "mozilla/dom/workers/bindings/WorkerFeature.h"
22
23 class nsIGlobalObject;
24
25 namespace mozilla {
26 namespace dom {
27
28 class AnyCallback;
29 class PromiseCallback;
30 class PromiseInit;
31 class PromiseNativeHandler;
32
33 class Promise;
34 class PromiseReportRejectFeature : public workers::WorkerFeature
35 {
36 // The Promise that owns this feature.
37 Promise* mPromise;
38
39 public:
40 PromiseReportRejectFeature(Promise* aPromise)
41 : mPromise(aPromise)
42 {
43 MOZ_ASSERT(mPromise);
44 }
45
46 virtual bool
47 Notify(JSContext* aCx, workers::Status aStatus) MOZ_OVERRIDE;
48 };
49
50 class Promise MOZ_FINAL : public nsISupports,
51 public nsWrapperCache
52 {
53 friend class NativePromiseCallback;
54 friend class PromiseResolverMixin;
55 friend class PromiseResolverTask;
56 friend class PromiseTask;
57 friend class PromiseReportRejectFeature;
58 friend class RejectPromiseCallback;
59 friend class ResolvePromiseCallback;
60 friend class WorkerPromiseResolverTask;
61 friend class WorkerPromiseTask;
62 friend class WrapperPromiseCallback;
63
64 ~Promise();
65
66 public:
67 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
68 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Promise)
69
70 Promise(nsIGlobalObject* aGlobal);
71
72 typedef void (Promise::*MaybeFunc)(JSContext* aCx,
73 JS::Handle<JS::Value> aValue);
74
75 void MaybeResolve(JSContext* aCx,
76 JS::Handle<JS::Value> aValue);
77 void MaybeReject(JSContext* aCx,
78 JS::Handle<JS::Value> aValue);
79
80 // Helpers for using Promise from C++.
81 // Most DOM objects are handled already. To add a new type T, add a
82 // ToJSValue overload in ToJSValue.h.
83 // aArg is a const reference so we can pass rvalues like integer constants
84 template <typename T>
85 void MaybeResolve(const T& aArg) {
86 MaybeSomething(aArg, &Promise::MaybeResolve);
87 }
88
89 // aArg is a const reference so we can pass rvalues like NS_ERROR_*
90 template <typename T>
91 void MaybeReject(const T& aArg) {
92 MaybeSomething(aArg, &Promise::MaybeReject);
93 }
94
95 // WebIDL
96
97 nsIGlobalObject* GetParentObject() const
98 {
99 return mGlobal;
100 }
101
102 virtual JSObject*
103 WrapObject(JSContext* aCx) MOZ_OVERRIDE;
104
105 static already_AddRefed<Promise>
106 Constructor(const GlobalObject& aGlobal, PromiseInit& aInit,
107 ErrorResult& aRv);
108
109 static already_AddRefed<Promise>
110 Resolve(const GlobalObject& aGlobal, JSContext* aCx,
111 JS::Handle<JS::Value> aValue, ErrorResult& aRv);
112
113 static already_AddRefed<Promise>
114 Resolve(nsIGlobalObject* aGlobal, JSContext* aCx,
115 JS::Handle<JS::Value> aValue, ErrorResult& aRv);
116
117 static already_AddRefed<Promise>
118 Reject(const GlobalObject& aGlobal, JSContext* aCx,
119 JS::Handle<JS::Value> aValue, ErrorResult& aRv);
120
121 static already_AddRefed<Promise>
122 Reject(nsIGlobalObject* aGlobal, JSContext* aCx,
123 JS::Handle<JS::Value> aValue, ErrorResult& aRv);
124
125 already_AddRefed<Promise>
126 Then(JSContext* aCx, AnyCallback* aResolveCallback,
127 AnyCallback* aRejectCallback);
128
129 already_AddRefed<Promise>
130 Catch(JSContext* aCx, AnyCallback* aRejectCallback);
131
132 static already_AddRefed<Promise>
133 All(const GlobalObject& aGlobal, JSContext* aCx,
134 const Sequence<JS::Value>& aIterable, ErrorResult& aRv);
135
136 static already_AddRefed<Promise>
137 Race(const GlobalObject& aGlobal, JSContext* aCx,
138 const Sequence<JS::Value>& aIterable, ErrorResult& aRv);
139
140 void AppendNativeHandler(PromiseNativeHandler* aRunnable);
141
142 private:
143 enum PromiseState {
144 Pending,
145 Resolved,
146 Rejected
147 };
148
149 enum PromiseTaskSync {
150 SyncTask,
151 AsyncTask
152 };
153
154 void SetState(PromiseState aState)
155 {
156 MOZ_ASSERT(mState == Pending);
157 MOZ_ASSERT(aState != Pending);
158 mState = aState;
159 }
160
161 void SetResult(JS::Handle<JS::Value> aValue)
162 {
163 mResult = aValue;
164 }
165
166 // This method processes promise's resolve/reject callbacks with promise's
167 // result. It's executed when the resolver.resolve() or resolver.reject() is
168 // called or when the promise already has a result and new callbacks are
169 // appended by then(), catch() or done().
170 void RunTask();
171
172 void RunResolveTask(JS::Handle<JS::Value> aValue,
173 Promise::PromiseState aState,
174 PromiseTaskSync aAsynchronous);
175
176 void AppendCallbacks(PromiseCallback* aResolveCallback,
177 PromiseCallback* aRejectCallback);
178
179 // If we have been rejected and our mResult is a JS exception,
180 // report it to the error console.
181 // Use MaybeReportRejectedOnce() for actual calls.
182 void MaybeReportRejected();
183
184 void MaybeReportRejectedOnce() {
185 MaybeReportRejected();
186 RemoveFeature();
187 mResult = JS::UndefinedValue();
188 }
189
190 void MaybeResolveInternal(JSContext* aCx,
191 JS::Handle<JS::Value> aValue,
192 PromiseTaskSync aSync = AsyncTask);
193 void MaybeRejectInternal(JSContext* aCx,
194 JS::Handle<JS::Value> aValue,
195 PromiseTaskSync aSync = AsyncTask);
196
197 void ResolveInternal(JSContext* aCx,
198 JS::Handle<JS::Value> aValue,
199 PromiseTaskSync aSync = AsyncTask);
200
201 void RejectInternal(JSContext* aCx,
202 JS::Handle<JS::Value> aValue,
203 PromiseTaskSync aSync = AsyncTask);
204
205 // Helper methods for using Promises from C++
206 JSObject* GetOrCreateWrapper(JSContext* aCx);
207
208 template <typename T>
209 void MaybeSomething(T& aArgument, MaybeFunc aFunc) {
210 ThreadsafeAutoJSContext cx;
211
212 JSObject* wrapper = GetOrCreateWrapper(cx);
213 if (!wrapper) {
214 HandleException(cx);
215 return;
216 }
217
218 JSAutoCompartment ac(cx, wrapper);
219 JS::Rooted<JS::Value> val(cx);
220 if (!ToJSValue(cx, aArgument, &val)) {
221 HandleException(cx);
222 return;
223 }
224
225 (this->*aFunc)(cx, val);
226 }
227
228 // Static methods for the PromiseInit functions.
229 static bool
230 JSCallback(JSContext *aCx, unsigned aArgc, JS::Value *aVp);
231
232 static bool
233 ThenableResolverCommon(JSContext* aCx, uint32_t /* PromiseCallback::Task */ aTask,
234 unsigned aArgc, JS::Value* aVp);
235 static bool
236 JSCallbackThenableResolver(JSContext *aCx, unsigned aArgc, JS::Value *aVp);
237 static bool
238 JSCallbackThenableRejecter(JSContext *aCx, unsigned aArgc, JS::Value *aVp);
239
240 static JSObject*
241 CreateFunction(JSContext* aCx, JSObject* aParent, Promise* aPromise,
242 int32_t aTask);
243
244 static JSObject*
245 CreateThenableFunction(JSContext* aCx, Promise* aPromise, uint32_t aTask);
246
247 void HandleException(JSContext* aCx);
248
249 void RemoveFeature();
250
251 nsRefPtr<nsIGlobalObject> mGlobal;
252
253 nsTArray<nsRefPtr<PromiseCallback> > mResolveCallbacks;
254 nsTArray<nsRefPtr<PromiseCallback> > mRejectCallbacks;
255
256 JS::Heap<JS::Value> mResult;
257 PromiseState mState;
258 bool mTaskPending;
259 bool mHadRejectCallback;
260
261 bool mResolvePending;
262
263 // If a rejected promise on a worker has no reject callbacks attached, it
264 // needs to know when the worker is shutting down, to report the error on the
265 // console before the worker's context is deleted. This feature is used for
266 // that purpose.
267 nsAutoPtr<PromiseReportRejectFeature> mFeature;
268 };
269
270 } // namespace dom
271 } // namespace mozilla
272
273 #endif // mozilla_dom_Promise_h

mercurial