blob: 78cc1e1f68c979f4346c74f12b44b9ded931ed9d [file] [log] [blame]
// Copyright 2016 Google Inc. 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_MOZJS_45_CONVERSION_HELPERS_H_
#define COBALT_SCRIPT_MOZJS_45_CONVERSION_HELPERS_H_
#include <limits>
#include <string>
#include <vector>
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/optional.h"
#include "base/stringprintf.h"
#include "base/time.h"
#include "cobalt/base/compiler.h"
#include "cobalt/base/enable_if.h"
#include "cobalt/base/token.h"
#include "cobalt/script/mozjs-45/mozjs_array_buffer.h"
#include "cobalt/script/mozjs-45/mozjs_array_buffer_view.h"
#include "cobalt/script/mozjs-45/mozjs_callback_interface_holder.h"
#include "cobalt/script/mozjs-45/mozjs_data_view.h"
#include "cobalt/script/mozjs-45/mozjs_exception_state.h"
#include "cobalt/script/mozjs-45/mozjs_global_environment.h"
#include "cobalt/script/mozjs-45/mozjs_typed_arrays.h"
#include "cobalt/script/mozjs-45/mozjs_user_object_holder.h"
#include "cobalt/script/mozjs-45/mozjs_value_handle.h"
#include "cobalt/script/mozjs-45/type_traits.h"
#include "cobalt/script/mozjs-45/union_type_conversion_forward.h"
#include "cobalt/script/mozjs-45/util/algorithm_helpers.h"
#include "cobalt/script/sequence.h"
#include "cobalt/script/value_handle.h"
#include "nb/memory_scope.h"
#include "third_party/mozjs-45/js/public/CharacterEncoding.h"
#include "third_party/mozjs-45/js/public/Conversions.h"
#include "third_party/mozjs-45/js/src/jsapi.h"
#include "third_party/mozjs-45/js/src/jsarray.h"
#include "third_party/mozjs-45/js/src/jscntxt.h"
#include "third_party/mozjs-45/js/src/jsstr.h"
#include "third_party/mozjs-45/js/src/proxy/Proxy.h"
namespace cobalt {
namespace script {
namespace mozjs {
// 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(JSContext* context, const std::string& in_string,
JS::MutableHandleValue out_value) {
TRACK_MEMORY_SCOPE("Javascript");
DCHECK(JS::CurrentGlobalOrNull(context));
size_t length = in_string.length();
char16_t* inflated_buffer =
UTF8CharsToNewTwoByteCharsZ(
context, JS::UTF8Chars(in_string.c_str(), length), &length)
.get();
if (!inflated_buffer) {
LOG(ERROR) << "Failed to inflate UTF8 string.";
out_value.setNull();
return;
}
JSString* string = JS_NewUCStringCopyN(context, inflated_buffer, length);
js_free(inflated_buffer);
out_value.setString(string);
}
// JSValue -> std::string
void FromJSValue(JSContext* context, JS::HandleValue 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(JSContext* context, const std::vector<uint8_t>& in_data,
JS::MutableHandleValue out_value) {
JSString* js_string = JS_NewStringCopyN(
context, reinterpret_cast<const char*>(in_data.data()), in_data.size());
out_value.setString(js_string);
}
// base::Token -> JSValue
inline void ToJSValue(JSContext* context, const base::Token& token,
JS::MutableHandleValue out_value) {
TRACK_MEMORY_SCOPE("Javascript");
ToJSValue(context, std::string(token.c_str()), out_value);
}
// bool -> JSValue
inline void ToJSValue(JSContext* context, bool in_boolean,
JS::MutableHandleValue out_value) {
TRACK_MEMORY_SCOPE("Javascript");
out_value.set(JS::BooleanValue(in_boolean));
}
// JSValue -> bool
inline void FromJSValue(JSContext* context, JS::HandleValue value,
int conversion_flags, ExceptionState* exception_state,
bool* out_boolean) {
TRACK_MEMORY_SCOPE("Javascript");
DCHECK_EQ(conversion_flags, kNoConversionFlags)
<< "No conversion flags supported.";
DCHECK(out_boolean);
// |JS::ToBoolean| implements the ECMAScript ToBoolean operation.
// Note that |JS::ToBoolean| will handle the case in which |value| is of
// type Symbol without throwing.
*out_boolean = JS::ToBoolean(value);
}
// signed integers <= 4 bytes -> JSValue
template <typename T>
inline void ToJSValue(
JSContext* context, T in_number, JS::MutableHandleValue 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) {
TRACK_MEMORY_SCOPE("Javascript");
out_value.setInt32(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;
}
template <typename T>
void ClampedValue(JSContext* context, JS::HandleValue value,
JS::MutableHandleValue clamped_value) {
double value_double;
JS::ToNumber(context, value, &value_double);
if (value_double > UpperBound<T>()) {
clamped_value.setDouble(UpperBound<T>());
} else if (value_double < LowerBound<T>()) {
clamped_value.setDouble(LowerBound<T>());
} else {
clamped_value.set(value);
}
}
namespace internal {
// A small helper metafunction for integer-like FromJSValue conversions to
// pick the right type to feed to SpiderMonkey, which can only be the output
// types observed here.
template <typename T>
struct IntegralTypeToJsOutType {
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;
};
// And some overloads to get all these different calls under the same
// identifier in the single template implementation.
inline bool JSToIntegral(JSContext* context, JS::HandleValue value,
int32_t* out) {
return JS::ToInt32(context, value, out);
}
inline bool JSToIntegral(JSContext* context, JS::HandleValue value,
int64_t* out) {
return JS::ToInt64(context, value, out);
}
inline bool JSToIntegral(JSContext* context, JS::HandleValue value,
uint32_t* out) {
return JS::ToUint32(context, value, out);
}
inline bool JSToIntegral(JSContext* context, JS::HandleValue value,
uint64_t* out) {
return JS::ToUint64(context, value, out);
}
} // namespace internal
// JSValue -> integer-like
template <typename T>
inline void FromJSValue(
JSContext* context, JS::HandleValue 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) {
TRACK_MEMORY_SCOPE("Javascript");
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::IntegralTypeToJsOutType<T>::type;
OutType out;
bool success;
if (UNLIKELY(conversion_flags & kConversionFlagClamped)) {
JS::RootedValue clamped_value(context);
ClampedValue<T>(context, value, &clamped_value);
success = internal::JSToIntegral(context, clamped_value, &out);
} else {
success = internal::JSToIntegral(context, 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) {
if (JS_IsExceptionPending(context)) {
// If SpiderMonkey already threw something as a result of calling
// |JS::To{Uint,Int}{32,64}|, then just use that...
base::polymorphic_downcast<MozjsExceptionState*>(exception_state)
->SetExceptionAlreadySet(context);
} else {
// ...and if not, then just tell them that it isn't the right type.
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(
JSContext* context, T in_number, JS::MutableHandleValue 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) {
TRACK_MEMORY_SCOPE("Javascript");
out_value.set(JS_NumberValue(in_number));
}
// unsigned integers <= 4 bytes -> JSValue
template <typename T>
inline void ToJSValue(
JSContext* context, T in_number, JS::MutableHandleValue 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) {
TRACK_MEMORY_SCOPE("Javascript");
// Must do static cast in the (valid) case where we get a uint8_t or
// uint16_t and call to |setNumber({uint32_t, double})| becomes ambiguous.
out_value.setNumber(static_cast<uint32_t>(in_number));
}
// unsigned integers > 4 bytes -> JSValue
template <typename T>
inline void ToJSValue(
JSContext* context, T in_number, JS::MutableHandleValue 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) {
TRACK_MEMORY_SCOPE("Javascript");
out_value.set(JS_NumberValue(in_number));
}
// double -> JSValue
template <typename T>
inline void ToJSValue(
JSContext* context, T in_number, JS::MutableHandleValue out_value,
typename base::enable_if<std::numeric_limits<T>::is_specialized &&
!std::numeric_limits<T>::is_integer,
T>::type* = NULL) {
TRACK_MEMORY_SCOPE("Javascript");
out_value.setDouble(in_number);
}
// JSValue -> double
template <typename T>
inline void FromJSValue(
JSContext* context, JS::HandleValue 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) {
TRACK_MEMORY_SCOPE("Javascript");
DCHECK_EQ(conversion_flags & ~kConversionFlagsNumeric, 0)
<< "Unexpected conversion flags found.";
DCHECK(out_number);
if (UNLIKELY(value.isSymbol())) {
exception_state->SetSimpleException(
kTypeError, "Cannot convert a Symbol value to a number");
return;
}
double double_value;
if (!JS::ToNumber(context, value, &double_value)) {
exception_state->SetSimpleException(kNotNumberType);
return;
}
if (!mozilla::IsFinite(double_value) &&
(conversion_flags & kConversionFlagRestricted)) {
exception_state->SetSimpleException(kNotFinite);
return;
}
*out_number = double_value;
}
// optional<T> -> JSValue
template <typename T>
inline void ToJSValue(JSContext* context, const base::optional<T>& in_optional,
JS::MutableHandleValue out_value) {
TRACK_MEMORY_SCOPE("Javascript");
if (!in_optional) {
out_value.setNull();
return;
}
ToJSValue(context, in_optional.value(), out_value);
}
// JSValue -> optional<T>
template <typename T>
inline void FromJSValue(JSContext* context, JS::HandleValue value,
int conversion_flags, ExceptionState* exception_state,
base::optional<T>* out_optional) {
TRACK_MEMORY_SCOPE("Javascript");
if (value.isNull()) {
*out_optional = base::nullopt;
} else if (value.isUndefined()) {
*out_optional = base::nullopt;
} else {
*out_optional = T();
FromJSValue(context, value, conversion_flags & ~kConversionFlagNullable,
exception_state, &(out_optional->value()));
}
}
// JSValue -> optional<std::string>
template <>
inline void FromJSValue(JSContext* context, JS::HandleValue value,
int conversion_flags, ExceptionState* exception_state,
base::optional<std::string>* out_optional) {
TRACK_MEMORY_SCOPE("Javascript");
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(context, value, conversion_flags & ~kConversionFlagNullable,
exception_state, &(out_optional->value()));
}
}
// ValueHandle -> JSValue
void ToJSValue(JSContext* context, const ValueHandleHolder* value_handle_holder,
JS::MutableHandleValue out_value);
// base::Time -> JSValue
void ToJSValue(JSContext* context, const base::Time& time,
JS::MutableHandleValue out_value);
// JSValue -> base::Time
void FromJSValue(JSContext* context, JS::HandleValue value,
int conversion_flags, ExceptionState* exception_state,
base::Time* out_time);
// JSValue -> ValueHandle
void FromJSValue(JSContext* context, JS::HandleValue value,
int conversion_flags, ExceptionState* exception_state,
MozjsValueHandleHolder* out_holder);
// object -> JSValue
template <typename T>
inline void ToJSValue(JSContext* context, const scoped_refptr<T>& in_object,
JS::MutableHandleValue out_value) {
TRACK_MEMORY_SCOPE("Javascript");
if (!in_object) {
out_value.setNull();
return;
}
MozjsGlobalEnvironment* global_environment =
static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
JS::RootedObject object(
context,
global_environment->wrapper_factory()->GetWrapperProxy(in_object));
DCHECK(object);
JS::RootedObject proxy_target(context, js::GetProxyTargetObject(object));
if (JS_IsGlobalObject(proxy_target)) {
object = proxy_target;
}
out_value.setObject(*object);
}
// raw object pointer -> JSValue
template <typename T>
inline void ToJSValue(JSContext* context, T* in_object,
JS::MutableHandleValue out_value) {
TRACK_MEMORY_SCOPE("Javascript");
ToJSValue(context, scoped_refptr<T>(in_object), out_value);
}
// JSValue -> object
template <typename T>
inline void FromJSValue(JSContext* context, JS::HandleValue value,
int conversion_flags, ExceptionState* exception_state,
scoped_refptr<T>* out_object) {
TRACK_MEMORY_SCOPE("Javascript");
DCHECK_EQ(conversion_flags & ~kConversionFlagsObject, 0)
<< "Unexpected conversion flags found.";
JS::RootedObject js_object(context);
if (value.isNull() || value.isUndefined()) {
if (!(conversion_flags & kConversionFlagNullable)) {
exception_state->SetSimpleException(kNotNullableType);
}
return;
}
if (!JS_ValueToObject(context, value, &js_object)) {
exception_state->SetSimpleException(kNotObjectType);
return;
}
DCHECK(js_object);
JS::RootedObject wrapper(context, js::IsProxy(js_object)
? js::GetProxyTargetObject(js_object)
: js_object);
MozjsGlobalEnvironment* global_environment =
static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context));
const WrapperFactory* wrapper_factory = global_environment->wrapper_factory();
if (wrapper_factory->IsWrapper(wrapper)) {
bool object_implements_interface =
wrapper_factory->DoesObjectImplementInterface(js_object,
base::GetTypeId<T>());
if (!object_implements_interface) {
exception_state->SetSimpleException(kDoesNotImplementInterface);
return;
}
WrapperPrivate* wrapper_private =
WrapperPrivate::GetFromWrapperObject(wrapper);
*out_object = wrapper_private->wrappable<T>();
return;
}
// This is not a platform object. Return a type error.
exception_state->SetSimpleException(kDoesNotImplementInterface);
}
// ScriptValue<T> (where T is a CallbackInterface) -> JSValue
// Note that there is currently no implementation for ScriptValue<T> where T
// is not a CallbackInterface.
template <typename T>
inline void ToJSValue(JSContext* context,
const ScriptValue<T>* callback_interface,
JS::MutableHandleValue out_value) {
TRACK_MEMORY_SCOPE("Javascript");
if (!callback_interface) {
out_value.set(JS::NullValue());
return;
}
typedef typename CallbackInterfaceTraits<T>::MozjsCallbackInterfaceClass
MozjsCallbackInterfaceClass;
// Downcast to MozjsUserObjectHolder<T> so we can get the underlying JSObject.
typedef MozjsUserObjectHolder<MozjsCallbackInterfaceClass>
MozjsUserObjectHolderClass;
const MozjsUserObjectHolderClass* user_object_holder =
base::polymorphic_downcast<const MozjsUserObjectHolderClass*>(
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 MozjsCallbackInterface type, from which we
// can get the implementing object.
const MozjsCallbackInterfaceClass* mozjs_callback_interface =
base::polymorphic_downcast<const MozjsCallbackInterfaceClass*>(
user_object_holder->GetValue());
DCHECK(mozjs_callback_interface);
out_value.setObjectOrNull(mozjs_callback_interface->handle());
}
// JSValue -> CallbackInterface
template <typename T>
inline void FromJSValue(
JSContext* context, JS::HandleValue value, int conversion_flags,
ExceptionState* out_exception,
MozjsCallbackInterfaceHolder<T>* out_callback_interface) {
TRACK_MEMORY_SCOPE("Javascript");
typedef T MozjsCallbackInterfaceClass;
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;
}
DCHECK(value.isObject());
*out_callback_interface = MozjsCallbackInterfaceHolder<T>(context, value);
}
// Sequence -> JSValue
template <typename T>
void ToJSValue(JSContext* context, const script::Sequence<T>& sequence,
JS::MutableHandleValue out_value) {
TRACK_MEMORY_SCOPE("Javascript");
// 1. Let n be the length of S.
typedef typename script::Sequence<T>::size_type size_type;
size_type count = sequence.size();
// 2. Let A be a new Array object created as if by the expression [].
JS::RootedObject array(context, js::NewDenseEmptyArray(context));
// 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.
JS::RootedValue element(context);
ToJSValue(context, sequence.at(index), &element);
std::string property =
base::StringPrintf("%" PRIu64, static_cast<uint64_t>(index));
// 4.3. Let P be the result of calling ToString(i).
// 4.4. Call CreateDataProperty(A, P, E).
JS_SetProperty(context, array, property.c_str(), element);
// 4.5. Set i to i + 1.
}
// 5. Return A.
out_value.setObject(*array);
}
// JSValue -> Sequence
template <typename T>
void FromJSValue(JSContext* context, JS::HandleValue value,
int conversion_flags, ExceptionState* exception_state,
script::Sequence<T>* out_sequence) {
TRACK_MEMORY_SCOPE("Javascript");
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.
JS::RootedObject iterable(context);
if (!value.isObject() ||
!JS_ValueToObject(context, value, &iterable)) {
exception_state->SetSimpleException(kNotObjectType);
return;
}
// 2. Let method be the result of GetMethod(V, @@iterator).
// 3. ReturnIfAbrupt(method).
// 4. If method is undefined, throw a TypeError.
// 5. Return the result of creating a sequence from V and method.
// https://heycam.github.io/webidl/#create-sequence-from-iterable
// 5.1. Let iter be GetIterator(iterable, method).
JS::RootedObject iter(context);
if (!util::GetIterator(context, iterable, &iter)) {
exception_state->SetSimpleException(kNotIterableType);
return;
}
// 5.2. ReturnIfAbrupt(iter).
// 5.3. Initialize i to be 0.
// 5.4. Repeat
while (true) {
// 5.4.1. Let next be IteratorStep(iter).
// 5.4.2. ReturnIfAbrupt(next).
// 5.4.3. If next is false, then return an IDL sequence value of type
// sequence<T> of length i, where the value of the element at index j
// is Sj.
JS::RootedObject next(context);
if (!util::IteratorStep(context, iter, &next)) {
break;
}
// 5.4.4. Let nextItem be IteratorValue(next).
// 5.4.5. ReturnIfAbrupt(nextItem).
JS::RootedValue next_item(context);
if (!util::IteratorValue(context, next, &next_item)) {
exception_state->SetSimpleException(kDoesNotImplementInterface);
util::IteratorClose(context, iter);
return;
}
// 5.4.6. Initialize Si to the result of converting nextItem to an IDL value
// of type T.
T idl_next_item;
FromJSValue(context, next_item, conversion_flags, exception_state,
&idl_next_item);
if (context->isExceptionPending()) {
// Exception converting element into to sequence element type.
util::IteratorClose(context, iter);
return;
}
out_sequence->push_back(idl_next_item);
// 5.4.7. Set i to i + 1.
}
util::IteratorClose(context, iter);
return;
}
template <typename T>
void ToJSValue(JSContext* context,
const ScriptValue<Promise<T>>* promise_holder,
JS::MutableHandleValue out_value);
template <typename T>
void ToJSValue(JSContext* context, ScriptValue<Promise<T>>* promise_holder,
JS::MutableHandleValue out_value);
// script::Handle<T> -> JSValue
template <typename T>
void ToJSValue(JSContext* context, const Handle<T>& handle,
JS::MutableHandleValue out_value) {
TRACK_MEMORY_SCOPE("Javascript");
ToJSValue(context, handle.GetScriptValue(), out_value);
}
// script::Handle<JSValue> -> object
template <typename T>
inline void FromJSValue(JSContext* context, JS::HandleValue 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(context, value, conversion_flags, exception_state,
&temporary_holder);
*out_object = std::move(Handle<T>(temporary_holder));
}
} // namespace mozjs
} // namespace script
} // namespace cobalt
// Union type conversion is generated by a pump script.
#include "cobalt/script/mozjs-45/union_type_conversion_impl.h"
#endif // COBALT_SCRIPT_MOZJS_45_CONVERSION_HELPERS_H_