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