1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef GIN_CONVERTER_H_
6 #define GIN_CONVERTER_H_
12 #include <type_traits>
15 #include "base/check.h"
16 #include "base/notreached.h"
17 #include "base/strings/string_piece.h"
18 #include "gin/gin_export.h"
19 #include "v8/include/v8-container.h"
20 #include "v8/include/v8-forward.h"
21 #include "v8/include/v8-isolate.h"
29 template<typename KeyType>
30 bool SetProperty(v8::Isolate* isolate,
31 v8::Local<v8::Object> object,
33 v8::Local<v8::Value> value) {
35 object->DefineOwnProperty(isolate->GetCurrentContext(), key, value);
36 return !maybe.IsNothing() && maybe.FromJust();
39 template <typename T, typename Enable = void>
40 struct ToV8ReturnsMaybe {
41 static const bool value = false;
44 template<typename T, typename Enable = void>
48 struct GIN_EXPORT Converter<bool> {
49 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
51 static bool FromV8(v8::Isolate* isolate,
52 v8::Local<v8::Value> val,
57 struct GIN_EXPORT Converter<int32_t> {
58 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
60 static bool FromV8(v8::Isolate* isolate,
61 v8::Local<v8::Value> val,
66 struct GIN_EXPORT Converter<uint32_t> {
67 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
69 static bool FromV8(v8::Isolate* isolate,
70 v8::Local<v8::Value> val,
75 struct GIN_EXPORT Converter<int64_t> {
76 // Warning: JavaScript cannot represent 64 integers precisely.
77 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
79 static bool FromV8(v8::Isolate* isolate,
80 v8::Local<v8::Value> val,
85 struct GIN_EXPORT Converter<uint64_t> {
86 // Warning: JavaScript cannot represent 64 integers precisely.
87 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
89 static bool FromV8(v8::Isolate* isolate,
90 v8::Local<v8::Value> val,
95 struct GIN_EXPORT Converter<float> {
96 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
98 static bool FromV8(v8::Isolate* isolate,
99 v8::Local<v8::Value> val,
104 struct GIN_EXPORT Converter<double> {
105 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
107 static bool FromV8(v8::Isolate* isolate,
108 v8::Local<v8::Value> val,
113 struct GIN_EXPORT Converter<base::StringPiece> {
114 // This crashes when val.size() > v8::String::kMaxLength.
115 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
116 const base::StringPiece& val);
117 // No conversion out is possible because StringPiece does not contain storage.
121 struct GIN_EXPORT Converter<std::string> {
122 // This crashes when val.size() > v8::String::kMaxLength.
123 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
124 const std::string& val);
125 static bool FromV8(v8::Isolate* isolate,
126 v8::Local<v8::Value> val,
131 struct GIN_EXPORT Converter<std::u16string> {
132 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
133 const std::u16string& val);
134 static bool FromV8(v8::Isolate* isolate,
135 v8::Local<v8::Value> val,
136 std::u16string* out);
139 // Converter for C++ TimeTicks to Javascript BigInt (unit: microseconds).
140 // TimeTicks can't be converted using the existing Converter<int64_t> because
141 // the target type will be Number and will lose precision.
143 struct GIN_EXPORT Converter<base::TimeTicks> {
144 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, base::TimeTicks val);
148 struct GIN_EXPORT Converter<v8::Local<v8::Function>> {
149 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
150 v8::Local<v8::Function> val);
151 static bool FromV8(v8::Isolate* isolate,
152 v8::Local<v8::Value> val,
153 v8::Local<v8::Function>* out);
157 struct GIN_EXPORT Converter<v8::Local<v8::Object> > {
158 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
159 v8::Local<v8::Object> val);
160 static bool FromV8(v8::Isolate* isolate,
161 v8::Local<v8::Value> val,
162 v8::Local<v8::Object>* out);
166 struct GIN_EXPORT Converter<v8::Local<v8::Promise>> {
167 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
168 v8::Local<v8::Promise> val);
169 static bool FromV8(v8::Isolate* isolate,
170 v8::Local<v8::Value> val,
171 v8::Local<v8::Promise>* out);
175 struct GIN_EXPORT Converter<v8::Local<v8::ArrayBuffer> > {
176 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
177 v8::Local<v8::ArrayBuffer> val);
178 static bool FromV8(v8::Isolate* isolate,
179 v8::Local<v8::Value> val,
180 v8::Local<v8::ArrayBuffer>* out);
184 struct GIN_EXPORT Converter<v8::Local<v8::External> > {
185 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
186 v8::Local<v8::External> val);
187 static bool FromV8(v8::Isolate* isolate,
188 v8::Local<v8::Value> val,
189 v8::Local<v8::External>* out);
193 struct GIN_EXPORT Converter<v8::Local<v8::Value> > {
194 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
195 v8::Local<v8::Value> val);
196 static bool FromV8(v8::Isolate* isolate,
197 v8::Local<v8::Value> val,
198 v8::Local<v8::Value>* out);
202 struct Converter<std::vector<T> > {
203 static std::conditional_t<ToV8ReturnsMaybe<T>::value,
204 v8::MaybeLocal<v8::Value>,
205 v8::Local<v8::Value>>
206 ToV8(v8::Isolate* isolate, const std::vector<T>& val) {
207 v8::Local<v8::Context> context = isolate->GetCurrentContext();
208 v8::Local<v8::Array> result(
209 v8::Array::New(isolate, static_cast<int>(val.size())));
210 for (uint32_t i = 0; i < val.size(); ++i) {
211 v8::MaybeLocal<v8::Value> maybe = Converter<T>::ToV8(isolate, val[i]);
212 v8::Local<v8::Value> element;
213 if (!maybe.ToLocal(&element))
215 bool property_created;
216 if (!result->CreateDataProperty(context, i, element)
217 .To(&property_created) ||
219 NOTREACHED() << "CreateDataProperty should always succeed here.";
225 static bool FromV8(v8::Isolate* isolate,
226 v8::Local<v8::Value> val,
227 std::vector<T>* out) {
231 std::vector<T> result;
232 v8::Local<v8::Array> array(v8::Local<v8::Array>::Cast(val));
233 uint32_t length = array->Length();
234 for (uint32_t i = 0; i < length; ++i) {
235 v8::Local<v8::Value> v8_item;
236 if (!array->Get(isolate->GetCurrentContext(), i).ToLocal(&v8_item))
239 if (!Converter<T>::FromV8(isolate, v8_item, &item))
241 result.push_back(item);
249 template <typename T>
250 struct Converter<v8::LocalVector<T>> {
251 static std::conditional_t<ToV8ReturnsMaybe<v8::Local<T>>::value,
252 v8::MaybeLocal<v8::Value>,
253 v8::Local<v8::Value>>
254 ToV8(v8::Isolate* isolate, const v8::LocalVector<T>& val) {
255 v8::Local<v8::Context> context = isolate->GetCurrentContext();
256 v8::Local<v8::Array> result(
257 v8::Array::New(isolate, static_cast<int>(val.size())));
258 for (uint32_t i = 0; i < val.size(); ++i) {
259 v8::MaybeLocal<v8::Value> maybe =
260 Converter<v8::Local<T>>::ToV8(isolate, val[i]);
261 v8::Local<v8::Value> element;
262 if (!maybe.ToLocal(&element)) {
265 bool property_created;
266 if (!result->CreateDataProperty(context, i, element)
267 .To(&property_created) ||
269 NOTREACHED() << "CreateDataProperty should always succeed here.";
275 static bool FromV8(v8::Isolate* isolate,
276 v8::Local<v8::Value> val,
277 v8::LocalVector<T>* out) {
278 if (!val->IsArray()) {
282 v8::LocalVector<T> result(isolate);
283 v8::Local<v8::Array> array(v8::Local<v8::Array>::Cast(val));
284 uint32_t length = array->Length();
285 for (uint32_t i = 0; i < length; ++i) {
286 v8::Local<v8::Value> v8_item;
287 if (!array->Get(isolate->GetCurrentContext(), i).ToLocal(&v8_item)) {
291 if (!Converter<v8::Local<T>>::FromV8(isolate, v8_item, &item)) {
294 result.push_back(item);
303 struct ToV8ReturnsMaybe<std::vector<T>> {
304 static const bool value = ToV8ReturnsMaybe<T>::value;
307 template <typename T>
308 struct ToV8ReturnsMaybe<v8::LocalVector<T>> {
309 static const bool value = ToV8ReturnsMaybe<T>::value;
312 // Convenience functions that deduce T.
313 template <typename T>
314 std::conditional_t<ToV8ReturnsMaybe<T>::value,
315 v8::MaybeLocal<v8::Value>,
316 v8::Local<v8::Value>>
317 ConvertToV8(v8::Isolate* isolate, const T& input) {
318 return Converter<T>::ToV8(isolate, input);
321 template <typename T>
322 std::enable_if_t<ToV8ReturnsMaybe<T>::value, bool> TryConvertToV8(
323 v8::Isolate* isolate,
325 v8::Local<v8::Value>* output) {
326 return ConvertToV8(isolate, input).ToLocal(output);
329 template <typename T>
330 std::enable_if_t<!ToV8ReturnsMaybe<T>::value, bool> TryConvertToV8(
331 v8::Isolate* isolate,
333 v8::Local<v8::Value>* output) {
334 *output = ConvertToV8(isolate, input);
338 // This crashes when input.size() > v8::String::kMaxLength.
339 GIN_EXPORT inline v8::Local<v8::String> StringToV8(
340 v8::Isolate* isolate,
341 const base::StringPiece& input) {
342 return ConvertToV8(isolate, input).As<v8::String>();
345 // This crashes when input.size() > v8::String::kMaxLength.
346 GIN_EXPORT v8::Local<v8::String> StringToSymbol(v8::Isolate* isolate,
347 const base::StringPiece& val);
349 // This crashes when input.size() > v8::String::kMaxLength.
350 GIN_EXPORT v8::Local<v8::String> StringToSymbol(v8::Isolate* isolate,
351 const base::StringPiece16& val);
354 bool ConvertFromV8(v8::Isolate* isolate, v8::Local<v8::Value> input,
357 return Converter<T>::FromV8(isolate, input, result);
360 GIN_EXPORT std::string V8ToString(v8::Isolate* isolate,
361 v8::Local<v8::Value> value);
365 #endif // GIN_CONVERTER_H_