268 lines
12 KiB
C++
268 lines
12 KiB
C++
/*
|
|
* Copyright (C) 2016 Apple Inc. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "JSDOMExceptionHandling.h"
|
|
#include <JavaScriptCore/Error.h>
|
|
|
|
namespace WebCore {
|
|
|
|
// Conversion from JSValue -> Implementation
|
|
template<typename T> struct Converter;
|
|
|
|
namespace Detail {
|
|
|
|
template <typename T> inline T* getPtrOrRef(const T* p) { return const_cast<T*>(p); }
|
|
template <typename T> inline T& getPtrOrRef(const T& p) { return const_cast<T&>(p); }
|
|
template <typename T> inline T* getPtrOrRef(const RefPtr<T>& p) { return p.get(); }
|
|
template <typename T> inline T& getPtrOrRef(const Ref<T>& p) { return p.get(); }
|
|
|
|
}
|
|
|
|
struct DefaultExceptionThrower {
|
|
void operator()(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope)
|
|
{
|
|
throwTypeError(&lexicalGlobalObject, scope);
|
|
}
|
|
};
|
|
|
|
template<typename T> typename Converter<T>::ReturnType convert(JSC::JSGlobalObject&, JSC::JSValue);
|
|
template<typename T> typename Converter<T>::ReturnType convert(JSC::JSGlobalObject&, JSC::JSValue, JSC::JSObject&);
|
|
template<typename T> typename Converter<T>::ReturnType convert(JSC::JSGlobalObject&, JSC::JSValue, JSDOMGlobalObject&);
|
|
template<typename T, typename ExceptionThrower> typename Converter<T>::ReturnType convert(JSC::JSGlobalObject&, JSC::JSValue, ExceptionThrower&&);
|
|
template<typename T, typename ExceptionThrower> typename Converter<T>::ReturnType convert(JSC::JSGlobalObject&, JSC::JSValue, JSC::JSObject&, ExceptionThrower&&);
|
|
template<typename T, typename ExceptionThrower> typename Converter<T>::ReturnType convert(JSC::JSGlobalObject&, JSC::JSValue, JSDOMGlobalObject&, ExceptionThrower&&);
|
|
|
|
template<typename T> inline typename Converter<T>::ReturnType convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value)
|
|
{
|
|
return Converter<T>::convert(lexicalGlobalObject, value);
|
|
}
|
|
|
|
template<typename T> inline typename Converter<T>::ReturnType convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value, JSC::JSObject& thisObject)
|
|
{
|
|
return Converter<T>::convert(lexicalGlobalObject, value, thisObject);
|
|
}
|
|
|
|
template<typename T> inline typename Converter<T>::ReturnType convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value, JSDOMGlobalObject& globalObject)
|
|
{
|
|
return Converter<T>::convert(lexicalGlobalObject, value, globalObject);
|
|
}
|
|
|
|
template<typename T, typename ExceptionThrower> inline typename Converter<T>::ReturnType convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value, ExceptionThrower&& exceptionThrower)
|
|
{
|
|
return Converter<T>::convert(lexicalGlobalObject, value, std::forward<ExceptionThrower>(exceptionThrower));
|
|
}
|
|
|
|
template<typename T, typename ExceptionThrower> inline typename Converter<T>::ReturnType convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value, JSC::JSObject& thisObject, ExceptionThrower&& exceptionThrower)
|
|
{
|
|
return Converter<T>::convert(lexicalGlobalObject, value, thisObject, std::forward<ExceptionThrower>(exceptionThrower));
|
|
}
|
|
|
|
template<typename T, typename ExceptionThrower> inline typename Converter<T>::ReturnType convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value, JSDOMGlobalObject& globalObject, ExceptionThrower&& exceptionThrower)
|
|
{
|
|
return Converter<T>::convert(lexicalGlobalObject, value, globalObject, std::forward<ExceptionThrower>(exceptionThrower));
|
|
}
|
|
|
|
|
|
// Conversion from Implementation -> JSValue
|
|
template<typename T> struct JSConverter;
|
|
|
|
template<typename T, typename U> inline JSC::JSValue toJS(U&&);
|
|
template<typename T, typename U> inline JSC::JSValue toJS(JSC::JSGlobalObject&, U&&);
|
|
template<typename T, typename U> inline JSC::JSValue toJS(JSC::JSGlobalObject&, JSDOMGlobalObject&, U&&);
|
|
template<typename T, typename U> inline JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject&, JSDOMGlobalObject&, U&&);
|
|
|
|
template<typename T, typename U> inline JSC::JSValue toJS(JSC::JSGlobalObject&, JSC::ThrowScope&, U&& valueOrFunctor);
|
|
template<typename T, typename U> inline JSC::JSValue toJS(JSC::JSGlobalObject&, JSDOMGlobalObject&, JSC::ThrowScope&, U&& valueOrFunctor);
|
|
template<typename T, typename U> inline JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject&, JSDOMGlobalObject&, JSC::ThrowScope&, U&& valueOrFunctor);
|
|
|
|
template<typename T, bool needsState = JSConverter<T>::needsState, bool needsGlobalObject = JSConverter<T>::needsGlobalObject>
|
|
struct JSConverterOverloader;
|
|
|
|
template<typename T>
|
|
struct JSConverterOverloader<T, true, true> {
|
|
template<typename U> static JSC::JSValue convert(JSC::JSGlobalObject& lexicalGlobalObject, JSDOMGlobalObject& globalObject, U&& value)
|
|
{
|
|
return JSConverter<T>::convert(lexicalGlobalObject, globalObject, std::forward<U>(value));
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
struct JSConverterOverloader<T, true, false> {
|
|
template<typename U> static JSC::JSValue convert(JSC::JSGlobalObject& lexicalGlobalObject, U&& value)
|
|
{
|
|
return JSConverter<T>::convert(lexicalGlobalObject, std::forward<U>(value));
|
|
}
|
|
|
|
template<typename U> static JSC::JSValue convert(JSC::JSGlobalObject& lexicalGlobalObject, JSDOMGlobalObject&, U&& value)
|
|
{
|
|
return JSConverter<T>::convert(lexicalGlobalObject, std::forward<U>(value));
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
struct JSConverterOverloader<T, false, false> {
|
|
template<typename U> static JSC::JSValue convert(JSC::JSGlobalObject&, U&& value)
|
|
{
|
|
return JSConverter<T>::convert(std::forward<U>(value));
|
|
}
|
|
|
|
template<typename U> static JSC::JSValue convert(JSC::JSGlobalObject&, JSDOMGlobalObject&, U&& value)
|
|
{
|
|
return JSConverter<T>::convert(std::forward<U>(value));
|
|
}
|
|
};
|
|
|
|
template<typename T, typename U> inline JSC::JSValue toJS(U&& value)
|
|
{
|
|
return JSConverter<T>::convert(std::forward<U>(value));
|
|
}
|
|
|
|
template<typename T, typename U> inline JSC::JSValue toJS(JSC::JSGlobalObject& lexicalGlobalObject, U&& value)
|
|
{
|
|
return JSConverterOverloader<T>::convert(lexicalGlobalObject, std::forward<U>(value));
|
|
}
|
|
|
|
template<typename T, typename U> inline JSC::JSValue toJS(JSC::JSGlobalObject& lexicalGlobalObject, JSDOMGlobalObject& globalObject, U&& value)
|
|
{
|
|
return JSConverterOverloader<T>::convert(lexicalGlobalObject, globalObject, std::forward<U>(value));
|
|
}
|
|
|
|
template<typename T, typename U> inline JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject& lexicalGlobalObject, JSDOMGlobalObject& globalObject, U&& value)
|
|
{
|
|
return JSConverter<T>::convertNewlyCreated(lexicalGlobalObject, globalObject, std::forward<U>(value));
|
|
}
|
|
|
|
template<typename T, typename U> inline JSC::JSValue toJS(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& throwScope, U&& valueOrFunctor)
|
|
{
|
|
if constexpr (std::is_invocable_v<U>) {
|
|
using FunctorReturnType = std::invoke_result_t<U>;
|
|
|
|
if constexpr (std::is_same_v<void, FunctorReturnType>) {
|
|
valueOrFunctor();
|
|
return JSC::jsUndefined();
|
|
} else if constexpr (std::is_same_v<ExceptionOr<void>, FunctorReturnType>) {
|
|
auto result = valueOrFunctor();
|
|
if (UNLIKELY(result.hasException())) {
|
|
propagateException(lexicalGlobalObject, throwScope, result.releaseException());
|
|
return { };
|
|
}
|
|
return JSC::jsUndefined();
|
|
} else
|
|
return toJS<T>(lexicalGlobalObject, throwScope, valueOrFunctor());
|
|
} else {
|
|
if constexpr (IsExceptionOr<U>) {
|
|
if (UNLIKELY(valueOrFunctor.hasException())) {
|
|
propagateException(lexicalGlobalObject, throwScope, valueOrFunctor.releaseException());
|
|
return { };
|
|
}
|
|
|
|
return toJS<T>(lexicalGlobalObject, valueOrFunctor.releaseReturnValue());
|
|
} else
|
|
return toJS<T>(lexicalGlobalObject, std::forward<U>(valueOrFunctor));
|
|
}
|
|
}
|
|
|
|
template<typename T, typename U> inline JSC::JSValue toJS(JSC::JSGlobalObject& lexicalGlobalObject, JSDOMGlobalObject& globalObject, JSC::ThrowScope& throwScope, U&& valueOrFunctor)
|
|
{
|
|
if constexpr (std::is_invocable_v<U>) {
|
|
using FunctorReturnType = std::invoke_result_t<U>;
|
|
|
|
if constexpr (std::is_same_v<void, FunctorReturnType>) {
|
|
valueOrFunctor();
|
|
return JSC::jsUndefined();
|
|
} else if constexpr (std::is_same_v<ExceptionOr<void>, FunctorReturnType>) {
|
|
auto result = valueOrFunctor();
|
|
if (UNLIKELY(result.hasException())) {
|
|
propagateException(lexicalGlobalObject, throwScope, result.releaseException());
|
|
return { };
|
|
}
|
|
return JSC::jsUndefined();
|
|
} else
|
|
return toJS<T>(lexicalGlobalObject, globalObject, throwScope, valueOrFunctor());
|
|
} else {
|
|
if constexpr (IsExceptionOr<U>) {
|
|
if (UNLIKELY(valueOrFunctor.hasException())) {
|
|
propagateException(lexicalGlobalObject, throwScope, valueOrFunctor.releaseException());
|
|
return { };
|
|
}
|
|
|
|
return toJS<T>(lexicalGlobalObject, globalObject, valueOrFunctor.releaseReturnValue());
|
|
} else
|
|
return toJS<T>(lexicalGlobalObject, globalObject, std::forward<U>(valueOrFunctor));
|
|
}
|
|
}
|
|
|
|
template<typename T, typename U> inline JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject& lexicalGlobalObject, JSDOMGlobalObject& globalObject, JSC::ThrowScope& throwScope, U&& valueOrFunctor)
|
|
{
|
|
if constexpr (std::is_invocable_v<U>) {
|
|
using FunctorReturnType = std::invoke_result_t<U>;
|
|
|
|
if constexpr (std::is_same_v<void, FunctorReturnType>) {
|
|
valueOrFunctor();
|
|
return JSC::jsUndefined();
|
|
} else if constexpr (std::is_same_v<ExceptionOr<void>, FunctorReturnType>) {
|
|
auto result = valueOrFunctor();
|
|
if (UNLIKELY(result.hasException())) {
|
|
propagateException(lexicalGlobalObject, throwScope, result.releaseException());
|
|
return { };
|
|
}
|
|
return JSC::jsUndefined();
|
|
} else
|
|
return toJSNewlyCreated<T>(lexicalGlobalObject, globalObject, throwScope, valueOrFunctor());
|
|
|
|
} else {
|
|
if constexpr (IsExceptionOr<U>) {
|
|
if (UNLIKELY(valueOrFunctor.hasException())) {
|
|
propagateException(lexicalGlobalObject, throwScope, valueOrFunctor.releaseException());
|
|
return { };
|
|
}
|
|
|
|
return toJSNewlyCreated<T>(lexicalGlobalObject, globalObject, valueOrFunctor.releaseReturnValue());
|
|
} else
|
|
return toJSNewlyCreated<T>(lexicalGlobalObject, globalObject, std::forward<U>(valueOrFunctor));
|
|
}
|
|
}
|
|
|
|
template<typename T> struct DefaultConverter {
|
|
using ReturnType = typename T::ImplementationType;
|
|
|
|
// We assume the worst, subtypes can override to be less pessimistic.
|
|
// An example of something that can have side effects
|
|
// is having a converter that does JSC::JSValue::toNumber.
|
|
// toNumber() in JavaScript can call arbitrary JS functions.
|
|
//
|
|
// An example of something that does not have side effects
|
|
// is something having a converter that does JSC::JSValue::toBoolean.
|
|
// toBoolean() in JS can't call arbitrary functions.
|
|
static constexpr bool conversionHasSideEffects = true;
|
|
};
|
|
|
|
// Conversion from JSValue -> Implementation for variadic arguments
|
|
template<typename IDLType> struct VariadicConverter;
|
|
|
|
} // namespace WebCore
|