JSDOMConvertRecord.h [plain text]
#pragma once
#include "IDLTypes.h"
#include "JSDOMConvertStrings.h"
#include "JSDOMGlobalObject.h"
#include <JavaScriptCore/ObjectConstructor.h>
namespace WebCore {
namespace Detail {
template<typename IDLStringType>
struct IdentifierConverter;
template<> struct IdentifierConverter<IDLDOMString> {
static String convert(JSC::JSGlobalObject&, const JSC::Identifier& identifier)
{
return identifier.string();
}
};
template<> struct IdentifierConverter<IDLByteString> {
static String convert(JSC::JSGlobalObject& lexicalGlobalObject, const JSC::Identifier& identifier)
{
return identifierToByteString(lexicalGlobalObject, identifier);
}
};
template<> struct IdentifierConverter<IDLUSVString> {
static String convert(JSC::JSGlobalObject& lexicalGlobalObject, const JSC::Identifier& identifier)
{
return identifierToUSVString(lexicalGlobalObject, 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::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value, JSDOMGlobalObject& globalObject)
{
return convertRecord<JSDOMGlobalObject&>(lexicalGlobalObject, value, globalObject);
}
static ReturnType convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value)
{
return convertRecord(lexicalGlobalObject, value);
}
private:
template<class...Args>
static ReturnType convertRecord(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value, Args ... args)
{
auto& vm = JSC::getVM(&lexicalGlobalObject);
auto scope = DECLARE_THROW_SCOPE(vm);
if (value.isUndefinedOrNull())
return { };
if (!value.isObject()) {
throwTypeError(&lexicalGlobalObject, scope);
return { };
}
JSC::JSObject* object = JSC::asObject(value);
ReturnType result;
JSC::PropertyNameArray keys(vm, JSC::PropertyNameMode::Strings, JSC::PrivateSymbolMode::Exclude);
object->methodTable(vm)->getOwnPropertyNames(object, &lexicalGlobalObject, keys, JSC::EnumerationMode(JSC::DontEnumPropertiesMode::Include));
RETURN_IF_EXCEPTION(scope, { });
for (auto& key : keys) {
JSC::PropertyDescriptor descriptor;
bool didGetDescriptor = object->getOwnPropertyDescriptor(&lexicalGlobalObject, key, descriptor);
RETURN_IF_EXCEPTION(scope, { });
if (didGetDescriptor && descriptor.enumerable()) {
auto typedKey = Detail::IdentifierConverter<K>::convert(lexicalGlobalObject, key);
RETURN_IF_EXCEPTION(scope, { });
auto subValue = object->get(&lexicalGlobalObject, key);
RETURN_IF_EXCEPTION(scope, { });
auto typedValue = Converter<V>::convert(lexicalGlobalObject, subValue, args...);
RETURN_IF_EXCEPTION(scope, { });
result.append({ 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 MapType>
static JSC::JSValue convert(JSC::JSGlobalObject& lexicalGlobalObject, JSDOMGlobalObject& globalObject, const MapType& map)
{
auto& vm = JSC::getVM(&lexicalGlobalObject);
auto result = constructEmptyObject(&lexicalGlobalObject, globalObject.objectPrototype());
for (const auto& keyValuePair : map) {
auto esValue = toJS<V>(lexicalGlobalObject, globalObject, keyValuePair.value);
bool created = result->putDirect(vm, JSC::Identifier::fromString(vm, keyValuePair.key), esValue);
ASSERT_UNUSED(created, created);
}
return result;
}
};
}