1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/promise/Promise.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,273 @@ 1.4 +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef mozilla_dom_Promise_h 1.11 +#define mozilla_dom_Promise_h 1.12 + 1.13 +#include "mozilla/Attributes.h" 1.14 +#include "mozilla/ErrorResult.h" 1.15 +#include "mozilla/TypeTraits.h" 1.16 +#include "mozilla/dom/BindingDeclarations.h" 1.17 +#include "nsCycleCollectionParticipant.h" 1.18 +#include "mozilla/dom/PromiseBinding.h" 1.19 +#include "mozilla/dom/ToJSValue.h" 1.20 +#include "nsWrapperCache.h" 1.21 +#include "nsAutoPtr.h" 1.22 +#include "js/TypeDecls.h" 1.23 + 1.24 +#include "mozilla/dom/workers/bindings/WorkerFeature.h" 1.25 + 1.26 +class nsIGlobalObject; 1.27 + 1.28 +namespace mozilla { 1.29 +namespace dom { 1.30 + 1.31 +class AnyCallback; 1.32 +class PromiseCallback; 1.33 +class PromiseInit; 1.34 +class PromiseNativeHandler; 1.35 + 1.36 +class Promise; 1.37 +class PromiseReportRejectFeature : public workers::WorkerFeature 1.38 +{ 1.39 + // The Promise that owns this feature. 1.40 + Promise* mPromise; 1.41 + 1.42 +public: 1.43 + PromiseReportRejectFeature(Promise* aPromise) 1.44 + : mPromise(aPromise) 1.45 + { 1.46 + MOZ_ASSERT(mPromise); 1.47 + } 1.48 + 1.49 + virtual bool 1.50 + Notify(JSContext* aCx, workers::Status aStatus) MOZ_OVERRIDE; 1.51 +}; 1.52 + 1.53 +class Promise MOZ_FINAL : public nsISupports, 1.54 + public nsWrapperCache 1.55 +{ 1.56 + friend class NativePromiseCallback; 1.57 + friend class PromiseResolverMixin; 1.58 + friend class PromiseResolverTask; 1.59 + friend class PromiseTask; 1.60 + friend class PromiseReportRejectFeature; 1.61 + friend class RejectPromiseCallback; 1.62 + friend class ResolvePromiseCallback; 1.63 + friend class WorkerPromiseResolverTask; 1.64 + friend class WorkerPromiseTask; 1.65 + friend class WrapperPromiseCallback; 1.66 + 1.67 + ~Promise(); 1.68 + 1.69 +public: 1.70 + NS_DECL_CYCLE_COLLECTING_ISUPPORTS 1.71 + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Promise) 1.72 + 1.73 + Promise(nsIGlobalObject* aGlobal); 1.74 + 1.75 + typedef void (Promise::*MaybeFunc)(JSContext* aCx, 1.76 + JS::Handle<JS::Value> aValue); 1.77 + 1.78 + void MaybeResolve(JSContext* aCx, 1.79 + JS::Handle<JS::Value> aValue); 1.80 + void MaybeReject(JSContext* aCx, 1.81 + JS::Handle<JS::Value> aValue); 1.82 + 1.83 + // Helpers for using Promise from C++. 1.84 + // Most DOM objects are handled already. To add a new type T, add a 1.85 + // ToJSValue overload in ToJSValue.h. 1.86 + // aArg is a const reference so we can pass rvalues like integer constants 1.87 + template <typename T> 1.88 + void MaybeResolve(const T& aArg) { 1.89 + MaybeSomething(aArg, &Promise::MaybeResolve); 1.90 + } 1.91 + 1.92 + // aArg is a const reference so we can pass rvalues like NS_ERROR_* 1.93 + template <typename T> 1.94 + void MaybeReject(const T& aArg) { 1.95 + MaybeSomething(aArg, &Promise::MaybeReject); 1.96 + } 1.97 + 1.98 + // WebIDL 1.99 + 1.100 + nsIGlobalObject* GetParentObject() const 1.101 + { 1.102 + return mGlobal; 1.103 + } 1.104 + 1.105 + virtual JSObject* 1.106 + WrapObject(JSContext* aCx) MOZ_OVERRIDE; 1.107 + 1.108 + static already_AddRefed<Promise> 1.109 + Constructor(const GlobalObject& aGlobal, PromiseInit& aInit, 1.110 + ErrorResult& aRv); 1.111 + 1.112 + static already_AddRefed<Promise> 1.113 + Resolve(const GlobalObject& aGlobal, JSContext* aCx, 1.114 + JS::Handle<JS::Value> aValue, ErrorResult& aRv); 1.115 + 1.116 + static already_AddRefed<Promise> 1.117 + Resolve(nsIGlobalObject* aGlobal, JSContext* aCx, 1.118 + JS::Handle<JS::Value> aValue, ErrorResult& aRv); 1.119 + 1.120 + static already_AddRefed<Promise> 1.121 + Reject(const GlobalObject& aGlobal, JSContext* aCx, 1.122 + JS::Handle<JS::Value> aValue, ErrorResult& aRv); 1.123 + 1.124 + static already_AddRefed<Promise> 1.125 + Reject(nsIGlobalObject* aGlobal, JSContext* aCx, 1.126 + JS::Handle<JS::Value> aValue, ErrorResult& aRv); 1.127 + 1.128 + already_AddRefed<Promise> 1.129 + Then(JSContext* aCx, AnyCallback* aResolveCallback, 1.130 + AnyCallback* aRejectCallback); 1.131 + 1.132 + already_AddRefed<Promise> 1.133 + Catch(JSContext* aCx, AnyCallback* aRejectCallback); 1.134 + 1.135 + static already_AddRefed<Promise> 1.136 + All(const GlobalObject& aGlobal, JSContext* aCx, 1.137 + const Sequence<JS::Value>& aIterable, ErrorResult& aRv); 1.138 + 1.139 + static already_AddRefed<Promise> 1.140 + Race(const GlobalObject& aGlobal, JSContext* aCx, 1.141 + const Sequence<JS::Value>& aIterable, ErrorResult& aRv); 1.142 + 1.143 + void AppendNativeHandler(PromiseNativeHandler* aRunnable); 1.144 + 1.145 +private: 1.146 + enum PromiseState { 1.147 + Pending, 1.148 + Resolved, 1.149 + Rejected 1.150 + }; 1.151 + 1.152 + enum PromiseTaskSync { 1.153 + SyncTask, 1.154 + AsyncTask 1.155 + }; 1.156 + 1.157 + void SetState(PromiseState aState) 1.158 + { 1.159 + MOZ_ASSERT(mState == Pending); 1.160 + MOZ_ASSERT(aState != Pending); 1.161 + mState = aState; 1.162 + } 1.163 + 1.164 + void SetResult(JS::Handle<JS::Value> aValue) 1.165 + { 1.166 + mResult = aValue; 1.167 + } 1.168 + 1.169 + // This method processes promise's resolve/reject callbacks with promise's 1.170 + // result. It's executed when the resolver.resolve() or resolver.reject() is 1.171 + // called or when the promise already has a result and new callbacks are 1.172 + // appended by then(), catch() or done(). 1.173 + void RunTask(); 1.174 + 1.175 + void RunResolveTask(JS::Handle<JS::Value> aValue, 1.176 + Promise::PromiseState aState, 1.177 + PromiseTaskSync aAsynchronous); 1.178 + 1.179 + void AppendCallbacks(PromiseCallback* aResolveCallback, 1.180 + PromiseCallback* aRejectCallback); 1.181 + 1.182 + // If we have been rejected and our mResult is a JS exception, 1.183 + // report it to the error console. 1.184 + // Use MaybeReportRejectedOnce() for actual calls. 1.185 + void MaybeReportRejected(); 1.186 + 1.187 + void MaybeReportRejectedOnce() { 1.188 + MaybeReportRejected(); 1.189 + RemoveFeature(); 1.190 + mResult = JS::UndefinedValue(); 1.191 + } 1.192 + 1.193 + void MaybeResolveInternal(JSContext* aCx, 1.194 + JS::Handle<JS::Value> aValue, 1.195 + PromiseTaskSync aSync = AsyncTask); 1.196 + void MaybeRejectInternal(JSContext* aCx, 1.197 + JS::Handle<JS::Value> aValue, 1.198 + PromiseTaskSync aSync = AsyncTask); 1.199 + 1.200 + void ResolveInternal(JSContext* aCx, 1.201 + JS::Handle<JS::Value> aValue, 1.202 + PromiseTaskSync aSync = AsyncTask); 1.203 + 1.204 + void RejectInternal(JSContext* aCx, 1.205 + JS::Handle<JS::Value> aValue, 1.206 + PromiseTaskSync aSync = AsyncTask); 1.207 + 1.208 + // Helper methods for using Promises from C++ 1.209 + JSObject* GetOrCreateWrapper(JSContext* aCx); 1.210 + 1.211 + template <typename T> 1.212 + void MaybeSomething(T& aArgument, MaybeFunc aFunc) { 1.213 + ThreadsafeAutoJSContext cx; 1.214 + 1.215 + JSObject* wrapper = GetOrCreateWrapper(cx); 1.216 + if (!wrapper) { 1.217 + HandleException(cx); 1.218 + return; 1.219 + } 1.220 + 1.221 + JSAutoCompartment ac(cx, wrapper); 1.222 + JS::Rooted<JS::Value> val(cx); 1.223 + if (!ToJSValue(cx, aArgument, &val)) { 1.224 + HandleException(cx); 1.225 + return; 1.226 + } 1.227 + 1.228 + (this->*aFunc)(cx, val); 1.229 + } 1.230 + 1.231 + // Static methods for the PromiseInit functions. 1.232 + static bool 1.233 + JSCallback(JSContext *aCx, unsigned aArgc, JS::Value *aVp); 1.234 + 1.235 + static bool 1.236 + ThenableResolverCommon(JSContext* aCx, uint32_t /* PromiseCallback::Task */ aTask, 1.237 + unsigned aArgc, JS::Value* aVp); 1.238 + static bool 1.239 + JSCallbackThenableResolver(JSContext *aCx, unsigned aArgc, JS::Value *aVp); 1.240 + static bool 1.241 + JSCallbackThenableRejecter(JSContext *aCx, unsigned aArgc, JS::Value *aVp); 1.242 + 1.243 + static JSObject* 1.244 + CreateFunction(JSContext* aCx, JSObject* aParent, Promise* aPromise, 1.245 + int32_t aTask); 1.246 + 1.247 + static JSObject* 1.248 + CreateThenableFunction(JSContext* aCx, Promise* aPromise, uint32_t aTask); 1.249 + 1.250 + void HandleException(JSContext* aCx); 1.251 + 1.252 + void RemoveFeature(); 1.253 + 1.254 + nsRefPtr<nsIGlobalObject> mGlobal; 1.255 + 1.256 + nsTArray<nsRefPtr<PromiseCallback> > mResolveCallbacks; 1.257 + nsTArray<nsRefPtr<PromiseCallback> > mRejectCallbacks; 1.258 + 1.259 + JS::Heap<JS::Value> mResult; 1.260 + PromiseState mState; 1.261 + bool mTaskPending; 1.262 + bool mHadRejectCallback; 1.263 + 1.264 + bool mResolvePending; 1.265 + 1.266 + // If a rejected promise on a worker has no reject callbacks attached, it 1.267 + // needs to know when the worker is shutting down, to report the error on the 1.268 + // console before the worker's context is deleted. This feature is used for 1.269 + // that purpose. 1.270 + nsAutoPtr<PromiseReportRejectFeature> mFeature; 1.271 +}; 1.272 + 1.273 +} // namespace dom 1.274 +} // namespace mozilla 1.275 + 1.276 +#endif // mozilla_dom_Promise_h