// Copyright 2013 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef GIN_CONVERTER_H_ #define GIN_CONVERTER_H_ #include #include #include #include #include #include #include #include #include "base/check.h" #include "base/location.h" #include "base/notreached.h" #include "gin/gin_export.h" #include "v8/include/v8-container.h" #include "v8/include/v8-forward.h" #include "v8/include/v8-isolate.h" #include "v8/include/v8-source-location.h" namespace base { class TimeTicks; } namespace gin { template bool SetProperty(v8::Isolate* isolate, v8::Local object, KeyType key, v8::Local value) { auto maybe = object->DefineOwnProperty(isolate->GetCurrentContext(), key, value); return !maybe.IsNothing() && maybe.FromJust(); } template struct Converter {}; namespace internal { template concept ToV8ReturnsMaybe = requires(v8::Isolate* isolate, T value) { { Converter::ToV8(isolate, value) } -> std::same_as>; }; } // namespace internal template<> struct GIN_EXPORT Converter { static v8::Local ToV8(v8::Isolate* isolate, bool val); static bool FromV8(v8::Isolate* isolate, v8::Local val, bool* out); }; template<> struct GIN_EXPORT Converter { static v8::Local ToV8(v8::Isolate* isolate, int32_t val); static bool FromV8(v8::Isolate* isolate, v8::Local val, int32_t* out); }; template<> struct GIN_EXPORT Converter { static v8::Local ToV8(v8::Isolate* isolate, uint32_t val); static bool FromV8(v8::Isolate* isolate, v8::Local val, uint32_t* out); }; template<> struct GIN_EXPORT Converter { // Warning: JavaScript cannot represent 64 integers precisely. static v8::Local ToV8(v8::Isolate* isolate, int64_t val); static bool FromV8(v8::Isolate* isolate, v8::Local val, int64_t* out); }; template<> struct GIN_EXPORT Converter { // Warning: JavaScript cannot represent 64 integers precisely. static v8::Local ToV8(v8::Isolate* isolate, uint64_t val); static bool FromV8(v8::Isolate* isolate, v8::Local val, uint64_t* out); }; template<> struct GIN_EXPORT Converter { static v8::Local ToV8(v8::Isolate* isolate, float val); static bool FromV8(v8::Isolate* isolate, v8::Local val, float* out); }; template<> struct GIN_EXPORT Converter { static v8::Local ToV8(v8::Isolate* isolate, double val); static bool FromV8(v8::Isolate* isolate, v8::Local val, double* out); }; template <> struct GIN_EXPORT Converter { // This crashes when val.size() > v8::String::kMaxLength. static v8::Local ToV8(v8::Isolate* isolate, const std::string_view& val); // No conversion out is possible because StringPiece does not contain storage. }; template<> struct GIN_EXPORT Converter { // This crashes when val.size() > v8::String::kMaxLength. static v8::Local ToV8(v8::Isolate* isolate, const std::string& val); static bool FromV8(v8::Isolate* isolate, v8::Local val, std::string* out); }; template <> struct GIN_EXPORT Converter { static v8::Local ToV8(v8::Isolate* isolate, const std::u16string& val); static bool FromV8(v8::Isolate* isolate, v8::Local val, std::u16string* out); }; // Converter for C++ TimeTicks to Javascript BigInt (unit: microseconds). // TimeTicks can't be converted using the existing Converter because // the target type will be Number and will lose precision. template <> struct GIN_EXPORT Converter { static v8::Local ToV8(v8::Isolate* isolate, base::TimeTicks val); }; template <> struct GIN_EXPORT Converter> { static v8::Local ToV8(v8::Isolate* isolate, v8::Local val); static bool FromV8(v8::Isolate* isolate, v8::Local val, v8::Local* out); }; template<> struct GIN_EXPORT Converter > { static v8::Local ToV8(v8::Isolate* isolate, v8::Local val); static bool FromV8(v8::Isolate* isolate, v8::Local val, v8::Local* out); }; template <> struct GIN_EXPORT Converter> { static v8::Local ToV8(v8::Isolate* isolate, v8::Local val); static bool FromV8(v8::Isolate* isolate, v8::Local val, v8::Local* out); }; template<> struct GIN_EXPORT Converter > { static v8::Local ToV8(v8::Isolate* isolate, v8::Local val); static bool FromV8(v8::Isolate* isolate, v8::Local val, v8::Local* out); }; template<> struct GIN_EXPORT Converter > { static v8::Local ToV8(v8::Isolate* isolate, v8::Local val); static bool FromV8(v8::Isolate* isolate, v8::Local val, v8::Local* out); }; template<> struct GIN_EXPORT Converter > { static v8::Local ToV8(v8::Isolate* isolate, v8::Local val); static bool FromV8(v8::Isolate* isolate, v8::Local val, v8::Local* out); }; template struct Converter > { static std::conditional_t, v8::MaybeLocal, v8::Local> ToV8(v8::Isolate* isolate, const std::vector& val) { v8::Local context = isolate->GetCurrentContext(); v8::Local result( v8::Array::New(isolate, static_cast(val.size()))); for (uint32_t i = 0; i < val.size(); ++i) { v8::MaybeLocal maybe = Converter::ToV8(isolate, val[i]); v8::Local element; if (!maybe.ToLocal(&element)) return {}; bool property_created; if (!result->CreateDataProperty(context, i, element) .To(&property_created) || !property_created) { NOTREACHED() << "CreateDataProperty should always succeed here."; } } return result; } static bool FromV8(v8::Isolate* isolate, v8::Local val, std::vector* out) { if (!val->IsArray()) return false; std::vector result; v8::Local array(v8::Local::Cast(val)); uint32_t length = array->Length(); for (uint32_t i = 0; i < length; ++i) { v8::Local v8_item; if (!array->Get(isolate->GetCurrentContext(), i).ToLocal(&v8_item)) return false; T item; if (!Converter::FromV8(isolate, v8_item, &item)) return false; result.push_back(std::move(item)); } out->swap(result); return true; } }; template struct Converter> { static std::conditional_t>, v8::MaybeLocal, v8::Local> ToV8(v8::Isolate* isolate, const v8::LocalVector& val) { v8::Local context = isolate->GetCurrentContext(); v8::Local result( v8::Array::New(isolate, static_cast(val.size()))); for (uint32_t i = 0; i < val.size(); ++i) { v8::MaybeLocal maybe = Converter>::ToV8(isolate, val[i]); v8::Local element; if (!maybe.ToLocal(&element)) { return {}; } bool property_created; if (!result->CreateDataProperty(context, i, element) .To(&property_created) || !property_created) { NOTREACHED() << "CreateDataProperty should always succeed here."; } } return result; } static bool FromV8(v8::Isolate* isolate, v8::Local val, v8::LocalVector* out) { if (!val->IsArray()) { return false; } v8::LocalVector result(isolate); v8::Local array(v8::Local::Cast(val)); uint32_t length = array->Length(); for (uint32_t i = 0; i < length; ++i) { v8::Local v8_item; if (!array->Get(isolate->GetCurrentContext(), i).ToLocal(&v8_item)) { return false; } v8::Local item; if (!Converter>::FromV8(isolate, v8_item, &item)) { return false; } result.push_back(item); } out->swap(result); return true; } }; // Convenience functions that deduce T. template std::conditional_t, v8::MaybeLocal, v8::Local> ConvertToV8(v8::Isolate* isolate, const T& input) { return Converter::ToV8(isolate, input); } template bool TryConvertToV8(v8::Isolate* isolate, const T& input, v8::Local* output) { if constexpr (internal::ToV8ReturnsMaybe) { return ConvertToV8(isolate, input).ToLocal(output); } else { *output = ConvertToV8(isolate, input); return true; } } // This crashes when input.size() > v8::String::kMaxLength. GIN_EXPORT inline v8::Local StringToV8( v8::Isolate* isolate, const std::string_view& input) { return ConvertToV8(isolate, input).As(); } // This crashes when input.size() > v8::String::kMaxLength. GIN_EXPORT v8::Local StringToSymbol(v8::Isolate* isolate, const std::string_view& val); // This crashes when input.size() > v8::String::kMaxLength. GIN_EXPORT v8::Local StringToSymbol(v8::Isolate* isolate, const std::u16string_view& val); GIN_EXPORT base::Location V8ToBaseLocation(const v8::SourceLocation& location); template bool ConvertFromV8(v8::Isolate* isolate, v8::Local input, T* result) { DCHECK(isolate); return Converter::FromV8(isolate, input, result); } GIN_EXPORT std::string V8ToString(v8::Isolate* isolate, v8::Local value); } // namespace gin #endif // GIN_CONVERTER_H_