Remove excessive headers from JavaScriptCore
[WebKit-https.git] / Source / WebCore / bindings / js / JSDOMPromiseDeferred.h
1 /*
2  * Copyright (C) 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #pragma once
27
28 #include "JSDOMConvert.h"
29 #include "JSDOMGuardedObject.h"
30 #include <runtime/CatchScope.h>
31 #include <runtime/JSPromiseDeferred.h>
32
33 namespace WebCore {
34
35 class DeferredPromise : public DOMGuarded<JSC::JSPromiseDeferred> {
36 public:
37     static Ref<DeferredPromise> create(JSDOMGlobalObject& globalObject, JSC::JSPromiseDeferred& deferred)
38     {
39         return adoptRef(*new DeferredPromise(globalObject, deferred));
40     }
41
42     template<class IDLType>
43     void resolve(typename IDLType::ParameterType value)
44     {
45         if (isSuspended())
46             return;
47         ASSERT(deferred());
48         ASSERT(globalObject());
49         JSC::ExecState* exec = globalObject()->globalExec();
50         JSC::JSLockHolder locker(exec);
51         resolve(*exec, toJS<IDLType>(*exec, *globalObject(), std::forward<typename IDLType::ParameterType>(value)));
52     }
53
54     void resolve()
55     {
56         if (isSuspended())
57             return;
58         ASSERT(deferred());
59         ASSERT(globalObject());
60         JSC::ExecState* exec = globalObject()->globalExec();
61         JSC::JSLockHolder locker(exec);
62         resolve(*exec, JSC::jsUndefined());
63     }
64
65     template<class IDLType>
66     void resolveWithNewlyCreated(typename IDLType::ParameterType value)
67     {
68         if (isSuspended())
69             return;
70         ASSERT(deferred());
71         ASSERT(globalObject());
72         JSC::ExecState* exec = globalObject()->globalExec();
73         JSC::JSLockHolder locker(exec);
74         resolve(*exec, toJSNewlyCreated<IDLType>(*exec, *globalObject(), std::forward<typename IDLType::ParameterType>(value)));
75     }
76
77     template<class IDLType>
78     void reject(typename IDLType::ParameterType value)
79     {
80         if (isSuspended())
81             return;
82         ASSERT(deferred());
83         ASSERT(globalObject());
84         JSC::ExecState* exec = globalObject()->globalExec();
85         JSC::JSLockHolder locker(exec);
86         reject(*exec, toJS<IDLType>(*exec, *globalObject(), std::forward<typename IDLType::ParameterType>(value)));
87     }
88
89     void reject();
90     void reject(std::nullptr_t);
91     void reject(Exception&&);
92     WEBCORE_EXPORT void reject(ExceptionCode, const String& = { });
93     void reject(const JSC::PrivateName&);
94
95     template<typename Callback>
96     void resolveWithCallback(Callback callback)
97     {
98         if (isSuspended())
99             return;
100         ASSERT(deferred());
101         ASSERT(globalObject());
102         JSC::ExecState* exec = globalObject()->globalExec();
103         JSC::JSLockHolder locker(exec);
104         resolve(*exec, callback(*exec, *globalObject()));
105     }
106
107     template<typename Callback>
108     void rejectWithCallback(Callback callback)
109     {
110         if (isSuspended())
111             return;
112         ASSERT(deferred());
113         ASSERT(globalObject());
114         JSC::ExecState* exec = globalObject()->globalExec();
115         JSC::JSLockHolder locker(exec);
116         reject(*exec, callback(*exec, *globalObject()));
117     }
118
119     JSC::JSValue promise() const;
120
121 private:
122     DeferredPromise(JSDOMGlobalObject& globalObject, JSC::JSPromiseDeferred& deferred)
123         : DOMGuarded<JSC::JSPromiseDeferred>(globalObject, deferred)
124     {
125     }
126
127     JSC::JSPromiseDeferred* deferred() const { return guarded(); }
128
129     WEBCORE_EXPORT void callFunction(JSC::ExecState&, JSC::JSValue function, JSC::JSValue resolution);
130     void resolve(JSC::ExecState& state, JSC::JSValue resolution) { callFunction(state, deferred()->resolve(), resolution); }
131     void reject(JSC::ExecState& state, JSC::JSValue resolution) { callFunction(state, deferred()->reject(), resolution); }
132 };
133
134 class DOMPromiseDeferredBase {
135 public:
136     DOMPromiseDeferredBase(Ref<DeferredPromise>&& genericPromise)
137         : m_promiseDeferred(WTFMove(genericPromise))
138     {
139     }
140
141     DOMPromiseDeferredBase(DOMPromiseDeferredBase&& promise)
142         : m_promiseDeferred(WTFMove(promise.m_promiseDeferred))
143     {
144     }
145
146     DOMPromiseDeferredBase(const DOMPromiseDeferredBase& other)
147         : m_promiseDeferred(other.m_promiseDeferred.copyRef())
148     {
149     }
150
151     DOMPromiseDeferredBase& operator=(const DOMPromiseDeferredBase& other)
152     {
153         m_promiseDeferred = other.m_promiseDeferred.copyRef();
154         return *this;
155     }
156
157     DOMPromiseDeferredBase& operator=(DOMPromiseDeferredBase&& other)
158     {
159         m_promiseDeferred = WTFMove(other.m_promiseDeferred);
160         return *this;
161     }
162
163     void reject()
164     {
165         m_promiseDeferred->reject();
166     }
167
168     template<typename... ErrorType> 
169     void reject(ErrorType&&... error)
170     {
171         m_promiseDeferred->reject(std::forward<ErrorType>(error)...);
172     }
173
174     template<typename IDLType>
175     void rejectType(typename IDLType::ParameterType value)
176     {
177         m_promiseDeferred->reject<IDLType>(std::forward<typename IDLType::ParameterType>(value));
178     }
179
180     JSC::JSValue promise() const { return m_promiseDeferred->promise(); };
181
182 protected:
183     Ref<DeferredPromise> m_promiseDeferred;
184 };
185
186 template<typename IDLType> 
187 class DOMPromiseDeferred : public DOMPromiseDeferredBase {
188 public:
189     using DOMPromiseDeferredBase::DOMPromiseDeferredBase;
190     using DOMPromiseDeferredBase::operator=;
191     using DOMPromiseDeferredBase::promise;
192     using DOMPromiseDeferredBase::reject;
193
194     void resolve(typename IDLType::ParameterType value)
195     { 
196         m_promiseDeferred->resolve<IDLType>(std::forward<typename IDLType::ParameterType>(value));
197     }
198 };
199
200 template<> class DOMPromiseDeferred<void> : public DOMPromiseDeferredBase {
201 public:
202     using DOMPromiseDeferredBase::DOMPromiseDeferredBase;
203     using DOMPromiseDeferredBase::operator=;
204     using DOMPromiseDeferredBase::promise;
205     using DOMPromiseDeferredBase::reject;
206
207     void resolve()
208     { 
209         m_promiseDeferred->resolve();
210     }
211 };
212
213
214 Ref<DeferredPromise> createDeferredPromise(JSC::ExecState&, JSDOMWindow&);
215
216 void fulfillPromiseWithJSON(Ref<DeferredPromise>&&, const String&);
217 void fulfillPromiseWithArrayBuffer(Ref<DeferredPromise>&&, ArrayBuffer*);
218 void fulfillPromiseWithArrayBuffer(Ref<DeferredPromise>&&, const void*, size_t);
219 WEBCORE_EXPORT void rejectPromiseWithExceptionIfAny(JSC::ExecState&, JSDOMGlobalObject&, JSC::JSPromiseDeferred&);
220 JSC::EncodedJSValue createRejectedPromiseWithTypeError(JSC::ExecState&, const String&);
221
222 using PromiseFunction = void(JSC::ExecState&, Ref<DeferredPromise>&&);
223
224 enum class PromiseExecutionScope { WindowOnly, WindowOrWorker };
225
226 template<PromiseFunction promiseFunction, PromiseExecutionScope executionScope>
227 inline JSC::JSValue callPromiseFunction(JSC::ExecState& state)
228 {
229     JSC::VM& vm = state.vm();
230     auto scope = DECLARE_CATCH_SCOPE(vm);
231
232     JSDOMGlobalObject& globalObject = *JSC::jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject());
233     JSC::JSPromiseDeferred* promiseDeferred = JSC::JSPromiseDeferred::create(&state, &globalObject);
234
235     // promiseDeferred can be null when terminating a Worker abruptly.
236     if (executionScope == PromiseExecutionScope::WindowOrWorker && !promiseDeferred)
237         return JSC::jsUndefined();
238
239     promiseFunction(state, DeferredPromise::create(globalObject, *promiseDeferred));
240
241     rejectPromiseWithExceptionIfAny(state, globalObject, *promiseDeferred);
242     ASSERT_UNUSED(scope, !scope.exception());
243     return promiseDeferred->promise();
244 }
245
246 template<PromiseExecutionScope executionScope, typename PromiseFunctor>
247 inline JSC::JSValue callPromiseFunction(JSC::ExecState& state, PromiseFunctor functor)
248 {
249     JSC::VM& vm = state.vm();
250     auto scope = DECLARE_CATCH_SCOPE(vm);
251
252     JSDOMGlobalObject& globalObject = *JSC::jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject());
253     JSC::JSPromiseDeferred* promiseDeferred = JSC::JSPromiseDeferred::create(&state, &globalObject);
254
255     // promiseDeferred can be null when terminating a Worker abruptly.
256     if (executionScope == PromiseExecutionScope::WindowOrWorker && !promiseDeferred)
257         return JSC::jsUndefined();
258
259     functor(state, DeferredPromise::create(globalObject, *promiseDeferred));
260
261     rejectPromiseWithExceptionIfAny(state, globalObject, *promiseDeferred);
262     ASSERT_UNUSED(scope, !scope.exception());
263     return promiseDeferred->promise();
264 }
265
266 using BindingPromiseFunction = JSC::EncodedJSValue(JSC::ExecState*, Ref<DeferredPromise>&&);
267 template<BindingPromiseFunction bindingFunction>
268 inline void bindingPromiseFunctionAdapter(JSC::ExecState& state, Ref<DeferredPromise>&& promise)
269 {
270     bindingFunction(&state, WTFMove(promise));
271 }
272
273 template<BindingPromiseFunction bindingPromiseFunction, PromiseExecutionScope executionScope>
274 inline JSC::JSValue callPromiseFunction(JSC::ExecState& state)
275 {
276     return callPromiseFunction<bindingPromiseFunctionAdapter<bindingPromiseFunction>, executionScope>(state);
277 }
278
279 } // namespace WebCore