[Fetch API] Response constructor should be able to take a ReadableStream as body
[WebKit-https.git] / Source / WebCore / bindings / js / JSDOMPromise.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 #ifndef JSDOMPromise_h
27 #define JSDOMPromise_h
28
29 #include "JSDOMBinding.h"
30 #include <heap/StrongInlines.h>
31 #include <runtime/JSPromiseDeferred.h>
32 #include <wtf/Optional.h>
33
34 namespace WebCore {
35
36 template<typename DOMClass>
37 struct TypeInspector {
38 private:
39     template<typename T> static constexpr auto testIsVector(int) -> decltype(std::declval<T>().shrinkToFit(), bool()) { return true; }
40     template<typename T> static constexpr bool testIsVector(...) { return false; }
41
42     template<typename T> static constexpr auto testIsRef(int) -> decltype(T::isRef) { return true; }
43     template<typename T> static constexpr bool testIsRef(...) { return false; }
44
45     template<typename T> static constexpr auto testIsRefPtr(int) -> decltype(T::isRefPtr) { return true; }
46     template<typename T> static constexpr bool testIsRefPtr(...) { return false; }
47
48 public:
49     static constexpr bool isRefOrRefPtr = testIsRef<DOMClass>(0) || testIsRefPtr<DOMClass>(0);
50     static constexpr bool isPassByValueType = std::is_pointer<DOMClass>::value
51         || std::is_same<DOMClass, std::nullptr_t>::value
52         || std::is_same<DOMClass, JSC::JSValue>::value
53         || std::is_same<DOMClass, bool>::value;
54     static constexpr bool isPassByConstRefType = testIsVector<DOMClass>(0)
55         || std::is_same<DOMClass, String>::value;
56 };
57
58 template<typename DOMClass, typename Enable = void>
59 struct PromiseResultInspector {
60 public:
61     static constexpr bool passByValue = false;
62     static constexpr bool passByRef = true;
63     static constexpr bool passByURef = false;
64     static constexpr bool passByConstRef = false;
65
66     typedef DOMClass& Type;
67 };
68
69 template<typename DOMClass>
70 struct PromiseResultInspector<DOMClass, typename std::enable_if<TypeInspector<DOMClass>::isPassByValueType>::type> {
71 public:
72     static constexpr bool passByValue = true;
73     static constexpr bool passByRef = false;
74     static constexpr bool passByURef = false;
75     static constexpr bool passByConstRef = false;
76
77     typedef DOMClass Type;
78 };
79
80 template<typename DOMClass>
81 struct PromiseResultInspector<DOMClass, typename std::enable_if<TypeInspector<DOMClass>::isPassByConstRefType>::type> {
82 public:
83     static constexpr bool passByValue = false;
84     static constexpr bool passByRef = false;
85     static constexpr bool passByURef = false;
86     static constexpr bool passByConstRef = true;
87
88     typedef const DOMClass& Type;
89 };
90
91 template<typename DOMClass>
92 struct PromiseResultInspector<DOMClass, typename std::enable_if<TypeInspector<DOMClass>::isRefOrRefPtr>::type> {
93     static constexpr bool passByValue = false;
94     static constexpr bool passByRef = false;
95     static constexpr bool passByURef = true;
96     static constexpr bool passByConstRef = false;
97 };
98
99 class DeferredWrapper {
100 public:
101     DeferredWrapper(JSC::ExecState*, JSDOMGlobalObject*, JSC::JSPromiseDeferred*);
102
103     template<class ResolveResultType> typename std::enable_if<PromiseResultInspector<ResolveResultType>::passByValue, void>::type
104     resolve(ResolveResultType result) { resolveWithValue(result); }
105     template<class ResolveResultType> typename std::enable_if<PromiseResultInspector<ResolveResultType>::passByRef, void>::type
106     resolve(ResolveResultType& result) { resolveWithValue(result); }
107     template<class ResolveResultType> typename std::enable_if<PromiseResultInspector<ResolveResultType>::passByURef, void>::type
108     resolve(ResolveResultType&& result) { resolveWithValue(std::forward<ResolveResultType>(result)); }
109     template<class ResolveResultType> typename std::enable_if<PromiseResultInspector<ResolveResultType>::passByConstRef, void>::type
110     resolve(const ResolveResultType& result) { resolveWithValue(result); }
111
112     template<class RejectResultType> typename std::enable_if<PromiseResultInspector<RejectResultType>::passByValue, void>::type
113     reject(RejectResultType result) { rejectWithValue(result); }
114     template<class RejectResultType> typename std::enable_if<PromiseResultInspector<RejectResultType>::passByRef, void>::type
115     reject(RejectResultType& result) { rejectWithValue(result); }
116     template<class RejectResultType> typename std::enable_if<PromiseResultInspector<RejectResultType>::passByURef, void>::type
117     reject(RejectResultType&& result) { rejectWithValue(std::forward<RejectResultType>(result)); }
118     template<class RejectResultType> typename std::enable_if<PromiseResultInspector<RejectResultType>::passByConstRef, void>::type
119     reject(const RejectResultType& result) { rejectWithValue(result); }
120
121     template<class ResolveResultType> void resolveWithNewlyCreated(Ref<ResolveResultType>&&);
122
123     void reject(ExceptionCode, const String& = { });
124
125     JSDOMGlobalObject& globalObject() const;
126     JSC::JSValue promise() const;
127
128 private:
129     void callFunction(JSC::ExecState&, JSC::JSValue function, JSC::JSValue resolution);
130     void resolve(JSC::ExecState& state, JSC::JSValue resolution) { callFunction(state, m_deferred->resolve(), resolution); }
131     void reject(JSC::ExecState& state, JSC::JSValue resolution) { callFunction(state, m_deferred->reject(), resolution); }
132
133     template<class RejectResultType> void rejectWithValue(RejectResultType&&);
134     template<class ResolveResultType> void resolveWithValue(ResolveResultType&&);
135
136     JSC::Strong<JSDOMGlobalObject> m_globalObject;
137     JSC::Strong<JSC::JSPromiseDeferred> m_deferred;
138 };
139
140 void fulfillPromiseWithJSON(DeferredWrapper&, const String&);
141 void fulfillPromiseWithArrayBuffer(DeferredWrapper&, ArrayBuffer*);
142 void fulfillPromiseWithArrayBuffer(DeferredWrapper&, const void*, size_t);
143 void rejectPromiseWithExceptionIfAny(JSC::ExecState&, JSDOMGlobalObject&, JSC::JSPromiseDeferred&);
144
145 inline JSC::JSValue callPromiseFunction(JSC::ExecState& state, JSC::EncodedJSValue promiseFunction(JSC::ExecState*, JSC::JSPromiseDeferred*))
146 {
147     JSDOMGlobalObject& globalObject = *JSC::jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject());
148     JSC::JSPromiseDeferred& promiseDeferred = *JSC::JSPromiseDeferred::create(&state, &globalObject);
149     promiseFunction(&state, &promiseDeferred);
150
151     rejectPromiseWithExceptionIfAny(state, globalObject, promiseDeferred);
152     ASSERT(!state.hadException());
153     return promiseDeferred.promise();
154 }
155
156 // At the moment, Value cannot be a Ref<T> or RefPtr<T>, it should be a DOM class.
157 template <typename Value>
158 class DOMPromise {
159 public:
160     DOMPromise(DeferredWrapper&& wrapper) : m_wrapper(WTFMove(wrapper)) { }
161     DOMPromise(DOMPromise&& promise) : m_wrapper(WTFMove(promise.m_wrapper)) { }
162
163     DOMPromise(const DOMPromise&) = default;
164     DOMPromise& operator=(DOMPromise const&) = default;
165
166     void resolve(typename PromiseResultInspector<Value>::Type value) { m_wrapper.resolve(value); }
167
168     template<typename... ErrorType> void reject(ErrorType&&... error) { m_wrapper.reject(std::forward<ErrorType>(error)...); }
169
170     DeferredWrapper& deferredWrapper() { return m_wrapper; }
171
172 private:
173     DeferredWrapper m_wrapper;
174 };
175
176 template<class ResolveResultType>
177 inline void DeferredWrapper::resolveWithValue(ResolveResultType&& result)
178 {
179     ASSERT(m_deferred);
180     ASSERT(m_globalObject);
181     JSC::ExecState* exec = m_globalObject->globalExec();
182     JSC::JSLockHolder locker(exec);
183     resolve(*exec, toJS(exec, m_globalObject.get(), std::forward<ResolveResultType>(result)));
184 }
185
186 template<class ResolveResultType>
187 inline void DeferredWrapper::resolveWithNewlyCreated(Ref<ResolveResultType>&& result)
188 {
189     ASSERT(m_deferred);
190     ASSERT(m_globalObject);
191     JSC::ExecState* exec = m_globalObject->globalExec();
192     JSC::JSLockHolder locker(exec);
193     resolve(*exec, toJSNewlyCreated(exec, m_globalObject.get(), WTFMove(result)));
194 }
195
196 template<class RejectResultType>
197 inline void DeferredWrapper::rejectWithValue(RejectResultType&& result)
198 {
199     ASSERT(m_deferred);
200     ASSERT(m_globalObject);
201     JSC::ExecState* exec = m_globalObject->globalExec();
202     JSC::JSLockHolder locker(exec);
203     reject(*exec, toJS(exec, m_globalObject.get(), std::forward<RejectResultType>(result)));
204 }
205
206 template<>
207 inline void DeferredWrapper::resolve(bool result)
208 {
209     ASSERT(m_deferred);
210     ASSERT(m_globalObject);
211     JSC::ExecState* exec = m_globalObject->globalExec();
212     JSC::JSLockHolder locker(exec);
213     resolve(*exec, JSC::jsBoolean(result));
214 }
215
216 template<>
217 inline void DeferredWrapper::resolve(JSC::JSValue value)
218 {
219     ASSERT(m_deferred);
220     ASSERT(m_globalObject);
221     JSC::ExecState* exec = m_globalObject->globalExec();
222     JSC::JSLockHolder locker(exec);
223     resolve(*exec, value);
224 }
225
226 template<>
227 inline void DeferredWrapper::reject(JSC::JSValue value)
228 {
229     ASSERT(m_deferred);
230     ASSERT(m_globalObject);
231     JSC::ExecState* exec = m_globalObject->globalExec();
232     JSC::JSLockHolder locker(exec);
233     reject(*exec, value);
234 }
235
236 template<>
237 inline void DeferredWrapper::resolve(std::nullptr_t)
238 {
239     ASSERT(m_deferred);
240     ASSERT(m_globalObject);
241     JSC::ExecState* exec = m_globalObject->globalExec();
242     JSC::JSLockHolder locker(exec);
243     resolve(*exec, JSC::jsUndefined());
244 }
245
246 template<>
247 inline void DeferredWrapper::reject(std::nullptr_t)
248 {
249     ASSERT(m_deferred);
250     ASSERT(m_globalObject);
251     JSC::ExecState* exec = m_globalObject->globalExec();
252     JSC::JSLockHolder locker(exec);
253     reject(*exec, JSC::jsNull());
254 }
255
256 template<>
257 inline void DeferredWrapper::resolve(const String& result)
258 {
259     ASSERT(m_deferred);
260     ASSERT(m_globalObject);
261     JSC::ExecState* exec = m_globalObject->globalExec();
262     JSC::JSLockHolder locker(exec);
263     resolve(*exec, jsString(exec, result));
264 }
265
266 template<>
267 inline void DeferredWrapper::reject(const String& result)
268 {
269     ASSERT(m_deferred);
270     ASSERT(m_globalObject);
271     JSC::ExecState* exec = m_globalObject->globalExec();
272     JSC::JSLockHolder locker(exec);
273     reject(*exec, jsString(exec, result));
274 }
275
276 }
277
278 #endif // JSDOMPromise_h