blob: b5673ea5a1ed5d95520b2c0d0098907705c8fe7a [file] [log] [blame]
// Copyright 2017 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef COBALT_SCRIPT_V8C_CONVERSION_HELPERS_H_
#define COBALT_SCRIPT_V8C_CONVERSION_HELPERS_H_
#include <cmath>
#include <limits>
#include <string>
#include <vector>
#include "base/logging.h"
#include "base/optional.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "cobalt/base/compiler.h"
#include "cobalt/base/enable_if.h"
#include "cobalt/base/token.h"
#include "cobalt/script/sequence.h"
#include "cobalt/script/v8c/algorithm_helpers.h"
#include "cobalt/script/v8c/helpers.h"
#include "cobalt/script/v8c/type_traits.h"
#include "cobalt/script/v8c/union_type_conversion_forward.h"
#include "cobalt/script/v8c/v8c_array_buffer.h"
#include "cobalt/script/v8c/v8c_array_buffer_view.h"
#include "cobalt/script/v8c/v8c_callback_interface_holder.h"
#include "cobalt/script/v8c/v8c_data_view.h"
#include "cobalt/script/v8c/v8c_global_environment.h"
#include "cobalt/script/v8c/v8c_typed_arrays.h"
#include "cobalt/script/v8c/v8c_user_object_holder.h"
#include "cobalt/script/v8c/v8c_value_handle.h"
#include "cobalt/script/value_handle.h"
#include "nb/memory_scope.h"
#include "v8/include/v8.h"
namespace cobalt {
namespace script {
namespace v8c {
// Flags that can be used as a bitmask for special conversion behaviour.
enum ConversionFlags {
kNoConversionFlags = 0,
kConversionFlagRestricted = 1 << 0,
kConversionFlagNullable = 1 << 1,
kConversionFlagTreatNullAsEmptyString = 1 << 2,
kConversionFlagTreatUndefinedAsEmptyString = 1 << 3,
kConversionFlagClamped = 1 << 4,
kConversionFlagObjectOnly = 1 << 5,
// Valid conversion flags for numeric values.
kConversionFlagsNumeric = kConversionFlagRestricted | kConversionFlagClamped,
// Valid conversion flags for string types.
kConversionFlagsString = kConversionFlagTreatNullAsEmptyString |
kConversionFlagTreatUndefinedAsEmptyString,
// Valid conversion flags for objects.
kConversionFlagsObject = kConversionFlagNullable,
// Valid conversion flags for ValueHandles.
kConversionFlagsValueHandle =
kConversionFlagObjectOnly | kConversionFlagNullable,
// Valid conversion flags for callback functions.
kConversionFlagsCallbackFunction = kConversionFlagNullable,
// Valid conversion flags for callback interfaces.
kConversionFlagsCallbackInterface = kConversionFlagNullable,
};
// std::string -> JSValue
inline void ToJSValue(v8::Isolate* isolate, const std::string& in_string,
v8::Local<v8::Value>* out_value) {
v8::MaybeLocal<v8::String> maybe_string = v8::String::NewFromUtf8(
isolate, in_string.data(), v8::NewStringType::kNormal, in_string.size());
v8::Local<v8::Value> string;
if (!maybe_string.ToLocal(&string)) {
*out_value = v8::Null(isolate);
return;
}
*out_value = string;
}
// JSValue -> std::string
void FromJSValue(v8::Isolate* isolate, v8::Local<v8::Value> value,
int conversion_flags, ExceptionState* exception_state,
std::string* out_string);
// std::vector<uint8_t> -> JSValue
// Note that this conversion is specifically for the Web IDL type ByteString.
// Ideally, conversion requests would be explicit in what type they wanted to
// convert to, however it is currently solely based on input type.
inline void ToJSValue(v8::Isolate* isolate, const std::vector<uint8_t>& in_data,
v8::Local<v8::Value>* out_value) {
v8::MaybeLocal<v8::String> maybe_string = v8::String::NewFromOneByte(
isolate, in_data.data(), v8::NewStringType::kNormal, in_data.size());
v8::Local<v8::Value> string;
if (!maybe_string.ToLocal(&string)) {
*out_value = v8::Null(isolate);
return;
}
*out_value = string;
}
// base::Token -> JSValue
inline void ToJSValue(v8::Isolate* isolate, const base::Token& token,
v8::Local<v8::Value>* out_value) {
ToJSValue(isolate, std::string(token.c_str()), out_value);
}
// bool -> JSValue
inline void ToJSValue(v8::Isolate* isolate, bool in_boolean,
v8::Local<v8::Value>* out_value) {
*out_value = v8::Boolean::New(isolate, in_boolean);
}
// JSValue -> bool
inline void FromJSValue(v8::Isolate* isolate, v8::Local<v8::Value> value,
int conversion_flags, ExceptionState* exception_state,
bool* out_boolean) {
DCHECK_EQ(conversion_flags, kNoConversionFlags)
<< "No conversion flags supported.";
DCHECK(out_boolean);
v8::MaybeLocal<v8::Boolean> maybe_boolean = value->ToBoolean(isolate);
v8::Local<v8::Boolean> boolean;
if (!maybe_boolean.ToLocal(&boolean)) {
// When these situations happen, there must be an error in the idl
// declaration.
DCHECK(false);
return;
}
*out_boolean = boolean->Value();
}
// signed integers <= 4 bytes -> JSValue
template <typename T>
inline void ToJSValue(
v8::Isolate* isolate, T in_number, v8::Local<v8::Value>* out_value,
typename base::enable_if<std::numeric_limits<T>::is_specialized &&
std::numeric_limits<T>::is_integer &&
std::numeric_limits<T>::is_signed &&
(sizeof(T) <= 4),
T>::type* = NULL) {
*out_value = v8::Integer::New(isolate, static_cast<int32_t>(in_number));
}
template <typename T>
inline const double UpperBound() {
return std::numeric_limits<T>::max();
}
template <typename T>
inline const double LowerBound() {
return std::numeric_limits<T>::min();
}
// The below specializations of UpperBound<T> and LowerBound<T> for 64
// bit integers use the (2^(53) - 1) and similar bounds specified in
// step 1 of ConvertToInt, see:
// https://heycam.github.io/webidl/#abstract-opdef-converttoint
template <>
inline const double UpperBound<int64_t>() {
const double kInt64UpperBound = static_cast<double>((1ll << 53) - 1);
return kInt64UpperBound;
}
template <>
inline const double LowerBound<int64_t>() {
const double kInt64LowerBound = static_cast<double>(-(1ll << 53) + 1);
return kInt64LowerBound;
}
template <>
inline const double UpperBound<uint64_t>() {
const double kUInt64UpperBound = static_cast<double>((1ll << 53) - 1);
return kUInt64UpperBound;
}
// TODO: Consider just having this return a value. Or just inline in it now
// that we removed the code duplication across integer conversions.
template <typename T>
void ClampedValue(v8::Isolate* isolate, v8::Local<v8::Value> value,
v8::Local<v8::Value>* clamped_value) {
v8::MaybeLocal<v8::Number> maybe_number =
value->ToNumber(isolate->GetCurrentContext());
v8::Local<v8::Number> number;
if (!maybe_number.ToLocal(&number)) {
return;
}
double value_of_number = number->Value();
if (value_of_number > UpperBound<T>()) {
value_of_number = UpperBound<T>();
} else if (value_of_number < LowerBound<T>()) {
value_of_number = LowerBound<T>();
}
*clamped_value = v8::Number::New(isolate, value_of_number);
}
namespace internal {
// A small helper metafunction for integer-like FromJSValue conversions to
// pick the right type to feed to V8, which can only be the output types
// observed here.
template <typename T>
struct IntegralTypeToOutType {
static_assert(std::numeric_limits<T>::is_specialized &&
std::numeric_limits<T>::is_integer,
"");
using type = typename std::conditional<
std::numeric_limits<T>::is_signed,
typename std::conditional<(sizeof(T) <= 4), int32_t, int64_t>::type,
typename std::conditional<(sizeof(T) <= 4), uint32_t,
uint64_t>::type>::type;
};
inline bool ToOutType(v8::Isolate* isolate, v8::Local<v8::Value> value,
int32_t* out) {
v8::Maybe<int32_t> maybe_result =
value->Int32Value(isolate->GetCurrentContext());
if (!maybe_result.To(out)) {
return false;
}
return true;
}
inline bool ToOutType(v8::Isolate* isolate, v8::Local<v8::Value> value,
int64_t* out) {
v8::Maybe<int64_t> maybe_result =
value->IntegerValue(isolate->GetCurrentContext());
if (!maybe_result.To(out)) {
return false;
}
*out = maybe_result.FromJust();
return true;
}
inline bool ToOutType(v8::Isolate* isolate, v8::Local<v8::Value> value,
uint32_t* out) {
v8::Maybe<uint32_t> maybe_result =
value->Uint32Value(isolate->GetCurrentContext());
if (!maybe_result.To(out)) {
return false;
}
*out = maybe_result.FromJust();
return true;
}
inline bool ToOutType(v8::Isolate* isolate, v8::Local<v8::Value> value,
uint64_t* out) {
// V8 doesn't have anything for uint64_t (TODO: why? More spec compliant?
// less spec compliant?...), so this one is different.
v8::Maybe<double> maybe_result =
value->NumberValue(isolate->GetCurrentContext());
if (maybe_result.IsNothing()) {
return false;
}
*out = static_cast<uint64_t>(maybe_result.FromJust());
return true;
}
} // namespace internal
// JSValue -> integer-like
template <typename T>
inline void FromJSValue(
v8::Isolate* isolate, v8::Local<v8::Value> value, int conversion_flags,
ExceptionState* exception_state, T* out_number,
typename base::enable_if<std::numeric_limits<T>::is_specialized &&
std::numeric_limits<T>::is_integer,
T>::type* = NULL) {
DCHECK(out_number);
if (UNLIKELY(value->IsSymbol())) {
exception_state->SetSimpleException(
kTypeError, "Cannot convert a Symbol value to a number");
return;
}
// Convert a JavaScript value to an integer type as specified by the
// ECMAScript standard.
using OutType = typename internal::IntegralTypeToOutType<T>::type;
OutType out;
bool success;
if (UNLIKELY(conversion_flags & kConversionFlagClamped)) {
v8::Local<v8::Value> clamped_value;
ClampedValue<T>(isolate, value, &clamped_value);
DCHECK(!clamped_value.IsEmpty());
success = internal::ToOutType(isolate, clamped_value, &out);
} else {
success = internal::ToOutType(isolate, value, &out);
}
// It is possible for |JS::To{Uint,Int}{32,64}| to fail in certain edge
// cases, such as application JavaScript setting up infinite recursion that
// gets triggered by the conversion.
if (!success) {
// TODO: Still need to handle infinite recursion edge case here.
// V8 does not provide APIs to determine if it is throwing exception and
// neither does v8 provide API to alert that we might enter infinite
// exception handling.
exception_state->SetSimpleException(
std::numeric_limits<T>::is_signed ? kNotInt64Type : kNotUint64Type);
return;
}
*out_number = static_cast<T>(out);
}
// signed integers > 4 bytes -> JSValue
template <typename T>
inline void ToJSValue(
v8::Isolate* isolate, T in_number, v8::Local<v8::Value>* out_value,
typename base::enable_if<std::numeric_limits<T>::is_specialized &&
std::numeric_limits<T>::is_integer &&
std::numeric_limits<T>::is_signed &&
(sizeof(T) > 4),
T>::type* = NULL) {
*out_value = v8::Number::New(isolate, in_number);
}
// unsigned integers <= 4 bytes -> JSValue
template <typename T>
inline void ToJSValue(
v8::Isolate* isolate, T in_number, v8::Local<v8::Value>* out_value,
typename base::enable_if<std::numeric_limits<T>::is_specialized &&
std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed &&
(sizeof(T) <= 4),
T>::type* = NULL) {
*out_value = v8::Integer::NewFromUnsigned(isolate, in_number);
}
// TODO: Don't specialize template on these..., have them share an impl w/
// double unsigned integers > 4 bytes -> JSValue
template <typename T>
inline void ToJSValue(
v8::Isolate* isolate, T in_number, v8::Local<v8::Value>* out_value,
typename base::enable_if<std::numeric_limits<T>::is_specialized &&
std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed &&
(sizeof(T) > 4),
T>::type* = NULL) {
*out_value = v8::Number::New(isolate, in_number);
}
// double -> JSValue
template <typename T>
inline void ToJSValue(
v8::Isolate* isolate, T in_number, v8::Local<v8::Value>* out_value,
typename base::enable_if<std::numeric_limits<T>::is_specialized &&
!std::numeric_limits<T>::is_integer,
T>::type* = NULL) {
*out_value = v8::Number::New(isolate, in_number);
}
// JSValue -> double
template <typename T>
inline void FromJSValue(
v8::Isolate* isolate, v8::Local<v8::Value> value, int conversion_flags,
ExceptionState* exception_state, T* out_number,
typename base::enable_if<std::numeric_limits<T>::is_specialized &&
!std::numeric_limits<T>::is_integer,
T>::type* = NULL) {
DCHECK_EQ(conversion_flags & ~kConversionFlagsNumeric, 0)
<< "Unexpected conversion flags found.";
v8::MaybeLocal<v8::Number> maybe_value_as_number =
value->ToNumber(isolate->GetCurrentContext());
v8::Local<v8::Number> value_as_number;
if (!maybe_value_as_number.ToLocal(&value_as_number)) {
NOTIMPLEMENTED();
return;
}
double value_as_double = value_as_number->Value();
if ((conversion_flags & kConversionFlagRestricted) &&
!std::isfinite(value_as_double)) {
exception_state->SetSimpleException(kNotFinite);
return;
}
*out_number = value_as_double;
}
// optional<T> -> JSValue
template <typename T>
inline void ToJSValue(v8::Isolate* isolate,
const base::Optional<T>& in_optional,
v8::Local<v8::Value>* out_value) {
if (in_optional) {
ToJSValue(isolate, in_optional.value(), out_value);
} else {
*out_value = v8::Null(isolate);
}
}
// JSValue -> optional<T>
template <typename T>
inline void FromJSValue(v8::Isolate* isolate, v8::Local<v8::Value> value,
int conversion_flags, ExceptionState* exception_state,
base::Optional<T>* out_optional) {
if (value->IsNullOrUndefined()) {
*out_optional = base::nullopt;
} else {
*out_optional = T();
FromJSValue(isolate, value, conversion_flags & ~kConversionFlagNullable,
exception_state, &(out_optional->value()));
}
}
// JSValue -> optional<std::string>
template <>
inline void FromJSValue(v8::Isolate* isolate, v8::Local<v8::Value> value,
int conversion_flags, ExceptionState* exception_state,
base::Optional<std::string>* out_optional) {
if (value->IsNull()) {
*out_optional = base::nullopt;
} else if (value->IsUndefined() &&
!(conversion_flags & kConversionFlagTreatUndefinedAsEmptyString)) {
// If TreatUndefinedAs=EmptyString is set, skip the default conversion
// of undefined to null.
*out_optional = base::nullopt;
} else {
*out_optional = std::string();
FromJSValue(isolate, value, conversion_flags & ~kConversionFlagNullable,
exception_state, &(out_optional->value()));
}
}
// ValueHandle -> JSValue
void ToJSValue(v8::Isolate* isolate,
const ValueHandleHolder* value_handle_holder,
v8::Local<v8::Value>* out_value);
// base::Time -> JSValue
void ToJSValue(v8::Isolate* isolate, const base::Time& time,
v8::Local<v8::Value>* out_value);
// JSValue -> base::Time
void FromJSValue(v8::Isolate* isolate, v8::Local<v8::Value> value,
int conversion_flags, ExceptionState* exception_state,
base::Time* out_time);
// JSValue -> ValueHandle
void FromJSValue(v8::Isolate* isolate, v8::Local<v8::Value> value,
int conversion_flags, ExceptionState* exception_state,
V8cValueHandleHolder* out_holder);
// object -> JSValue
template <typename T>
inline void ToJSValue(v8::Isolate* isolate, const scoped_refptr<T>& in_object,
v8::Local<v8::Value>* out_value) {
if (!in_object) {
*out_value = v8::Null(isolate);
return;
}
V8cGlobalEnvironment* global_environment =
V8cGlobalEnvironment::GetFromIsolate(isolate);
*out_value = global_environment->wrapper_factory()->GetWrapper(in_object);
}
// raw object pointer -> JSValue
template <typename T>
inline void ToJSValue(v8::Isolate* isolate, T* in_object,
v8::Local<v8::Value>* out_value) {
ToJSValue(isolate, scoped_refptr<T>(in_object), out_value);
}
// JSValue -> object
template <typename T>
inline void FromJSValue(v8::Isolate* isolate, v8::Local<v8::Value> value,
int conversion_flags, ExceptionState* exception_state,
scoped_refptr<T>* out_object) {
DCHECK_EQ(conversion_flags & ~kConversionFlagsObject, 0)
<< "Unexpected conversion flags found.";
if (value->IsNullOrUndefined()) {
if (!(conversion_flags & kConversionFlagNullable)) {
exception_state->SetSimpleException(kNotNullableType);
}
return;
}
if (!value->IsObject()) {
exception_state->SetSimpleException(kNotObjectType);
return;
}
V8cGlobalEnvironment* global_environment =
V8cGlobalEnvironment::GetFromIsolate(isolate);
WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
v8::Local<v8::Object> object = value.As<v8::Object>();
// Note that |DoesObjectImplementInterface| handles the case in which
// |object| has no |WrapperPrivate|.
if (!wrapper_factory->DoesObjectImplementInterface(object,
base::GetTypeId<T>())) {
exception_state->SetSimpleException(kDoesNotImplementInterface);
return;
}
WrapperPrivate* wrapper_private =
WrapperPrivate::GetFromWrapperObject(object);
DCHECK(wrapper_private);
*out_object = wrapper_private->wrappable<T>();
}
// CallbackInterface -> JSValue
template <typename T>
inline void ToJSValue(v8::Isolate* isolate,
const ScriptValue<T>* callback_interface,
v8::Local<v8::Value>* out_value) {
if (!callback_interface) {
*out_value = v8::Null(isolate);
return;
}
typedef typename CallbackInterfaceTraits<T>::V8cCallbackInterfaceClass
V8cCallbackInterfaceClass;
// Downcast to V8cUserObjectHolder<T> so we can get the underlying JSObject.
typedef V8cUserObjectHolder<V8cCallbackInterfaceClass>
V8cUserObjectHolderClass;
const V8cUserObjectHolderClass* user_object_holder =
base::polymorphic_downcast<const V8cUserObjectHolderClass*>(
callback_interface);
// Shouldn't be NULL. If the callback was NULL then NULL should have been
// passed as an argument into this function.
// Downcast to the corresponding V8cCallbackInterface type, from which we
// can get the implementing object.
const V8cCallbackInterfaceClass* v8c_callback_interface =
base::polymorphic_downcast<const V8cCallbackInterfaceClass*>(
user_object_holder->GetValue());
DCHECK(v8c_callback_interface);
*out_value = v8c_callback_interface->NewLocal(isolate);
}
// JSValue -> CallbackInterface
template <typename T>
inline void FromJSValue(v8::Isolate* isolate, v8::Local<v8::Value> value,
int conversion_flags, ExceptionState* out_exception,
V8cCallbackInterfaceHolder<T>* out_callback_interface) {
typedef T V8cCallbackInterfaceClass;
DCHECK_EQ(conversion_flags & ~kConversionFlagsCallbackFunction, 0)
<< "No conversion flags supported.";
if (value->IsNull()) {
if (!(conversion_flags & kConversionFlagNullable)) {
out_exception->SetSimpleException(kNotNullableType);
}
// If it is a nullable type, just return.
return;
}
// https://www.w3.org/TR/WebIDL/#es-user-objects
// Any user object can be considered to implement a user interface. Actually
// checking if the correct properties exist will happen when the operation
// on the callback interface is run.
if (!value->IsObject()) {
out_exception->SetSimpleException(kNotObjectType);
return;
}
*out_callback_interface = V8cCallbackInterfaceHolder<T>(isolate, value);
}
// Sequence -> JSValue
template <typename T>
void ToJSValue(v8::Isolate* isolate, const script::Sequence<T>& sequence,
v8::Local<v8::Value>* out_value) {
// 1. Let n be the length of S.
using size_type = typename script::Sequence<T>::size_type;
size_type count = sequence.size();
// 2. Let A be a new Array object created as if by the expression [].
v8::Local<v8::Array> array = v8::Array::New(isolate);
// 3. Initialize i to be 0.
// 4. While i < n:
for (size_type index = 0; index < count; ++index) {
// 4.1. Let V be the value in S at index i.
// 4.2. Let E be the result of converting V to an ECMAScript value.
v8::Local<v8::Value> element;
ToJSValue(isolate, sequence.at(index), &element);
// 4.3. Let P be the result of calling ToString(i).
// 4.4. Call CreateDataProperty(A, P, E).
v8::Maybe<bool> set_result =
array->Set(isolate->GetCurrentContext(), index, element);
// 4.5. Set i to i + 1.
}
// 5. Return A.
*out_value = array;
}
// JSValue -> Sequence
template <typename T>
void FromJSValue(v8::Isolate* isolate, v8::Local<v8::Value> value,
int conversion_flags, ExceptionState* exception_state,
script::Sequence<T>* out_sequence) {
DCHECK_EQ(0, conversion_flags);
DCHECK(out_sequence);
// JS -> IDL type conversion procedure described here:
// https://heycam.github.io/webidl/#es-sequence
// 1. If Type(V) is not Object, throw a TypeError.
if (!value->IsObject()) {
exception_state->SetSimpleException(kNotObjectType);
return;
}
// 2. Let method be ? GetMethod(V, @@iterator).
// 3. If method is undefined, throw a TypeError.
v8::Local<v8::Object> iterable = value.As<v8::Object>();
v8::Local<v8::Object> iterator;
V8cExceptionState* v8c_exception_state =
base::polymorphic_downcast<V8cExceptionState*>(exception_state);
if (!GetIterator(isolate, iterable, v8c_exception_state).ToLocal(&iterator)) {
DCHECK(v8c_exception_state->is_exception_set());
return;
}
v8::Local<v8::String> next_key = NewInternalString(isolate, "next");
v8::Local<v8::String> value_key = NewInternalString(isolate, "value");
v8::Local<v8::String> done_key = NewInternalString(isolate, "done");
v8::Local<v8::Context> context = isolate->GetCurrentContext();
// 4. Return the result of creating a sequence from V and method.
// https://heycam.github.io/webidl/#create-sequence-from-iterable
for (;;) {
// Let next be ? IteratorStep(iter).
v8::Local<v8::Value> next;
if (!iterator->Get(context, next_key).ToLocal(&next)) {
exception_state->SetSimpleException(kTypeError, "");
return;
}
if (!next->IsFunction()) {
exception_state->SetSimpleException(kTypeError,
"Iterator.next should be callable.");
return;
}
v8::Local<v8::Value> next_result;
if (!next.As<v8::Function>()
->Call(context, iterator, 0, nullptr)
.ToLocal(&next_result)) {
return;
}
if (!next_result->IsObject()) {
exception_state->SetSimpleException(
kTypeError, "Iterator.next did not return an object.");
return;
}
// Let nextItem be ? IteratorValue(next).
v8::Local<v8::Object> result_object = next_result.As<v8::Object>();
v8::Local<v8::Value> next_item;
v8::Local<v8::Value> done;
if (!result_object->Get(context, value_key).ToLocal(&next_item) ||
!result_object->Get(context, done_key).ToLocal(&done)) {
return;
}
if (done->BooleanValue(isolate)) {
break;
}
// Initialize S_i to the result of converting nextItem to an IDL value
// of type T.
T idl_next_item;
FromJSValue(isolate, next_item, conversion_flags, exception_state,
&idl_next_item);
if (v8c_exception_state->is_exception_set()) {
return;
}
out_sequence->push_back(idl_next_item);
}
}
template <typename T>
void ToJSValue(v8::Isolate* isolate,
const ScriptValue<Promise<T>>* promise_holder,
v8::Local<v8::Value>* out_value);
template <typename T>
void ToJSValue(v8::Isolate* isolate, ScriptValue<Promise<T>>* promise_holder,
v8::Local<v8::Value>* out_value);
// script::Handle<T> -> JSValue
template <typename T>
void ToJSValue(v8::Isolate* isolate, const Handle<T>& local,
v8::Local<v8::Value>* out_value) {
TRACK_MEMORY_SCOPE("Javascript");
ToJSValue(isolate, local.GetScriptValue(), out_value);
}
// script::Handle<JSValue> -> object
template <typename T>
inline void FromJSValue(v8::Isolate* isolate, v8::Local<v8::Value> value,
int conversion_flags, ExceptionState* exception_state,
Handle<T>* out_object) {
DCHECK_EQ(conversion_flags & ~kConversionFlagsObject, 0)
<< "Unexpected conversion flags found.";
if (value->IsNullOrUndefined()) {
if (!(conversion_flags & kConversionFlagNullable)) {
exception_state->SetSimpleException(kNotNullableType);
}
return;
}
typename TypeTraits<T>::ConversionType temporary_holder;
FromJSValue(isolate, value, conversion_flags, exception_state,
&temporary_holder);
*out_object = std::move(Handle<T>(temporary_holder));
}
} // namespace v8c
} // namespace script
} // namespace cobalt
// Union type conversion is generated by a pump script.
#include "cobalt/script/v8c/union_type_conversion_impl.h"
#endif // COBALT_SCRIPT_V8C_CONVERSION_HELPERS_H_