#pragma once
#include "BufferSource.h"
#include "IDLTypes.h"
#include "JSDOMBinding.h"
#include <runtime/JSONObject.h>
namespace WebCore {
template<typename T> struct Converter;
enum class IntegerConversionConfiguration { Normal, EnforceRange, Clamp };
enum class StringConversionConfiguration { Normal, TreatNullAsEmptyString };
struct DefaultExceptionThrower {
void operator()(JSC::ExecState& state, JSC::ThrowScope& scope)
{
throwTypeError(&state, scope);
}
};
template<typename T> typename Converter<T>::ReturnType convert(JSC::ExecState&, JSC::JSValue);
template<typename T> typename Converter<T>::ReturnType convert(JSC::ExecState&, JSC::JSValue, JSC::JSObject&);
template<typename T> typename Converter<T>::ReturnType convert(JSC::ExecState&, JSC::JSValue, JSDOMGlobalObject&);
template<typename T> typename Converter<T>::ReturnType convert(JSC::ExecState&, JSC::JSValue, IntegerConversionConfiguration);
template<typename T> typename Converter<T>::ReturnType convert(JSC::ExecState&, JSC::JSValue, StringConversionConfiguration);
template<typename T, typename ExceptionThrower> typename Converter<T>::ReturnType convert(JSC::ExecState&, JSC::JSValue, ExceptionThrower&&);
template<typename T, typename ExceptionThrower> typename Converter<T>::ReturnType convert(JSC::ExecState&, JSC::JSValue, JSC::JSObject&, ExceptionThrower&&);
template<typename T, typename ExceptionThrower> typename Converter<T>::ReturnType convert(JSC::ExecState&, JSC::JSValue, JSDOMGlobalObject&, ExceptionThrower&&);
template<typename T> T convertDictionary(JSC::ExecState&, JSC::JSValue);
template<typename T> std::optional<T> parseEnumeration(JSC::ExecState&, JSC::JSValue);
template<typename T> T convertEnumeration(JSC::ExecState&, JSC::JSValue);
template<typename T> const char* expectedEnumerationValues();
template<typename T> inline typename Converter<T>::ReturnType convert(JSC::ExecState& state, JSC::JSValue value)
{
return Converter<T>::convert(state, value);
}
template<typename T> inline typename Converter<T>::ReturnType convert(JSC::ExecState& state, JSC::JSValue value, JSC::JSObject& thisObject)
{
return Converter<T>::convert(state, value, thisObject);
}
template<typename T> inline typename Converter<T>::ReturnType convert(JSC::ExecState& state, JSC::JSValue value, JSDOMGlobalObject& globalObject)
{
return Converter<T>::convert(state, value, globalObject);
}
template<typename T> inline typename Converter<T>::ReturnType convert(JSC::ExecState& state, JSC::JSValue value, IntegerConversionConfiguration configuration)
{
return Converter<T>::convert(state, value, configuration);
}
template<typename T> inline typename Converter<T>::ReturnType convert(JSC::ExecState& state, JSC::JSValue value, StringConversionConfiguration configuration)
{
return Converter<T>::convert(state, value, configuration);
}
template<typename T, typename ExceptionThrower> inline typename Converter<T>::ReturnType convert(JSC::ExecState& state, JSC::JSValue value, ExceptionThrower&& exceptionThrower)
{
return Converter<T>::convert(state, value, std::forward<ExceptionThrower>(exceptionThrower));
}
template<typename T, typename ExceptionThrower> inline typename Converter<T>::ReturnType convert(JSC::ExecState& state, JSC::JSValue value, JSC::JSObject& thisObject, ExceptionThrower&& exceptionThrower)
{
return Converter<T>::convert(state, value, thisObject, std::forward<ExceptionThrower>(exceptionThrower));
}
template<typename T, typename ExceptionThrower> inline typename Converter<T>::ReturnType convert(JSC::ExecState& state, JSC::JSValue value, JSDOMGlobalObject& globalObject, ExceptionThrower&& exceptionThrower)
{
return Converter<T>::convert(state, value, globalObject, std::forward<ExceptionThrower>(exceptionThrower));
}
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::ExecState&, U&&);
template<typename T, typename U> inline JSC::JSValue toJS(JSC::ExecState&, JSDOMGlobalObject&, U&&);
template<typename T, typename U> inline JSC::JSValue toJS(JSC::ExecState&, JSC::ThrowScope&, ExceptionOr<U>&&);
template<typename T, typename U> inline JSC::JSValue toJS(JSC::ExecState&, JSDOMGlobalObject&, JSC::ThrowScope&, ExceptionOr<U>&&);
template<typename T, typename U> inline JSC::JSValue toJSNewlyCreated(JSC::ExecState&, JSDOMGlobalObject&, U&&);
template<typename T, typename U> inline JSC::JSValue toJSNewlyCreated(JSC::ExecState&, JSDOMGlobalObject&, JSC::ThrowScope&, ExceptionOr<U>&&);
template<typename T> JSC::JSString* convertEnumerationToJS(JSC::ExecState&, T);
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::ExecState& state, JSDOMGlobalObject& globalObject, U&& value)
{
return JSConverter<T>::convert(state, globalObject, std::forward<U>(value));
}
};
template<typename T>
struct JSConverterOverloader<T, true, false> {
template<typename U> static JSC::JSValue convert(JSC::ExecState& state, U&& value)
{
return JSConverter<T>::convert(state, std::forward<U>(value));
}
template<typename U> static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject&, U&& value)
{
return JSConverter<T>::convert(state, std::forward<U>(value));
}
};
template<typename T>
struct JSConverterOverloader<T, false, false> {
template<typename U> static JSC::JSValue convert(JSC::ExecState&, U&& value)
{
return JSConverter<T>::convert(std::forward<U>(value));
}
template<typename U> static JSC::JSValue convert(JSC::ExecState&, 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::ExecState& state, U&& value)
{
return JSConverterOverloader<T>::convert(state, std::forward<U>(value));
}
template<typename T, typename U> inline JSC::JSValue toJS(JSC::ExecState& state, JSDOMGlobalObject& globalObject, U&& value)
{
return JSConverterOverloader<T>::convert(state, globalObject, std::forward<U>(value));
}
template<typename T, typename U> inline JSC::JSValue toJS(JSC::ExecState& state, JSC::ThrowScope& throwScope, ExceptionOr<U>&& value)
{
if (UNLIKELY(value.hasException())) {
propagateException(state, throwScope, value.releaseException());
return { };
}
return toJS<T>(state, value.releaseReturnValue());
}
template<typename T, typename U> inline JSC::JSValue toJS(JSC::ExecState& state, JSDOMGlobalObject& globalObject, JSC::ThrowScope& throwScope, ExceptionOr<U>&& value)
{
if (UNLIKELY(value.hasException())) {
propagateException(state, throwScope, value.releaseException());
return { };
}
return toJS<T>(state, globalObject, value.releaseReturnValue());
}
template<typename T, typename U> inline JSC::JSValue toJSNewlyCreated(JSC::ExecState& state, JSDOMGlobalObject& globalObject, U&& value)
{
return JSConverter<T>::convertNewlyCreated(state, globalObject, std::forward<U>(value));
}
template<typename T, typename U> inline JSC::JSValue toJSNewlyCreated(JSC::ExecState& state, JSDOMGlobalObject& globalObject, JSC::ThrowScope& throwScope, ExceptionOr<U>&& value)
{
if (UNLIKELY(value.hasException())) {
propagateException(state, throwScope, value.releaseException());
return { };
}
return toJSNewlyCreated<T>(state, globalObject, value.releaseReturnValue());
}
template<typename T> struct DefaultConverter {
using ReturnType = typename T::ImplementationType;
};
namespace Detail {
template<typename IDLType>
struct NullableConversionType;
template<typename IDLType>
struct NullableConversionType {
using Type = typename IDLNullable<IDLType>::ImplementationType;
};
template<typename T>
struct NullableConversionType<IDLInterface<T>> {
using Type = typename Converter<IDLInterface<T>>::ReturnType;
};
}
template<typename T> struct Converter<IDLNullable<T>> : DefaultConverter<IDLNullable<T>> {
using ReturnType = typename Detail::NullableConversionType<T>::Type;
static ReturnType convert(JSC::ExecState& state, JSC::JSValue value)
{
if (value.isUndefinedOrNull())
return T::nullValue();
return Converter<T>::convert(state, value);
}
static ReturnType convert(JSC::ExecState& state, JSC::JSValue value, JSC::JSObject& thisObject)
{
if (value.isUndefinedOrNull())
return T::nullValue();
return Converter<T>::convert(state, value, thisObject);
}
static ReturnType convert(JSC::ExecState& state, JSC::JSValue value, JSDOMGlobalObject& globalObject)
{
if (value.isUndefinedOrNull())
return T::nullValue();
return Converter<T>::convert(state, value, globalObject);
}
static ReturnType convert(JSC::ExecState& state, JSC::JSValue value, IntegerConversionConfiguration configuration)
{
if (value.isUndefinedOrNull())
return T::nullValue();
return Converter<T>::convert(state, value, configuration);
}
static ReturnType convert(JSC::ExecState& state, JSC::JSValue value, StringConversionConfiguration configuration)
{
if (value.isUndefinedOrNull())
return T::nullValue();
return Converter<T>::convert(state, value, configuration);
}
template<typename ExceptionThrower = DefaultExceptionThrower>
static ReturnType convert(JSC::ExecState& state, JSC::JSValue value, ExceptionThrower&& exceptionThrower)
{
if (value.isUndefinedOrNull())
return T::nullValue();
return Converter<T>::convert(state, value, std::forward<ExceptionThrower>(exceptionThrower));
}
template<typename ExceptionThrower = DefaultExceptionThrower>
static ReturnType convert(JSC::ExecState& state, JSC::JSValue value, JSC::JSObject& thisObject, ExceptionThrower&& exceptionThrower)
{
if (value.isUndefinedOrNull())
return T::nullValue();
return Converter<T>::convert(state, value, thisObject, std::forward<ExceptionThrower>(exceptionThrower));
}
template<typename ExceptionThrower = DefaultExceptionThrower>
static ReturnType convert(JSC::ExecState& state, JSC::JSValue value, JSDOMGlobalObject& globalObject, ExceptionThrower&& exceptionThrower)
{
if (value.isUndefinedOrNull())
return T::nullValue();
return Converter<T>::convert(state, value, globalObject, std::forward<ExceptionThrower>(exceptionThrower));
}
};
template<typename T> struct JSConverter<IDLNullable<T>> {
using ImplementationType = typename IDLNullable<T>::ImplementationType;
static constexpr bool needsState = JSConverter<T>::needsState;
static constexpr bool needsGlobalObject = JSConverter<T>::needsGlobalObject;
template<typename U>
static JSC::JSValue convert(U&& value)
{
if (T::isNullValue(value))
return JSC::jsNull();
return JSConverter<T>::convert(T::extractValueFromNullable(value));
}
template<typename U>
static JSC::JSValue convert(JSC::ExecState& state, U&& value)
{
if (T::isNullValue(value))
return JSC::jsNull();
return JSConverter<T>::convert(state, T::extractValueFromNullable(value));
}
template<typename U>
static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject& globalObject, U&& value)
{
if (T::isNullValue(value))
return JSC::jsNull();
return JSConverter<T>::convert(state, globalObject, T::extractValueFromNullable(value));
}
template<typename U>
static JSC::JSValue convertNewlyCreated(JSC::ExecState& state, JSDOMGlobalObject& globalObject, U&& value)
{
if (T::isNullValue(value))
return JSC::jsNull();
return JSConverter<T>::convert(state, globalObject, T::extractValueFromNullable(value));
}
};
template<> struct Converter<IDLBoolean> : DefaultConverter<IDLBoolean> {
static bool convert(JSC::ExecState& state, JSC::JSValue value)
{
return value.toBoolean(&state);
}
};
template<> struct JSConverter<IDLBoolean> {
static constexpr bool needsState = false;
static constexpr bool needsGlobalObject = false;
static JSC::JSValue convert(bool value)
{
return JSC::jsBoolean(value);
}
};
template<> struct JSDOMWrapperConverterTraits<JSC::ArrayBuffer> {
using WrapperClass = JSC::JSArrayBuffer;
using ToWrappedReturnType = JSC::ArrayBuffer*;
};
template<> struct JSDOMWrapperConverterTraits<JSC::ArrayBufferView> {
using WrapperClass = JSC::JSArrayBufferView;
using ToWrappedReturnType = RefPtr<ArrayBufferView>;
};
template<typename Adaptor> struct JSDOMWrapperConverterTraits<JSC::GenericTypedArrayView<Adaptor>> {
using WrapperClass = JSC::JSGenericTypedArrayView<Adaptor>;
using ToWrappedReturnType = RefPtr<JSC::GenericTypedArrayView<Adaptor>>;
};
template<typename T> struct Converter<IDLInterface<T>> : DefaultConverter<IDLInterface<T>> {
using ReturnType = typename JSDOMWrapperConverterTraits<T>::ToWrappedReturnType;
using WrapperType = typename JSDOMWrapperConverterTraits<T>::WrapperClass;
template<typename ExceptionThrower = DefaultExceptionThrower>
static ReturnType convert(JSC::ExecState& state, JSC::JSValue value, ExceptionThrower&& exceptionThrower = ExceptionThrower())
{
JSC::VM& vm = state.vm();
auto scope = DECLARE_THROW_SCOPE(vm);
ReturnType object = WrapperType::toWrapped(value);
if (UNLIKELY(!object))
exceptionThrower(state, scope);
return object;
}
};
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 const_cast<T*>(p.get()); }
template <typename T> inline T& getPtrOrRef(const Ref<T>& p) { return const_cast<T&>(p.get()); }
}
template<typename T> struct JSConverter<IDLInterface<T>> {
static constexpr bool needsState = true;
static constexpr bool needsGlobalObject = true;
template <typename U>
static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject& globalObject, const U& value)
{
return toJS(&state, &globalObject, Detail::getPtrOrRef(value));
}
template<typename U>
static JSC::JSValue convertNewlyCreated(JSC::ExecState& state, JSDOMGlobalObject& globalObject, U&& value)
{
return toJSNewlyCreated(&state, &globalObject, std::forward<U>(value));
}
};
template<> struct Converter<IDLAny> : DefaultConverter<IDLAny> {
static JSC::JSValue convert(JSC::ExecState&, JSC::JSValue value)
{
return value;
}
};
template<> struct JSConverter<IDLAny> {
static constexpr bool needsState = false;
static constexpr bool needsGlobalObject = false;
static JSC::JSValue convert(const JSC::JSValue& value)
{
return value;
}
};
template<> struct Converter<IDLByte> : DefaultConverter<IDLByte> {
static int8_t convert(JSC::ExecState& state, JSC::JSValue value, IntegerConversionConfiguration configuration = IntegerConversionConfiguration::Normal)
{
switch (configuration) {
case IntegerConversionConfiguration::Normal:
break;
case IntegerConversionConfiguration::EnforceRange:
return toInt8EnforceRange(state, value);
case IntegerConversionConfiguration::Clamp:
return toInt8Clamp(state, value);
}
return toInt8(state, value);
}
};
template<> struct JSConverter<IDLByte> {
using Type = typename IDLByte::ImplementationType;
static constexpr bool needsState = false;
static constexpr bool needsGlobalObject = false;
static JSC::JSValue convert(Type value)
{
return JSC::jsNumber(value);
}
};
template<> struct Converter<IDLOctet> : DefaultConverter<IDLOctet> {
static uint8_t convert(JSC::ExecState& state, JSC::JSValue value, IntegerConversionConfiguration configuration = IntegerConversionConfiguration::Normal)
{
switch (configuration) {
case IntegerConversionConfiguration::Normal:
break;
case IntegerConversionConfiguration::EnforceRange:
return toUInt8EnforceRange(state, value);
case IntegerConversionConfiguration::Clamp:
return toUInt8Clamp(state, value);
}
return toUInt8(state, value);
}
};
template<> struct JSConverter<IDLOctet> {
using Type = typename IDLOctet::ImplementationType;
static constexpr bool needsState = false;
static constexpr bool needsGlobalObject = false;
static JSC::JSValue convert(Type value)
{
return JSC::jsNumber(value);
}
};
template<> struct Converter<IDLShort> : DefaultConverter<IDLShort> {
static int16_t convert(JSC::ExecState& state, JSC::JSValue value, IntegerConversionConfiguration configuration = IntegerConversionConfiguration::Normal)
{
switch (configuration) {
case IntegerConversionConfiguration::Normal:
break;
case IntegerConversionConfiguration::EnforceRange:
return toInt16EnforceRange(state, value);
case IntegerConversionConfiguration::Clamp:
return toInt16Clamp(state, value);
}
return toInt16(state, value);
}
};
template<> struct JSConverter<IDLShort> {
using Type = typename IDLShort::ImplementationType;
static constexpr bool needsState = false;
static constexpr bool needsGlobalObject = false;
static JSC::JSValue convert(Type value)
{
return JSC::jsNumber(value);
}
};
template<> struct Converter<IDLUnsignedShort> : DefaultConverter<IDLUnsignedShort> {
static uint16_t convert(JSC::ExecState& state, JSC::JSValue value, IntegerConversionConfiguration configuration = IntegerConversionConfiguration::Normal)
{
switch (configuration) {
case IntegerConversionConfiguration::Normal:
break;
case IntegerConversionConfiguration::EnforceRange:
return toUInt16EnforceRange(state, value);
case IntegerConversionConfiguration::Clamp:
return toUInt16Clamp(state, value);
}
return toUInt16(state, value);
}
};
template<> struct JSConverter<IDLUnsignedShort> {
using Type = typename IDLUnsignedShort::ImplementationType;
static constexpr bool needsState = false;
static constexpr bool needsGlobalObject = false;
static JSC::JSValue convert(Type value)
{
return JSC::jsNumber(value);
}
};
template<> struct Converter<IDLLong> : DefaultConverter<IDLLong> {
static int32_t convert(JSC::ExecState& state, JSC::JSValue value, IntegerConversionConfiguration configuration = IntegerConversionConfiguration::Normal)
{
switch (configuration) {
case IntegerConversionConfiguration::Normal:
break;
case IntegerConversionConfiguration::EnforceRange:
return toInt32EnforceRange(state, value);
case IntegerConversionConfiguration::Clamp:
return toInt32Clamp(state, value);
}
return value.toInt32(&state);
}
};
template<> struct JSConverter<IDLLong> {
using Type = typename IDLLong::ImplementationType;
static constexpr bool needsState = false;
static constexpr bool needsGlobalObject = false;
static JSC::JSValue convert(Type value)
{
return JSC::jsNumber(value);
}
};
template<> struct Converter<IDLUnsignedLong> : DefaultConverter<IDLUnsignedLong> {
static uint32_t convert(JSC::ExecState& state, JSC::JSValue value, IntegerConversionConfiguration configuration = IntegerConversionConfiguration::Normal)
{
switch (configuration) {
case IntegerConversionConfiguration::Normal:
break;
case IntegerConversionConfiguration::EnforceRange:
return toUInt32EnforceRange(state, value);
case IntegerConversionConfiguration::Clamp:
return toUInt32Clamp(state, value);
}
return value.toUInt32(&state);
}
};
template<> struct JSConverter<IDLUnsignedLong> {
using Type = typename IDLUnsignedLong::ImplementationType;
static constexpr bool needsState = false;
static constexpr bool needsGlobalObject = false;
static JSC::JSValue convert(Type value)
{
return JSC::jsNumber(value);
}
};
template<> struct Converter<IDLLongLong> : DefaultConverter<IDLLongLong> {
static int64_t convert(JSC::ExecState& state, JSC::JSValue value, IntegerConversionConfiguration configuration = IntegerConversionConfiguration::Normal)
{
if (value.isInt32())
return value.asInt32();
switch (configuration) {
case IntegerConversionConfiguration::Normal:
break;
case IntegerConversionConfiguration::EnforceRange:
return toInt64EnforceRange(state, value);
case IntegerConversionConfiguration::Clamp:
return toInt64Clamp(state, value);
}
return toInt64(state, value);
}
};
template<> struct JSConverter<IDLLongLong> {
using Type = typename IDLLongLong::ImplementationType;
static constexpr bool needsState = false;
static constexpr bool needsGlobalObject = false;
static JSC::JSValue convert(Type value)
{
return JSC::jsNumber(value);
}
};
template<> struct Converter<IDLUnsignedLongLong> : DefaultConverter<IDLUnsignedLongLong> {
static uint64_t convert(JSC::ExecState& state, JSC::JSValue value, IntegerConversionConfiguration configuration = IntegerConversionConfiguration::Normal)
{
if (value.isUInt32())
return value.asUInt32();
switch (configuration) {
case IntegerConversionConfiguration::Normal:
break;
case IntegerConversionConfiguration::EnforceRange:
return toUInt64EnforceRange(state, value);
case IntegerConversionConfiguration::Clamp:
return toUInt64Clamp(state, value);
}
return toUInt64(state, value);
}
};
template<> struct JSConverter<IDLUnsignedLongLong> {
using Type = typename IDLUnsignedLongLong::ImplementationType;
static constexpr bool needsState = false;
static constexpr bool needsGlobalObject = false;
static JSC::JSValue convert(Type value)
{
return JSC::jsNumber(value);
}
};
template<> struct Converter<IDLFloat> : DefaultConverter<IDLFloat> {
static float convert(JSC::ExecState& state, JSC::JSValue value)
{
JSC::VM& vm = state.vm();
auto scope = DECLARE_THROW_SCOPE(vm);
double number = value.toNumber(&state);
if (UNLIKELY(!std::isfinite(number)))
throwNonFiniteTypeError(state, scope);
return static_cast<float>(number);
}
};
template<> struct JSConverter<IDLFloat> {
using Type = typename IDLFloat::ImplementationType;
static constexpr bool needsState = false;
static constexpr bool needsGlobalObject = false;
static JSC::JSValue convert(Type value)
{
return JSC::jsNumber(value);
}
};
template<> struct Converter<IDLUnrestrictedFloat> : DefaultConverter<IDLUnrestrictedFloat> {
static float convert(JSC::ExecState& state, JSC::JSValue value)
{
return static_cast<float>(value.toNumber(&state));
}
};
template<> struct JSConverter<IDLUnrestrictedFloat> {
using Type = typename IDLUnrestrictedFloat::ImplementationType;
static constexpr bool needsState = false;
static constexpr bool needsGlobalObject = false;
static JSC::JSValue convert(Type value)
{
return JSC::jsNumber(value);
}
};
template<> struct Converter<IDLDouble> : DefaultConverter<IDLDouble> {
static double convert(JSC::ExecState& state, JSC::JSValue value)
{
JSC::VM& vm = state.vm();
auto scope = DECLARE_THROW_SCOPE(vm);
double number = value.toNumber(&state);
if (UNLIKELY(!std::isfinite(number)))
throwNonFiniteTypeError(state, scope);
return number;
}
};
template<> struct JSConverter<IDLDouble> {
using Type = typename IDLDouble::ImplementationType;
static constexpr bool needsState = false;
static constexpr bool needsGlobalObject = false;
static JSC::JSValue convert(Type value)
{
return JSC::jsNumber(value);
}
};
template<> struct Converter<IDLUnrestrictedDouble> : DefaultConverter<IDLUnrestrictedDouble> {
static double convert(JSC::ExecState& state, JSC::JSValue value)
{
return value.toNumber(&state);
}
};
template<> struct JSConverter<IDLUnrestrictedDouble> {
using Type = typename IDLUnrestrictedDouble::ImplementationType;
static constexpr bool needsState = false;
static constexpr bool needsGlobalObject = false;
static JSC::JSValue convert(Type value)
{
return JSC::jsNumber(value);
}
static JSC::JSValue convert(MediaTime value)
{
return JSC::jsNumber(value.toDouble());
}
};
template<> struct Converter<IDLDOMString> : DefaultConverter<IDLDOMString> {
static String convert(JSC::ExecState& state, JSC::JSValue value, StringConversionConfiguration configuration = StringConversionConfiguration::Normal)
{
if (configuration == StringConversionConfiguration::TreatNullAsEmptyString && value.isNull())
return emptyString();
return value.toWTFString(&state);
}
};
template<> struct JSConverter<IDLDOMString> {
static constexpr bool needsState = true;
static constexpr bool needsGlobalObject = false;
static JSC::JSValue convert(JSC::ExecState& state, const String& value)
{
return JSC::jsStringWithCache(&state, value);
}
};
template<> struct Converter<IDLByteString> : DefaultConverter<IDLByteString> {
static String convert(JSC::ExecState& state, JSC::JSValue value, StringConversionConfiguration configuration = StringConversionConfiguration::Normal)
{
if (configuration == StringConversionConfiguration::TreatNullAsEmptyString && value.isNull())
return emptyString();
return valueToByteString(state, value);
}
};
template<> struct JSConverter<IDLByteString> {
static constexpr bool needsState = true;
static constexpr bool needsGlobalObject = false;
static JSC::JSValue convert(JSC::ExecState& state, const String& value)
{
return JSC::jsStringWithCache(&state, value);
}
};
template<> struct Converter<IDLUSVString> : DefaultConverter<IDLUSVString> {
static String convert(JSC::ExecState& state, JSC::JSValue value, StringConversionConfiguration configuration = StringConversionConfiguration::Normal)
{
if (configuration == StringConversionConfiguration::TreatNullAsEmptyString && value.isNull())
return emptyString();
return valueToUSVString(state, value);
}
};
template<> struct JSConverter<IDLUSVString> {
static constexpr bool needsState = true;
static constexpr bool needsGlobalObject = false;
static JSC::JSValue convert(JSC::ExecState& state, const String& value)
{
return JSC::jsStringWithCache(&state, value);
}
};
template<> struct Converter<IDLObject> : DefaultConverter<IDLObject> {
template<typename ExceptionThrower = DefaultExceptionThrower>
static JSC::Strong<JSC::JSObject> convert(JSC::ExecState& state, JSC::JSValue value, ExceptionThrower&& exceptionThrower = ExceptionThrower())
{
JSC::VM& vm = state.vm();
auto scope = DECLARE_THROW_SCOPE(vm);
if (!value.isObject()) {
exceptionThrower(state, scope);
return { };
}
return { vm, JSC::asObject(value) };
}
};
namespace Detail {
template<typename IDLType>
struct ArrayConverterBase;
template<typename IDLType>
struct ArrayConverterBase {
using ReturnType = Vector<typename IDLType::ImplementationType>;
};
template<typename T>
struct ArrayConverterBase<IDLInterface<T>> {
using ReturnType = Vector<RefPtr<T>>;
};
template<typename IDLType>
struct ArrayConverter : ArrayConverterBase<IDLType> {
using ReturnType = typename ArrayConverterBase<IDLType>::ReturnType;
static ReturnType convert(JSC::ExecState& state, JSC::JSValue value)
{
auto& vm = state.vm();
auto scope = DECLARE_THROW_SCOPE(vm);
if (!value.isObject()) {
throwSequenceTypeError(state, scope);
return { };
}
ReturnType result;
forEachInIterable(&state, value, [&result](JSC::VM& vm, JSC::ExecState* state, JSC::JSValue jsValue) {
auto scope = DECLARE_THROW_SCOPE(vm);
auto convertedValue = Converter<IDLType>::convert(*state, jsValue);
if (UNLIKELY(scope.exception()))
return;
result.append(WTFMove(convertedValue));
});
return result;
}
};
}
template<typename T> struct Converter<IDLSequence<T>> : DefaultConverter<IDLSequence<T>> {
using ReturnType = typename Detail::ArrayConverter<T>::ReturnType;
static ReturnType convert(JSC::ExecState& state, JSC::JSValue value)
{
return Detail::ArrayConverter<T>::convert(state, value);
}
};
template<typename T> struct JSConverter<IDLSequence<T>> {
static constexpr bool needsState = true;
static constexpr bool needsGlobalObject = true;
template<typename U, size_t inlineCapacity>
static JSC::JSValue convert(JSC::ExecState& exec, JSDOMGlobalObject& globalObject, const Vector<U, inlineCapacity>& vector)
{
JSC::MarkedArgumentBuffer list;
for (auto& element : vector)
list.append(toJS<T>(exec, globalObject, element));
return JSC::constructArray(&exec, nullptr, &globalObject, list);
}
};
template<typename T> struct Converter<IDLFrozenArray<T>> : DefaultConverter<IDLFrozenArray<T>> {
using ReturnType = typename Detail::ArrayConverter<T>::ReturnType;
static ReturnType convert(JSC::ExecState& state, JSC::JSValue value)
{
return Detail::ArrayConverter<T>::convert(state, value);
}
};
template<typename T> struct JSConverter<IDLFrozenArray<T>> {
static constexpr bool needsState = true;
static constexpr bool needsGlobalObject = true;
template<typename U, size_t inlineCapacity>
static JSC::JSValue convert(JSC::ExecState& exec, JSDOMGlobalObject& globalObject, const Vector<U, inlineCapacity>& vector)
{
JSC::MarkedArgumentBuffer list;
for (auto& element : vector)
list.append(toJS<T>(exec, globalObject, element));
auto* array = JSC::constructArray(&exec, nullptr, &globalObject, list);
return JSC::objectConstructorFreeze(&exec, array);
}
};
namespace Detail {
template<typename IDLStringType>
struct IdentifierConverter;
template<> struct IdentifierConverter<IDLDOMString> {
static String convert(JSC::ExecState&, const JSC::Identifier& identifier)
{
return identifier.string();
}
};
template<> struct IdentifierConverter<IDLByteString> {
static String convert(JSC::ExecState& state, const JSC::Identifier& identifier)
{
return identifierToByteString(state, identifier);
}
};
template<> struct IdentifierConverter<IDLUSVString> {
static String convert(JSC::ExecState& state, const JSC::Identifier& identifier)
{
return identifierToUSVString(state, identifier);
}
};
}
template<typename K, typename V> struct Converter<IDLRecord<K, V>> : DefaultConverter<IDLRecord<K, V>> {
using ReturnType = typename IDLRecord<K, V>::ImplementationType;
using KeyType = typename K::ImplementationType;
using ValueType = typename V::ImplementationType;
static ReturnType convert(JSC::ExecState& state, JSC::JSValue value)
{
auto& vm = state.vm();
auto scope = DECLARE_THROW_SCOPE(vm);
if (value.isUndefinedOrNull())
return { };
if (!value.isObject()) {
throwTypeError(&state, scope);
return { };
}
JSC::JSObject* object = JSC::asObject(value);
ReturnType result;
JSC::PropertyNameArray keys(&vm, JSC::PropertyNameMode::Strings);
object->getOwnPropertyNames(object, &state, keys, JSC::EnumerationMode());
RETURN_IF_EXCEPTION(scope, { });
for (auto& key : keys) {
JSC::PropertyDescriptor descriptor;
bool didGetDescriptor = object->getOwnPropertyDescriptor(&state, key, descriptor);
RETURN_IF_EXCEPTION(scope, { });
if (!didGetDescriptor)
continue;
if (!descriptor.value().isUndefined() && descriptor.enumerable()) {
auto typedKey = Detail::IdentifierConverter<K>::convert(state, key);
auto subValue = object->get(&state, key);
RETURN_IF_EXCEPTION(scope, { });
auto typedValue = Converter<V>::convert(state, subValue);
RETURN_IF_EXCEPTION(scope, { });
result.set(typedKey, typedValue);
}
}
return result;
}
};
template<typename K, typename V> struct JSConverter<IDLRecord<K, V>> {
static constexpr bool needsState = true;
static constexpr bool needsGlobalObject = true;
template<typename ValueType>
static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject& globalObject, const HashMap<String, ValueType>& map)
{
auto& vm = state.vm();
auto result = constructEmptyObject(&state);
for (const auto& keyValuePair : map) {
auto esValue = toJS<V>(state, globalObject, keyValuePair.value);
bool created = result->putDirect(vm, JSC::Identifier::fromString(&vm, keyValuePair.key), esValue);
ASSERT_UNUSED(created, created);
}
return result;
}
};
template<typename T> struct Converter<IDLDictionary<T>> : DefaultConverter<IDLDictionary<T>> {
using ReturnType = T;
static ReturnType convert(JSC::ExecState& state, JSC::JSValue value)
{
return convertDictionary<T>(state, value);
}
};
template<typename T> struct JSConverter<IDLDictionary<T>> {
static constexpr bool needsState = true;
static constexpr bool needsGlobalObject = true;
static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject& globalObject, const T& dictionary)
{
return convertDictionaryToJS(state, globalObject, dictionary);
}
};
template<typename T> struct Converter<IDLEnumeration<T>> : DefaultConverter<IDLEnumeration<T>> {
static T convert(JSC::ExecState& state, JSC::JSValue value)
{
return convertEnumeration<T>(state, value);
}
};
template<typename T> struct JSConverter<IDLEnumeration<T>> {
static constexpr bool needsState = true;
static constexpr bool needsGlobalObject = false;
static JSC::JSValue convert(JSC::ExecState& exec, T value)
{
return convertEnumerationToJS(exec, value);
}
};
template<typename T> struct Converter<IDLCallbackFunction<T>> : DefaultConverter<IDLCallbackFunction<T>> {
template<typename ExceptionThrower = DefaultExceptionThrower>
static RefPtr<T> convert(JSC::ExecState& state, JSC::JSValue value, JSDOMGlobalObject& globalObject, ExceptionThrower&& exceptionThrower = ExceptionThrower())
{
JSC::VM& vm = state.vm();
auto scope = DECLARE_THROW_SCOPE(vm);
if (!value.isFunction()) {
exceptionThrower(state, scope);
return nullptr;
}
return T::create(JSC::asObject(value), &globalObject);
}
};
template<typename T> struct JSConverter<IDLCallbackFunction<T>> {
static constexpr bool needsState = false;
static constexpr bool needsGlobalObject = false;
template <typename U>
static JSC::JSValue convert(const U& value)
{
return toJS(Detail::getPtrOrRef(value));
}
template<typename U>
static JSC::JSValue convertNewlyCreated(U&& value)
{
return toJSNewlyCreated(std::forward<U>(value));
}
};
template<typename T> struct Converter<IDLCallbackInterface<T>> : DefaultConverter<IDLCallbackInterface<T>> {
template<typename ExceptionThrower = DefaultExceptionThrower>
static RefPtr<T> convert(JSC::ExecState& state, JSC::JSValue value, JSDOMGlobalObject& globalObject, ExceptionThrower&& exceptionThrower = ExceptionThrower())
{
JSC::VM& vm = state.vm();
auto scope = DECLARE_THROW_SCOPE(vm);
if (!value.isObject()) {
exceptionThrower(state, scope);
return nullptr;
}
return T::create(JSC::asObject(value), &globalObject);
}
};
template<typename T> struct JSConverter<IDLCallbackInterface<T>> {
static constexpr bool needsState = false;
static constexpr bool needsGlobalObject = false;
template <typename U>
static JSC::JSValue convert(const U& value)
{
return toJS(Detail::getPtrOrRef(value));
}
template<typename U>
static JSC::JSValue convertNewlyCreated(U&& value)
{
return toJSNewlyCreated(std::forward<U>(value));
}
};
template<typename ReturnType, typename T, bool enabled>
struct ConditionalConverter;
template<typename ReturnType, typename T>
struct ConditionalConverter<ReturnType, T, true> {
static std::optional<ReturnType> convert(JSC::ExecState& state, JSC::JSValue value)
{
return ReturnType(Converter<T>::convert(state, value));
}
};
template<typename ReturnType, typename T>
struct ConditionalConverter<ReturnType, T, false> {
static std::optional<ReturnType> convert(JSC::ExecState&, JSC::JSValue)
{
return std::nullopt;
}
};
namespace Detail {
template<typename List, bool condition>
struct ConditionalFront;
template<typename List>
struct ConditionalFront<List, true>
{
using type = brigand::front<List>;
};
template<typename List>
struct ConditionalFront<List, false>
{
using type = void;
};
}
template<typename List, bool condition>
using ConditionalFront = typename Detail::ConditionalFront<List, condition>::type;
template<typename... T> struct Converter<IDLUnion<T...>> : DefaultConverter<IDLUnion<T...>> {
using Type = IDLUnion<T...>;
using TypeList = typename Type::TypeList;
using ReturnType = typename Type::ImplementationType;
using NumericTypeList = brigand::filter<TypeList, IsIDLNumber<brigand::_1>>;
static constexpr size_t numberOfNumericTypes = brigand::size<NumericTypeList>::value;
static_assert(numberOfNumericTypes == 0 || numberOfNumericTypes == 1, "There can be 0 or 1 numeric types in an IDLUnion.");
using NumericType = ConditionalFront<NumericTypeList, numberOfNumericTypes != 0>;
using StringTypeList = brigand::filter<TypeList, std::is_base_of<IDLString, brigand::_1>>;
static constexpr size_t numberOfStringTypes = brigand::size<StringTypeList>::value;
static_assert(numberOfStringTypes == 0 || numberOfStringTypes == 1, "There can be 0 or 1 string types in an IDLUnion.");
using StringType = ConditionalFront<StringTypeList, numberOfStringTypes != 0>;
using SequenceTypeList = brigand::filter<TypeList, IsIDLSequence<brigand::_1>>;
static constexpr size_t numberOfSequenceTypes = brigand::size<SequenceTypeList>::value;
static_assert(numberOfSequenceTypes == 0 || numberOfSequenceTypes == 1, "There can be 0 or 1 sequence types in an IDLUnion.");
using SequenceType = ConditionalFront<SequenceTypeList, numberOfSequenceTypes != 0>;
using FrozenArrayTypeList = brigand::filter<TypeList, IsIDLFrozenArray<brigand::_1>>;
static constexpr size_t numberOfFrozenArrayTypes = brigand::size<FrozenArrayTypeList>::value;
static_assert(numberOfFrozenArrayTypes == 0 || numberOfFrozenArrayTypes == 1, "There can be 0 or 1 FrozenArray types in an IDLUnion.");
using FrozenArrayType = ConditionalFront<FrozenArrayTypeList, numberOfFrozenArrayTypes != 0>;
using DictionaryTypeList = brigand::filter<TypeList, IsIDLDictionary<brigand::_1>>;
static constexpr size_t numberOfDictionaryTypes = brigand::size<DictionaryTypeList>::value;
static_assert(numberOfDictionaryTypes == 0 || numberOfDictionaryTypes == 1, "There can be 0 or 1 dictionary types in an IDLUnion.");
static constexpr bool hasDictionaryType = numberOfDictionaryTypes != 0;
using DictionaryType = ConditionalFront<DictionaryTypeList, hasDictionaryType>;
using RecordTypeList = brigand::filter<TypeList, IsIDLRecord<brigand::_1>>;
static constexpr size_t numberOfRecordTypes = brigand::size<RecordTypeList>::value;
static_assert(numberOfRecordTypes == 0 || numberOfRecordTypes == 1, "There can be 0 or 1 record types in an IDLUnion.");
static constexpr bool hasRecordType = numberOfRecordTypes != 0;
using RecordType = ConditionalFront<RecordTypeList, hasRecordType>;
static constexpr bool hasObjectType = (numberOfSequenceTypes + numberOfFrozenArrayTypes + numberOfDictionaryTypes + numberOfRecordTypes) > 0;
using InterfaceTypeList = brigand::filter<TypeList, IsIDLInterface<brigand::_1>>;
static ReturnType convert(JSC::ExecState& state, JSC::JSValue value)
{
auto scope = DECLARE_THROW_SCOPE(state.vm());
constexpr bool hasNullType = brigand::any<TypeList, std::is_same<IDLNull, brigand::_1>>::value;
if (hasNullType) {
if (value.isUndefinedOrNull())
return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, IDLNull, hasNullType>::convert(state, value).value());
}
if (hasDictionaryType || hasRecordType) {
if (value.isUndefinedOrNull()) {
if (hasDictionaryType)
return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, DictionaryType, hasDictionaryType>::convert(state, value).value());
if (hasRecordType)
return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, RecordType, hasRecordType>::convert(state, value).value());
}
}
if (brigand::any<TypeList, IsIDLInterface<brigand::_1>>::value) {
std::optional<ReturnType> returnValue;
brigand::for_each<InterfaceTypeList>([&](auto&& type) {
if (returnValue)
return;
using Type = typename WTF::RemoveCVAndReference<decltype(type)>::type::type;
using ImplementationType = typename Type::ImplementationType;
using RawType = typename Type::RawType;
using WrapperType = typename JSDOMWrapperConverterTraits<RawType>::WrapperClass;
auto castedValue = WrapperType::toWrapped(value);
if (!castedValue)
return;
returnValue = ReturnType(ImplementationType(castedValue));
});
if (returnValue)
return WTFMove(returnValue.value());
}
if (hasObjectType) {
if (value.isCell()) {
JSC::JSCell* cell = value.asCell();
if (cell->isObject()) {
constexpr bool hasSequenceType = numberOfSequenceTypes != 0;
if (hasSequenceType) {
bool hasIterator = hasIteratorMethod(state, value);
RETURN_IF_EXCEPTION(scope, ReturnType());
if (hasIterator)
return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, SequenceType, hasSequenceType>::convert(state, value).value());
}
constexpr bool hasFrozenArrayType = numberOfFrozenArrayTypes != 0;
if (hasFrozenArrayType) {
bool hasIterator = hasIteratorMethod(state, value);
RETURN_IF_EXCEPTION(scope, ReturnType());
if (hasIterator)
return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, FrozenArrayType, hasFrozenArrayType>::convert(state, value).value());
}
if (hasDictionaryType)
return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, DictionaryType, hasDictionaryType>::convert(state, value).value());
if (hasRecordType)
return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, RecordType, hasRecordType>::convert(state, value).value());
}
}
}
constexpr bool hasBooleanType = brigand::any<TypeList, std::is_same<IDLBoolean, brigand::_1>>::value;
if (hasBooleanType) {
if (value.isBoolean())
return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, IDLBoolean, hasBooleanType>::convert(state, value).value());
}
constexpr bool hasNumericType = brigand::size<NumericTypeList>::value != 0;
if (hasNumericType) {
if (value.isNumber())
return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, NumericType, hasNumericType>::convert(state, value).value());
}
constexpr bool hasStringType = brigand::size<StringTypeList>::value != 0;
if (hasStringType)
return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, StringType, hasStringType>::convert(state, value).value());
if (hasNumericType)
return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, NumericType, hasNumericType>::convert(state, value).value());
if (hasBooleanType)
return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, IDLBoolean, hasBooleanType>::convert(state, value).value());
throwTypeError(&state, scope);
return ReturnType();
}
};
template<typename... T> struct JSConverter<IDLUnion<T...>> {
using Type = IDLUnion<T...>;
using TypeList = typename Type::TypeList;
using ImplementationType = typename Type::ImplementationType;
static constexpr bool needsState = true;
static constexpr bool needsGlobalObject = true;
using Sequence = brigand::make_sequence<brigand::ptrdiff_t<0>, WTF::variant_size<ImplementationType>::value>;
static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject& globalObject, const ImplementationType& variant)
{
auto index = variant.index();
std::optional<JSC::JSValue> returnValue;
brigand::for_each<Sequence>([&](auto&& type) {
using I = typename WTF::RemoveCVAndReference<decltype(type)>::type::type;
if (I::value == index) {
ASSERT(!returnValue);
returnValue = toJS<brigand::at<TypeList, I>>(state, globalObject, WTF::get<I::value>(variant));
}
});
ASSERT(returnValue);
return returnValue.value();
}
};
template<> struct Converter<IDLDate> : DefaultConverter<IDLDate> {
static double convert(JSC::ExecState& state, JSC::JSValue value)
{
return valueToDate(&state, value);
}
};
template<> struct JSConverter<IDLDate> {
static constexpr bool needsState = true;
static constexpr bool needsGlobalObject = false;
static JSC::JSValue convert(JSC::ExecState& state, double value)
{
return jsDate(&state, value);
}
};
template<typename T> struct Converter<IDLSerializedScriptValue<T>> : DefaultConverter<IDLSerializedScriptValue<T>> {
static RefPtr<T> convert(JSC::ExecState& state, JSC::JSValue value)
{
return T::create(state, value);
}
};
template<typename T> struct JSConverter<IDLSerializedScriptValue<T>> {
static constexpr bool needsState = true;
static constexpr bool needsGlobalObject = true;
static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject& globalObject, RefPtr<T> value)
{
return value ? value->deserialize(state, &globalObject) : JSC::jsNull();
}
};
template<typename T> struct Converter<IDLEventListener<T>> : DefaultConverter<IDLEventListener<T>> {
using ReturnType = RefPtr<T>;
static ReturnType convert(JSC::ExecState& state, JSC::JSValue value, JSC::JSObject& thisObject)
{
auto scope = DECLARE_THROW_SCOPE(state.vm());
auto listener = T::create(value, thisObject, false, currentWorld(&state));
if (!listener)
throwTypeError(&state, scope);
return listener;
}
};
template<typename T> struct Converter<IDLXPathNSResolver<T>> : DefaultConverter<IDLXPathNSResolver<T>> {
using ReturnType = RefPtr<T>;
using WrapperType = typename JSDOMWrapperConverterTraits<T>::WrapperClass;
template<typename ExceptionThrower = DefaultExceptionThrower>
static ReturnType convert(JSC::ExecState& state, JSC::JSValue value, ExceptionThrower&& exceptionThrower = ExceptionThrower())
{
JSC::VM& vm = state.vm();
auto scope = DECLARE_THROW_SCOPE(vm);
ReturnType object = WrapperType::toWrapped(state, value);
if (UNLIKELY(!object))
exceptionThrower(state, scope);
return object;
}
};
template<typename T> struct JSConverter<IDLXPathNSResolver<T>> {
static constexpr bool needsState = true;
static constexpr bool needsGlobalObject = true;
template <typename U>
static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject& globalObject, const U& value)
{
return toJS(&state, &globalObject, Detail::getPtrOrRef(value));
}
template<typename U>
static JSC::JSValue convertNewlyCreated(JSC::ExecState& state, JSDOMGlobalObject& globalObject, U&& value)
{
return toJSNewlyCreated(&state, &globalObject, std::forward<U>(value));
}
};
template<> struct Converter<IDLJSON> : DefaultConverter<IDLJSON> {
static String convert(JSC::ExecState& state, JSC::JSValue value)
{
return JSC::JSONStringify(&state, value, 0);
}
};
template<> struct JSConverter<IDLJSON> {
static constexpr bool needsState = true;
static constexpr bool needsGlobalObject = false;
static JSC::JSValue convert(JSC::ExecState& state, const String& value)
{
return JSC::JSONParse(&state, value);
}
};
namespace Detail {
template<typename IDLType>
struct VariadicConverterBase;
template<typename IDLType>
struct VariadicConverterBase {
using Item = typename IDLType::ImplementationType;
static std::optional<Item> convert(JSC::ExecState& state, JSC::JSValue value)
{
auto& vm = state.vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto result = Converter<IDLType>::convert(state, value);
RETURN_IF_EXCEPTION(scope, std::nullopt);
return WTFMove(result);
}
};
template<typename T>
struct VariadicConverterBase<IDLInterface<T>> {
using Item = std::reference_wrapper<T>;
static std::optional<Item> convert(JSC::ExecState& state, JSC::JSValue value)
{
auto* result = Converter<IDLInterface<T>>::convert(state, value);
if (!result)
return std::nullopt;
return std::optional<Item>(*result);
}
};
template<typename IDLType>
struct VariadicConverter : VariadicConverterBase<IDLType> {
using Item = typename VariadicConverterBase<IDLType>::Item;
using Container = Vector<Item>;
struct Result {
size_t argumentIndex;
std::optional<Container> arguments;
};
};
}
template<typename IDLType> typename Detail::VariadicConverter<IDLType>::Result convertVariadicArguments(JSC::ExecState& state, size_t startIndex)
{
size_t length = state.argumentCount();
if (startIndex > length)
return { 0, std::nullopt };
typename Detail::VariadicConverter<IDLType>::Container result;
result.reserveInitialCapacity(length - startIndex);
for (size_t i = startIndex; i < length; ++i) {
auto value = Detail::VariadicConverter<IDLType>::convert(state, state.uncheckedArgument(i));
if (!value)
return { i, std::nullopt };
result.uncheckedAppend(WTFMove(*value));
}
return { length, WTFMove(result) };
}
}