MediaDevices.getUserMedia should migrate from callbacks to DOMPromise
[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 #if ENABLE(PROMISES)
30
31 #include "JSDOMBinding.h"
32 #include <heap/StrongInlines.h>
33 #include <runtime/JSPromiseDeferred.h>
34 #include <wtf/Optional.h>
35
36 namespace WebCore {
37
38 class DeferredWrapper {
39 public:
40     DeferredWrapper(JSC::ExecState*, JSDOMGlobalObject*, JSC::JSPromiseDeferred*);
41
42     template<class ResolveResultType>
43     void resolve(const ResolveResultType&);
44
45     template<class RejectResultType>
46     void reject(const RejectResultType&);
47
48     JSC::JSObject* promise() const;
49
50 private:
51     void callFunction(JSC::ExecState&, JSC::JSValue function, JSC::JSValue resolution);
52     void resolve(JSC::ExecState& state, JSC::JSValue resolution) { callFunction(state, m_deferred->resolve(), resolution); }
53     void reject(JSC::ExecState& state, JSC::JSValue resolution) { callFunction(state, m_deferred->reject(), resolution); }
54
55     JSC::Strong<JSDOMGlobalObject> m_globalObject;
56     JSC::Strong<JSC::JSPromiseDeferred> m_deferred;
57 };
58
59 void rejectPromiseWithExceptionIfAny(JSC::ExecState&, JSDOMGlobalObject&, JSC::JSPromiseDeferred&);
60
61 template<class JSClassName>
62 inline JSC::JSValue callPromiseFunction(JSC::ExecState& state, JSClassName& jsObject, JSC::EncodedJSValue promiseFunction(JSC::ExecState*, JSClassName*, JSC::JSPromiseDeferred*))
63 {
64     JSC::JSPromiseDeferred* promiseDeferred = JSC::JSPromiseDeferred::create(&state, jsObject.globalObject());
65     promiseFunction(&state, &jsObject, promiseDeferred);
66
67     rejectPromiseWithExceptionIfAny(state, *jsObject.globalObject(), *promiseDeferred);
68     ASSERT(!state.hadException());
69     return promiseDeferred->promise();
70 }
71
72 template <typename Value, typename Error>
73 class DOMPromise {
74 public:
75     DOMPromise(DeferredWrapper&& wrapper) : m_wrapper(WTF::move(wrapper)) { }
76     DOMPromise(DOMPromise&& promise) : m_wrapper(WTF::move(promise.m_wrapper)) { }
77
78     DOMPromise(const DOMPromise&)= delete;
79     DOMPromise& operator=(DOMPromise const&) = delete;
80
81     void resolve(const Value& value) { m_wrapper.resolve<Value>(value); }
82     void reject(const Error& error) { m_wrapper.reject<Error>(error); }
83
84 private:
85     DeferredWrapper m_wrapper;
86 };
87
88 template<typename Value, typename Error>
89 class DOMPromiseWithCallback {
90 public:
91     DOMPromiseWithCallback(DeferredWrapper&& wrapper) : m_wrapper(WTF::move(wrapper)) { }
92     DOMPromiseWithCallback(std::function<void(const Value&)> resolve, std::function<void(const Error&)> reject)
93         : m_resolveCallback(WTF::move(resolve))
94         , m_rejectCallback(WTF::move(reject))
95     {
96         ASSERT(m_resolveCallback);
97         ASSERT(m_rejectCallback);
98     }
99     explicit DOMPromiseWithCallback(DOMPromiseWithCallback&& promise)
100         : m_wrapper(WTF::move(promise.m_wrapper))
101         , m_resolveCallback(WTF::move(promise.m_resolveCallback))
102         , m_rejectCallback(WTF::move(promise.m_rejectCallback)) { }
103
104     void resolve(const Value&);
105     void reject(const Error&);
106
107 private:
108     Optional<DOMPromise<Value, Error>> m_wrapper;
109     std::function<void(const Value&)> m_resolveCallback;
110     std::function<void(const Error&)> m_rejectCallback;
111 };
112
113 template<class ResolveResultType>
114 inline void DeferredWrapper::resolve(const ResolveResultType& result)
115 {
116     ASSERT(m_deferred);
117     ASSERT(m_globalObject);
118     JSC::ExecState* exec = m_globalObject->globalExec();
119     JSC::JSLockHolder locker(exec);
120     resolve(*exec, toJS(exec, m_globalObject.get(), result));
121 }
122
123 template<class RejectResultType>
124 inline void DeferredWrapper::reject(const RejectResultType& result)
125 {
126     ASSERT(m_deferred);
127     ASSERT(m_globalObject);
128     JSC::ExecState* exec = m_globalObject->globalExec();
129     JSC::JSLockHolder locker(exec);
130     reject(*exec, toJS(exec, m_globalObject.get(), result));
131 }
132
133 template<>
134 inline void DeferredWrapper::reject(const std::nullptr_t&)
135 {
136     ASSERT(m_deferred);
137     ASSERT(m_globalObject);
138     JSC::ExecState* exec = m_globalObject->globalExec();
139     JSC::JSLockHolder locker(exec);
140     reject(*exec, JSC::jsNull());
141 }
142
143 template<>
144 inline void DeferredWrapper::reject(const JSC::JSValue& value)
145 {
146     ASSERT(m_deferred);
147     ASSERT(m_globalObject);
148     JSC::ExecState* exec = m_globalObject->globalExec();
149     JSC::JSLockHolder locker(exec);
150     reject(*exec, value);
151 }
152
153 template<>
154 inline void DeferredWrapper::reject<ExceptionCode>(const ExceptionCode& ec)
155 {
156     ASSERT(m_deferred);
157     ASSERT(m_globalObject);
158     JSC::ExecState* exec = m_globalObject->globalExec();
159     JSC::JSLockHolder locker(exec);
160     reject(*exec, createDOMException(exec, ec));
161 }
162
163 template<>
164 inline void DeferredWrapper::resolve<String>(const String& result)
165 {
166     ASSERT(m_deferred);
167     ASSERT(m_globalObject);
168     JSC::ExecState* exec = m_globalObject->globalExec();
169     JSC::JSLockHolder locker(exec);
170     resolve(*exec, jsString(exec, result));
171 }
172
173 template<>
174 inline void DeferredWrapper::resolve<bool>(const bool& result)
175 {
176     ASSERT(m_deferred);
177     ASSERT(m_globalObject);
178     JSC::ExecState* exec = m_globalObject->globalExec();
179     JSC::JSLockHolder locker(exec);
180     resolve(*exec, JSC::jsBoolean(result));
181 }
182
183 template<>
184 inline void DeferredWrapper::resolve<JSC::JSValue>(const JSC::JSValue& value)
185 {
186     ASSERT(m_deferred);
187     ASSERT(m_globalObject);
188     JSC::ExecState* exec = m_globalObject->globalExec();
189     JSC::JSLockHolder locker(exec);
190     resolve(*exec, value);
191 }
192 template<>
193 inline void DeferredWrapper::resolve<Vector<unsigned char>>(const Vector<unsigned char>& result)
194 {
195     ASSERT(m_deferred);
196     ASSERT(m_globalObject);
197     JSC::ExecState* exec = m_globalObject->globalExec();
198     JSC::JSLockHolder locker(exec);
199     RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(result.data(), result.size());
200     resolve(*exec, toJS(exec, m_globalObject.get(), buffer.get()));
201 }
202
203 template<>
204 inline void DeferredWrapper::resolve(const std::nullptr_t&)
205 {
206     ASSERT(m_deferred);
207     ASSERT(m_globalObject);
208     JSC::ExecState* exec = m_globalObject->globalExec();
209     JSC::JSLockHolder locker(exec);
210     resolve(*exec, JSC::jsUndefined());
211 }
212
213 template<>
214 inline void DeferredWrapper::reject<String>(const String& result)
215 {
216     ASSERT(m_deferred);
217     ASSERT(m_globalObject);
218     JSC::ExecState* exec = m_globalObject->globalExec();
219     JSC::JSLockHolder locker(exec);
220     reject(*exec, jsString(exec, result));
221 }
222
223 template<typename Value, typename Error>
224 inline void DOMPromiseWithCallback<Value, Error>::resolve(const Value& value)
225 {
226     if (m_resolveCallback) {
227         m_resolveCallback(value);
228         return;
229     }
230     ASSERT(m_wrapper);
231     m_wrapper.value().resolve(value);
232 }
233
234 template<typename Value, typename Error>
235 inline void DOMPromiseWithCallback<Value, Error>::reject(const Error& error)
236 {
237     if (m_rejectCallback) {
238         m_rejectCallback(error);
239         return;
240     }
241     ASSERT(m_wrapper);
242     m_wrapper.value().reject(error);
243 }
244
245 }
246
247 #endif // ENABLE(PROMISES)
248
249 #endif // JSDOMPromise_h