1/*
2 * Copyright (C) 2016 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 "JSDOMExceptionHandling.h"
29#include <JavaScriptCore/Error.h>
30
31namespace WebCore {
32
33// Conversion from JSValue -> Implementation
34template<typename T> struct Converter;
35
36namespace Detail {
37
38template <typename T> inline T* getPtrOrRef(const T* p) { return const_cast<T*>(p); }
39template <typename T> inline T& getPtrOrRef(const T& p) { return const_cast<T&>(p); }
40template <typename T> inline T* getPtrOrRef(const RefPtr<T>& p) { return p.get(); }
41template <typename T> inline T& getPtrOrRef(const Ref<T>& p) { return p.get(); }
42
43}
44
45struct DefaultExceptionThrower {
46 void operator()(JSC::ExecState& state, JSC::ThrowScope& scope)
47 {
48 throwTypeError(&state, scope);
49 }
50};
51
52template<typename T> typename Converter<T>::ReturnType convert(JSC::ExecState&, JSC::JSValue);
53template<typename T> typename Converter<T>::ReturnType convert(JSC::ExecState&, JSC::JSValue, JSC::JSObject&);
54template<typename T> typename Converter<T>::ReturnType convert(JSC::ExecState&, JSC::JSValue, JSDOMGlobalObject&);
55template<typename T, typename ExceptionThrower> typename Converter<T>::ReturnType convert(JSC::ExecState&, JSC::JSValue, ExceptionThrower&&);
56template<typename T, typename ExceptionThrower> typename Converter<T>::ReturnType convert(JSC::ExecState&, JSC::JSValue, JSC::JSObject&, ExceptionThrower&&);
57template<typename T, typename ExceptionThrower> typename Converter<T>::ReturnType convert(JSC::ExecState&, JSC::JSValue, JSDOMGlobalObject&, ExceptionThrower&&);
58
59template<typename T> inline typename Converter<T>::ReturnType convert(JSC::ExecState& state, JSC::JSValue value)
60{
61 return Converter<T>::convert(state, value);
62}
63
64template<typename T> inline typename Converter<T>::ReturnType convert(JSC::ExecState& state, JSC::JSValue value, JSC::JSObject& thisObject)
65{
66 return Converter<T>::convert(state, value, thisObject);
67}
68
69template<typename T> inline typename Converter<T>::ReturnType convert(JSC::ExecState& state, JSC::JSValue value, JSDOMGlobalObject& globalObject)
70{
71 return Converter<T>::convert(state, value, globalObject);
72}
73
74template<typename T, typename ExceptionThrower> inline typename Converter<T>::ReturnType convert(JSC::ExecState& state, JSC::JSValue value, ExceptionThrower&& exceptionThrower)
75{
76 return Converter<T>::convert(state, value, std::forward<ExceptionThrower>(exceptionThrower));
77}
78
79template<typename T, typename ExceptionThrower> inline typename Converter<T>::ReturnType convert(JSC::ExecState& state, JSC::JSValue value, JSC::JSObject& thisObject, ExceptionThrower&& exceptionThrower)
80{
81 return Converter<T>::convert(state, value, thisObject, std::forward<ExceptionThrower>(exceptionThrower));
82}
83
84template<typename T, typename ExceptionThrower> inline typename Converter<T>::ReturnType convert(JSC::ExecState& state, JSC::JSValue value, JSDOMGlobalObject& globalObject, ExceptionThrower&& exceptionThrower)
85{
86 return Converter<T>::convert(state, value, globalObject, std::forward<ExceptionThrower>(exceptionThrower));
87}
88
89
90template <typename T>
91struct IsExceptionOr : public std::integral_constant<bool, WTF::IsTemplate<std::decay_t<T>, ExceptionOr>::value> { };
92
93
94// Conversion from Implementation -> JSValue
95template<typename T> struct JSConverter;
96
97template<typename T, typename U> inline JSC::JSValue toJS(U&&);
98template<typename T, typename U> inline JSC::JSValue toJS(JSC::ExecState&, U&&);
99template<typename T, typename U> inline JSC::JSValue toJS(JSC::ExecState&, JSDOMGlobalObject&, U&&);
100template<typename T, typename U> inline JSC::JSValue toJSNewlyCreated(JSC::ExecState&, JSDOMGlobalObject&, U&&);
101template<typename T, typename U> inline auto toJS(JSC::ExecState&, JSC::ThrowScope&, U&&) -> std::enable_if_t<IsExceptionOr<U>::value, JSC::JSValue>;
102template<typename T, typename U> inline auto toJS(JSC::ExecState&, JSC::ThrowScope&, U&&) -> std::enable_if_t<!IsExceptionOr<U>::value, JSC::JSValue>;
103template<typename T, typename U> inline auto toJS(JSC::ExecState&, JSDOMGlobalObject&, JSC::ThrowScope&, U&&) -> std::enable_if_t<IsExceptionOr<U>::value, JSC::JSValue>;
104template<typename T, typename U> inline auto toJS(JSC::ExecState&, JSDOMGlobalObject&, JSC::ThrowScope&, U&&) -> std::enable_if_t<!IsExceptionOr<U>::value, JSC::JSValue>;
105template<typename T, typename U> inline auto toJSNewlyCreated(JSC::ExecState&, JSDOMGlobalObject&, JSC::ThrowScope&, U&&) -> std::enable_if_t<IsExceptionOr<U>::value, JSC::JSValue>;
106template<typename T, typename U> inline auto toJSNewlyCreated(JSC::ExecState&, JSDOMGlobalObject&, JSC::ThrowScope&, U&&) -> std::enable_if_t<!IsExceptionOr<U>::value, JSC::JSValue>;
107
108template<typename T, bool needsState = JSConverter<T>::needsState, bool needsGlobalObject = JSConverter<T>::needsGlobalObject>
109struct JSConverterOverloader;
110
111template<typename T>
112struct JSConverterOverloader<T, true, true> {
113 template<typename U> static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject& globalObject, U&& value)
114 {
115 return JSConverter<T>::convert(state, globalObject, std::forward<U>(value));
116 }
117};
118
119template<typename T>
120struct JSConverterOverloader<T, true, false> {
121 template<typename U> static JSC::JSValue convert(JSC::ExecState& state, U&& value)
122 {
123 return JSConverter<T>::convert(state, std::forward<U>(value));
124 }
125
126 template<typename U> static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject&, U&& value)
127 {
128 return JSConverter<T>::convert(state, std::forward<U>(value));
129 }
130};
131
132template<typename T>
133struct JSConverterOverloader<T, false, false> {
134 template<typename U> static JSC::JSValue convert(JSC::ExecState&, U&& value)
135 {
136 return JSConverter<T>::convert(std::forward<U>(value));
137 }
138
139 template<typename U> static JSC::JSValue convert(JSC::ExecState&, JSDOMGlobalObject&, U&& value)
140 {
141 return JSConverter<T>::convert(std::forward<U>(value));
142 }
143};
144
145template<typename T, typename U> inline JSC::JSValue toJS(U&& value)
146{
147 return JSConverter<T>::convert(std::forward<U>(value));
148}
149
150template<typename T, typename U> inline JSC::JSValue toJS(JSC::ExecState& state, U&& value)
151{
152 return JSConverterOverloader<T>::convert(state, std::forward<U>(value));
153}
154
155template<typename T, typename U> inline JSC::JSValue toJS(JSC::ExecState& state, JSDOMGlobalObject& globalObject, U&& value)
156{
157 return JSConverterOverloader<T>::convert(state, globalObject, std::forward<U>(value));
158}
159
160template<typename T, typename U> inline JSC::JSValue toJSNewlyCreated(JSC::ExecState& state, JSDOMGlobalObject& globalObject, U&& value)
161{
162 return JSConverter<T>::convertNewlyCreated(state, globalObject, std::forward<U>(value));
163}
164
165template<typename T, typename U> inline auto toJS(JSC::ExecState& state, JSC::ThrowScope& throwScope, U&& value) -> std::enable_if_t<IsExceptionOr<U>::value, JSC::JSValue>
166{
167 if (UNLIKELY(value.hasException())) {
168 propagateException(state, throwScope, value.releaseException());
169 return { };
170 }
171
172 return toJS<T>(state, value.releaseReturnValue());
173}
174
175template<typename T, typename U> inline auto toJS(JSC::ExecState& state, JSC::ThrowScope&, U&& value) -> std::enable_if_t<!IsExceptionOr<U>::value, JSC::JSValue>
176{
177 return toJS<T>(state, std::forward<U>(value));
178}
179
180template<typename T, typename U> inline auto toJS(JSC::ExecState& state, JSDOMGlobalObject& globalObject, JSC::ThrowScope& throwScope, U&& value) -> std::enable_if_t<IsExceptionOr<U>::value, JSC::JSValue>
181{
182 if (UNLIKELY(value.hasException())) {
183 propagateException(state, throwScope, value.releaseException());
184 return { };
185 }
186
187 return toJS<T>(state, globalObject, value.releaseReturnValue());
188}
189
190template<typename T, typename U> inline auto toJS(JSC::ExecState& state, JSDOMGlobalObject& globalObject, JSC::ThrowScope&, U&& value) -> std::enable_if_t<!IsExceptionOr<U>::value, JSC::JSValue>
191{
192 return toJS<T>(state, globalObject, std::forward<U>(value));
193}
194
195template<typename T, typename U> inline auto toJSNewlyCreated(JSC::ExecState& state, JSDOMGlobalObject& globalObject, JSC::ThrowScope& throwScope, U&& value) -> std::enable_if_t<IsExceptionOr<U>::value, JSC::JSValue>
196{
197 if (UNLIKELY(value.hasException())) {
198 propagateException(state, throwScope, value.releaseException());
199 return { };
200 }
201
202 return toJSNewlyCreated<T>(state, globalObject, value.releaseReturnValue());
203}
204
205template<typename T, typename U> inline auto toJSNewlyCreated(JSC::ExecState& state, JSDOMGlobalObject& globalObject, JSC::ThrowScope&, U&& value) -> std::enable_if_t<!IsExceptionOr<U>::value, JSC::JSValue>
206{
207 return toJSNewlyCreated<T>(state, globalObject, std::forward<U>(value));
208}
209
210
211template<typename T> struct DefaultConverter {
212 using ReturnType = typename T::ImplementationType;
213
214 // We assume the worst, subtypes can override to be less pessimistic.
215 // An example of something that can have side effects
216 // is having a converter that does JSC::JSValue::toNumber.
217 // toNumber() in JavaScript can call arbitrary JS functions.
218 //
219 // An example of something that does not have side effects
220 // is something having a converter that does JSC::JSValue::toBoolean.
221 // toBoolean() in JS can't call arbitrary functions.
222 static constexpr bool conversionHasSideEffects = true;
223};
224
225// Conversion from JSValue -> Implementation for variadic arguments
226template<typename IDLType> struct VariadicConverter;
227
228} // namespace WebCore
229