blob: f01f9c4c5421763f659f386d5397ad29433086e8 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SKY_ENGINE_TONIC_DART_CONVERTER_H_
#define SKY_ENGINE_TONIC_DART_CONVERTER_H_
#include <string>
#include "sky/engine/tonic/dart_state.h"
#include "sky/engine/tonic/dart_string.h"
#include "sky/engine/tonic/dart_string_cache.h"
#include "sky/engine/tonic/dart_value.h"
#include "sky/engine/wtf/text/StringUTF8Adaptor.h"
#include "sky/engine/wtf/text/WTFString.h"
namespace blink {
// DartConvert converts types back and forth from Sky to Dart. The template
// parameter |T| determines what kind of type conversion to perform.
template <typename T, typename Enable = void>
struct DartConverter {
};
// This is to work around the fact that typedefs do not create new types. If you
// have a typedef, and want it to use a different converter, specialize this
// template and override the types here.
// Ex:
// typedef int ColorType; // Want to use a different converter.
// class ColorConverterType {}; // Dummy type.
// template<> struct DartConvertType<ColorConverterType> {
// using ConverterType = ColorConverterType;
// using ValueType = ColorType;
// };
template <typename T>
struct DartConverterTypes {
using ConverterType = T;
using ValueType = T;
};
////////////////////////////////////////////////////////////////////////////////
// Boolean
template <>
struct DartConverter<bool> {
static Dart_Handle ToDart(bool val) { return Dart_NewBoolean(val); }
static void SetReturnValue(Dart_NativeArguments args, bool val) {
Dart_SetBooleanReturnValue(args, val);
}
static bool FromDart(Dart_Handle handle) {
bool result = 0;
Dart_BooleanValue(handle, &result);
return result;
}
static bool FromArguments(Dart_NativeArguments args,
int index,
Dart_Handle& exception) {
bool result = false;
Dart_GetNativeBooleanArgument(args, index, &result);
return result;
}
};
////////////////////////////////////////////////////////////////////////////////
// Numbers
template <typename T>
struct DartConverterInteger {
static Dart_Handle ToDart(T val) { return Dart_NewInteger(val); }
static void SetReturnValue(Dart_NativeArguments args, T val) {
Dart_SetIntegerReturnValue(args, val);
}
static T FromDart(Dart_Handle handle) {
int64_t result = 0;
Dart_IntegerToInt64(handle, &result);
return static_cast<T>(result);
}
static T FromArguments(Dart_NativeArguments args,
int index,
Dart_Handle& exception) {
int64_t result = 0;
Dart_GetNativeIntegerArgument(args, index, &result);
return static_cast<T>(result);
}
};
template <>
struct DartConverter<int> : public DartConverterInteger<int> {};
template <>
struct DartConverter<unsigned> : public DartConverterInteger<unsigned> {};
template <>
struct DartConverter<long long> : public DartConverterInteger<long long> {};
template <>
struct DartConverter<unsigned long long> {
static Dart_Handle ToDart(unsigned long long val) {
// FIXME: WebIDL unsigned long long is guaranteed to fit into 64-bit
// unsigned,
// so we need a dart API for constructing an integer from uint64_t.
DCHECK(val <= 0x7fffffffffffffffLL);
return Dart_NewInteger(static_cast<int64_t>(val));
}
static void SetReturnValue(Dart_NativeArguments args,
unsigned long long val) {
DCHECK(val <= 0x7fffffffffffffffLL);
Dart_SetIntegerReturnValue(args, val);
}
static unsigned long long FromDart(Dart_Handle handle) {
int64_t result = 0;
Dart_IntegerToInt64(handle, &result);
return result;
}
static unsigned long long FromArguments(Dart_NativeArguments args,
int index,
Dart_Handle& exception) {
int64_t result = 0;
Dart_GetNativeIntegerArgument(args, index, &result);
return result;
}
};
template <typename T>
struct DartConverterFloatingPoint {
static Dart_Handle ToDart(T val) { return Dart_NewDouble(val); }
static void SetReturnValue(Dart_NativeArguments args, T val) {
Dart_SetDoubleReturnValue(args, val);
}
static T FromDart(Dart_Handle handle) {
double result = 0;
Dart_DoubleValue(handle, &result);
return result;
}
static T FromArguments(Dart_NativeArguments args,
int index,
Dart_Handle& exception) {
double result = 0;
Dart_GetNativeDoubleArgument(args, index, &result);
return result;
}
};
template <>
struct DartConverter<float> : public DartConverterFloatingPoint<float> {};
template <>
struct DartConverter<double> : public DartConverterFloatingPoint<double> {};
////////////////////////////////////////////////////////////////////////////////
// Enums
template <typename T>
struct DartConverterEnum {
static T FromArguments(Dart_NativeArguments args,
int index,
Dart_Handle& exception) {
return FromDart(Dart_GetNativeArgument(args, index));
}
static T FromDart(Dart_Handle handle) {
Dart_Handle index_handle =
Dart_GetField(handle, DartState::Current()->index_handle());
uint64_t enum_index = 0;
Dart_IntegerToUint64(index_handle, &enum_index);
return static_cast<T>(enum_index);
}
};
////////////////////////////////////////////////////////////////////////////////
// Strings
template <>
struct DartConverter<String> {
static Dart_Handle ToDart(DartState* state, const String& val) {
if (val.isEmpty())
return Dart_EmptyString();
return Dart_HandleFromWeakPersistent(state->string_cache().Get(val.impl()));
}
static void SetReturnValue(Dart_NativeArguments args,
const String& val,
bool auto_scope = true) {
// TODO(abarth): What should we do with auto_scope?
if (val.isEmpty()) {
Dart_SetReturnValue(args, Dart_EmptyString());
return;
}
DartState* state = DartState::Current();
Dart_SetWeakHandleReturnValue(args, state->string_cache().Get(val.impl()));
}
static void SetReturnValueWithNullCheck(Dart_NativeArguments args,
const String& val,
bool auto_scope = true) {
if (val.isNull())
Dart_SetReturnValue(args, Dart_Null());
else
SetReturnValue(args, val, auto_scope);
}
static String FromDart(Dart_Handle handle) {
intptr_t char_size = 0;
intptr_t length = 0;
void* peer = nullptr;
Dart_Handle result =
Dart_StringGetProperties(handle, &char_size, &length, &peer);
if (peer)
return String(static_cast<StringImpl*>(peer));
if (Dart_IsError(result))
return String();
return ExternalizeDartString(handle);
}
static String FromArguments(Dart_NativeArguments args,
int index,
Dart_Handle& exception,
bool auto_scope = true) {
// TODO(abarth): What should we do with auto_scope?
void* peer = nullptr;
Dart_Handle handle = Dart_GetNativeStringArgument(args, index, &peer);
if (peer)
return reinterpret_cast<StringImpl*>(peer);
if (Dart_IsError(handle))
return String();
return ExternalizeDartString(handle);
}
static String FromArgumentsWithNullCheck(Dart_NativeArguments args,
int index,
Dart_Handle& exception,
bool auto_scope = true) {
// TODO(abarth): What should we do with auto_scope?
void* peer = nullptr;
Dart_Handle handle = Dart_GetNativeStringArgument(args, index, &peer);
if (peer)
return reinterpret_cast<StringImpl*>(peer);
if (Dart_IsError(handle) || Dart_IsNull(handle))
return String();
return ExternalizeDartString(handle);
}
};
template <>
struct DartConverter<AtomicString> {
static Dart_Handle ToDart(DartState* state, const AtomicString& val) {
return DartConverter<String>::ToDart(state, val.string());
}
};
////////////////////////////////////////////////////////////////////////////////
// Collections
template <typename T>
struct DartConverter<Vector<T>> {
using ValueType = typename DartConverterTypes<T>::ValueType;
using ConverterType = typename DartConverterTypes<T>::ConverterType;
static Dart_Handle ToDart(const Vector<ValueType>& val) {
Dart_Handle list = Dart_NewList(val.size());
if (Dart_IsError(list))
return list;
for (size_t i = 0; i < val.size(); i++) {
Dart_Handle result =
Dart_ListSetAt(list, i,
DartConverter<ConverterType>::ToDart(val[i]));
if (Dart_IsError(result))
return result;
}
return list;
}
static Vector<ValueType> FromDart(Dart_Handle handle) {
Vector<ValueType> result;
if (!Dart_IsList(handle))
return result;
intptr_t length = 0;
Dart_ListLength(handle, &length);
result.reserveCapacity(length);
for (intptr_t i = 0; i < length; ++i) {
Dart_Handle item = Dart_ListGetAt(handle, i);
DCHECK(!Dart_IsError(item));
DCHECK(item);
result.append(DartConverter<ConverterType>::FromDart(item));
}
return result;
}
static Vector<ValueType> FromArguments(Dart_NativeArguments args,
int index,
Dart_Handle& exception,
bool auto_scope = true) {
// TODO(abarth): What should we do with auto_scope?
return FromDart(Dart_GetNativeArgument(args, index));
}
};
////////////////////////////////////////////////////////////////////////////////
// DartValue
template <>
struct DartConverter<DartValue*> {
static Dart_Handle ToDart(DartState* state, DartValue* val) {
return val->dart_value();
}
static void SetReturnValue(Dart_NativeArguments args, DartValue* val) {
Dart_SetReturnValue(args, val->dart_value());
}
static PassRefPtr<DartValue> FromDart(Dart_Handle handle) {
return DartValue::Create(DartState::Current(), handle);
}
static PassRefPtr<DartValue> FromArguments(Dart_NativeArguments args,
int index,
Dart_Handle& exception,
bool auto_scope = true) {
// TODO(abarth): What should we do with auto_scope?
return FromDart(Dart_GetNativeArgument(args, index));
}
};
////////////////////////////////////////////////////////////////////////////////
// Convience wrappers for commonly used conversions
inline Dart_Handle StringToDart(DartState* state, const String& val) {
return DartConverter<String>::ToDart(state, val);
}
inline Dart_Handle StringToDart(DartState* state, const AtomicString& val) {
return DartConverter<AtomicString>::ToDart(state, val);
}
inline String StringFromDart(Dart_Handle handle) {
return DartConverter<String>::FromDart(handle);
}
////////////////////////////////////////////////////////////////////////////////
// Convience wrappers using type inference for ease of code generation
template <typename T>
inline Dart_Handle VectorToDart(const Vector<T>& val) {
return DartConverter<Vector<T>>::ToDart(val);
}
template<typename T>
Dart_Handle ToDart(const T& object) {
return DartConverter<T>::ToDart(object);
}
////////////////////////////////////////////////////////////////////////////////
// std::string support (slower, but more convienent for some clients)
inline Dart_Handle StdStringToDart(const std::string& val) {
return Dart_NewStringFromUTF8(reinterpret_cast<const uint8_t*>(val.data()),
val.length());
}
inline std::string StdStringFromDart(Dart_Handle handle) {
String string = StringFromDart(handle);
StringUTF8Adaptor utf8(string);
return std::string(utf8.data(), utf8.length());
}
// Alias Dart_NewStringFromCString for less typing.
inline Dart_Handle ToDart(const char* val) {
return Dart_NewStringFromCString(val);
}
} // namespace blink
#endif // SKY_ENGINE_TONIC_DART_CONVERTER_H_