blob: 88ed39f337d5e9a1004d4e270f2bd020251ee518 [file] [log] [blame]
Avi Drissman468e51b62022-09-13 20:47:011// Copyright 2013 The Chromium Authors
[email protected]a22998a2013-11-10 05:00:502// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef GIN_CONVERTER_H_
6#define GIN_CONVERTER_H_
7
avi90e658dd2015-12-21 07:16:198#include <stdint.h>
9
Jeremy Romanee67271a2023-11-14 16:36:2210#include <concepts>
Hans Wennborg5cd6d192020-06-18 11:14:5611#include <ostream>
[email protected]a22998a2013-11-10 05:00:5012#include <string>
Jeremy Romaneb8a2f172018-01-29 17:33:4013#include <type_traits>
Joel Klinghed99d2a1592023-11-07 19:22:3214#include <utility>
[email protected]a22998a2013-11-10 05:00:5015#include <vector>
16
Hans Wennborgc8b134b2020-06-19 21:15:3917#include "base/check.h"
François Doraybcd7d6b2024-02-26 16:49:5218#include "base/location.h"
Hans Wennborgc8b134b2020-06-19 21:15:3919#include "base/notreached.h"
[email protected]b520e132013-11-29 03:21:4820#include "base/strings/string_piece.h"
[email protected]48c21632013-12-12 21:32:3421#include "gin/gin_export.h"
Dan Elphick05acd602021-08-30 15:22:0722#include "v8/include/v8-container.h"
23#include "v8/include/v8-forward.h"
24#include "v8/include/v8-isolate.h"
François Doraybcd7d6b2024-02-26 16:49:5225#include "v8/include/v8-source-location.h"
[email protected]a22998a2013-11-10 05:00:5026
Keren Zhu1deb4672022-01-14 19:11:5127namespace base {
28class TimeTicks;
29}
30
[email protected]a22998a2013-11-10 05:00:5031namespace gin {
32
bashidbd2ef9bb2015-06-02 01:39:3233template<typename KeyType>
34bool SetProperty(v8::Isolate* isolate,
35 v8::Local<v8::Object> object,
36 KeyType key,
37 v8::Local<v8::Value> value) {
rdevlin.cronin415b73b2015-11-13 01:14:4738 auto maybe =
39 object->DefineOwnProperty(isolate->GetCurrentContext(), key, value);
bashidbd2ef9bb2015-06-02 01:39:3240 return !maybe.IsNothing() && maybe.FromJust();
41}
42
[email protected]cf76c84a2013-12-06 14:07:0743template<typename T, typename Enable = void>
[email protected]a22998a2013-11-10 05:00:5044struct Converter {};
45
Jeremy Romanee67271a2023-11-14 16:36:2246namespace internal {
47
48template <typename T>
49concept ToV8ReturnsMaybe = requires(v8::Isolate* isolate, T value) {
50 {
51 Converter<T>::ToV8(isolate, value)
52 } -> std::same_as<v8::MaybeLocal<v8::Value>>;
53};
54
55} // namespace internal
56
[email protected]a22998a2013-11-10 05:00:5057template<>
[email protected]48c21632013-12-12 21:32:3458struct GIN_EXPORT Converter<bool> {
deepak.sfaaa1b62015-04-30 07:30:4859 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
[email protected]a22998a2013-11-10 05:00:5060 bool val);
[email protected]7618ebbb2013-11-27 03:38:2661 static bool FromV8(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:4862 v8::Local<v8::Value> val,
[email protected]a22998a2013-11-10 05:00:5063 bool* out);
64};
65
66template<>
[email protected]48c21632013-12-12 21:32:3467struct GIN_EXPORT Converter<int32_t> {
deepak.sfaaa1b62015-04-30 07:30:4868 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
[email protected]a22998a2013-11-10 05:00:5069 int32_t val);
[email protected]7618ebbb2013-11-27 03:38:2670 static bool FromV8(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:4871 v8::Local<v8::Value> val,
[email protected]a22998a2013-11-10 05:00:5072 int32_t* out);
73};
74
75template<>
[email protected]48c21632013-12-12 21:32:3476struct GIN_EXPORT Converter<uint32_t> {
deepak.sfaaa1b62015-04-30 07:30:4877 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
[email protected]a22998a2013-11-10 05:00:5078 uint32_t val);
[email protected]7618ebbb2013-11-27 03:38:2679 static bool FromV8(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:4880 v8::Local<v8::Value> val,
[email protected]a22998a2013-11-10 05:00:5081 uint32_t* out);
82};
83
84template<>
[email protected]48c21632013-12-12 21:32:3485struct GIN_EXPORT Converter<int64_t> {
[email protected]e87f3122013-11-12 00:41:2786 // Warning: JavaScript cannot represent 64 integers precisely.
deepak.sfaaa1b62015-04-30 07:30:4887 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
[email protected]e87f3122013-11-12 00:41:2788 int64_t val);
[email protected]7618ebbb2013-11-27 03:38:2689 static bool FromV8(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:4890 v8::Local<v8::Value> val,
[email protected]e87f3122013-11-12 00:41:2791 int64_t* out);
92};
93
94template<>
[email protected]48c21632013-12-12 21:32:3495struct GIN_EXPORT Converter<uint64_t> {
[email protected]e87f3122013-11-12 00:41:2796 // Warning: JavaScript cannot represent 64 integers precisely.
deepak.sfaaa1b62015-04-30 07:30:4897 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
[email protected]e87f3122013-11-12 00:41:2798 uint64_t val);
[email protected]7618ebbb2013-11-27 03:38:2699 static bool FromV8(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:48100 v8::Local<v8::Value> val,
[email protected]e87f3122013-11-12 00:41:27101 uint64_t* out);
102};
103
104template<>
[email protected]d73341d12013-12-21 00:48:46105struct GIN_EXPORT Converter<float> {
deepak.sfaaa1b62015-04-30 07:30:48106 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
[email protected]d73341d12013-12-21 00:48:46107 float val);
108 static bool FromV8(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:48109 v8::Local<v8::Value> val,
[email protected]d73341d12013-12-21 00:48:46110 float* out);
111};
112
113template<>
[email protected]48c21632013-12-12 21:32:34114struct GIN_EXPORT Converter<double> {
deepak.sfaaa1b62015-04-30 07:30:48115 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
[email protected]a22998a2013-11-10 05:00:50116 double val);
[email protected]7618ebbb2013-11-27 03:38:26117 static bool FromV8(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:48118 v8::Local<v8::Value> val,
[email protected]a22998a2013-11-10 05:00:50119 double* out);
120};
121
122template<>
[email protected]48c21632013-12-12 21:32:34123struct GIN_EXPORT Converter<base::StringPiece> {
bashidbd2ef9bb2015-06-02 01:39:32124 // This crashes when val.size() > v8::String::kMaxLength.
deepak.sfaaa1b62015-04-30 07:30:48125 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
[email protected]b520e132013-11-29 03:21:48126 const base::StringPiece& val);
127 // No conversion out is possible because StringPiece does not contain storage.
128};
129
130template<>
[email protected]48c21632013-12-12 21:32:34131struct GIN_EXPORT Converter<std::string> {
bashidbd2ef9bb2015-06-02 01:39:32132 // This crashes when val.size() > v8::String::kMaxLength.
deepak.sfaaa1b62015-04-30 07:30:48133 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
[email protected]a22998a2013-11-10 05:00:50134 const std::string& val);
[email protected]7618ebbb2013-11-27 03:38:26135 static bool FromV8(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:48136 v8::Local<v8::Value> val,
[email protected]a22998a2013-11-10 05:00:50137 std::string* out);
138};
139
Shimi Zhang15708bfc2019-08-13 19:24:48140template <>
Jan Wilken Dörrie739ccc212021-03-11 18:13:05141struct GIN_EXPORT Converter<std::u16string> {
Shimi Zhang15708bfc2019-08-13 19:24:48142 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
Jan Wilken Dörrie739ccc212021-03-11 18:13:05143 const std::u16string& val);
Shimi Zhang15708bfc2019-08-13 19:24:48144 static bool FromV8(v8::Isolate* isolate,
145 v8::Local<v8::Value> val,
Jan Wilken Dörrie739ccc212021-03-11 18:13:05146 std::u16string* out);
Shimi Zhang15708bfc2019-08-13 19:24:48147};
148
Keren Zhu1deb4672022-01-14 19:11:51149// Converter for C++ TimeTicks to Javascript BigInt (unit: microseconds).
150// TimeTicks can't be converted using the existing Converter<int64_t> because
151// the target type will be Number and will lose precision.
152template <>
153struct GIN_EXPORT Converter<base::TimeTicks> {
154 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, base::TimeTicks val);
155};
156
Shimi Zhang15708bfc2019-08-13 19:24:48157template <>
158struct GIN_EXPORT Converter<v8::Local<v8::Function>> {
Nitish Sakhawalkarf7bbaa522019-02-11 16:19:09159 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
160 v8::Local<v8::Function> val);
[email protected]7618ebbb2013-11-27 03:38:26161 static bool FromV8(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:48162 v8::Local<v8::Value> val,
163 v8::Local<v8::Function>* out);
[email protected]a22998a2013-11-10 05:00:50164};
165
166template<>
deepak.sfaaa1b62015-04-30 07:30:48167struct GIN_EXPORT Converter<v8::Local<v8::Object> > {
168 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
169 v8::Local<v8::Object> val);
[email protected]7618ebbb2013-11-27 03:38:26170 static bool FromV8(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:48171 v8::Local<v8::Value> val,
172 v8::Local<v8::Object>* out);
[email protected]a22998a2013-11-10 05:00:50173};
174
Scott Grahamd2f4ed4b2018-10-17 01:57:27175template <>
176struct GIN_EXPORT Converter<v8::Local<v8::Promise>> {
177 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
178 v8::Local<v8::Promise> val);
179 static bool FromV8(v8::Isolate* isolate,
180 v8::Local<v8::Value> val,
181 v8::Local<v8::Promise>* out);
182};
183
[email protected]97f21ca2013-11-17 17:46:07184template<>
deepak.sfaaa1b62015-04-30 07:30:48185struct GIN_EXPORT Converter<v8::Local<v8::ArrayBuffer> > {
186 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
187 v8::Local<v8::ArrayBuffer> val);
[email protected]7618ebbb2013-11-27 03:38:26188 static bool FromV8(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:48189 v8::Local<v8::Value> val,
190 v8::Local<v8::ArrayBuffer>* out);
[email protected]ec95fdf2013-11-24 19:10:11191};
192
193template<>
deepak.sfaaa1b62015-04-30 07:30:48194struct GIN_EXPORT Converter<v8::Local<v8::External> > {
195 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
196 v8::Local<v8::External> val);
[email protected]7618ebbb2013-11-27 03:38:26197 static bool FromV8(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:48198 v8::Local<v8::Value> val,
199 v8::Local<v8::External>* out);
[email protected]97f21ca2013-11-17 17:46:07200};
201
202template<>
deepak.sfaaa1b62015-04-30 07:30:48203struct GIN_EXPORT Converter<v8::Local<v8::Value> > {
204 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
205 v8::Local<v8::Value> val);
[email protected]7618ebbb2013-11-27 03:38:26206 static bool FromV8(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:48207 v8::Local<v8::Value> val,
208 v8::Local<v8::Value>* out);
[email protected]97f21ca2013-11-17 17:46:07209};
210
[email protected]a22998a2013-11-10 05:00:50211template<typename T>
212struct Converter<std::vector<T> > {
Jeremy Romanee67271a2023-11-14 16:36:22213 static std::conditional_t<internal::ToV8ReturnsMaybe<T>,
Jeremy Romaneb8a2f172018-01-29 17:33:40214 v8::MaybeLocal<v8::Value>,
215 v8::Local<v8::Value>>
216 ToV8(v8::Isolate* isolate, const std::vector<T>& val) {
217 v8::Local<v8::Context> context = isolate->GetCurrentContext();
deepak.sfaaa1b62015-04-30 07:30:48218 v8::Local<v8::Array> result(
[email protected]91cd4fe2013-11-28 09:31:58219 v8::Array::New(isolate, static_cast<int>(val.size())));
bashidbd2ef9bb2015-06-02 01:39:32220 for (uint32_t i = 0; i < val.size(); ++i) {
Jeremy Romaneb8a2f172018-01-29 17:33:40221 v8::MaybeLocal<v8::Value> maybe = Converter<T>::ToV8(isolate, val[i]);
222 v8::Local<v8::Value> element;
223 if (!maybe.ToLocal(&element))
224 return {};
225 bool property_created;
226 if (!result->CreateDataProperty(context, i, element)
227 .To(&property_created) ||
228 !property_created) {
229 NOTREACHED() << "CreateDataProperty should always succeed here.";
230 }
[email protected]a22998a2013-11-10 05:00:50231 }
232 return result;
233 }
234
[email protected]7618ebbb2013-11-27 03:38:26235 static bool FromV8(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:48236 v8::Local<v8::Value> val,
[email protected]a22998a2013-11-10 05:00:50237 std::vector<T>* out) {
238 if (!val->IsArray())
239 return false;
240
241 std::vector<T> result;
deepak.sfaaa1b62015-04-30 07:30:48242 v8::Local<v8::Array> array(v8::Local<v8::Array>::Cast(val));
[email protected]a22998a2013-11-10 05:00:50243 uint32_t length = array->Length();
244 for (uint32_t i = 0; i < length; ++i) {
bashidbd2ef9bb2015-06-02 01:39:32245 v8::Local<v8::Value> v8_item;
246 if (!array->Get(isolate->GetCurrentContext(), i).ToLocal(&v8_item))
247 return false;
[email protected]a22998a2013-11-10 05:00:50248 T item;
bashidbd2ef9bb2015-06-02 01:39:32249 if (!Converter<T>::FromV8(isolate, v8_item, &item))
[email protected]a22998a2013-11-10 05:00:50250 return false;
Joel Klinghed99d2a1592023-11-07 19:22:32251 result.push_back(std::move(item));
[email protected]a22998a2013-11-10 05:00:50252 }
253
254 out->swap(result);
255 return true;
256 }
257};
258
Nikolaos Papaspyrou5ce2a2f2023-10-19 09:09:00259template <typename T>
260struct Converter<v8::LocalVector<T>> {
Jeremy Romanee67271a2023-11-14 16:36:22261 static std::conditional_t<internal::ToV8ReturnsMaybe<v8::Local<T>>,
Nikolaos Papaspyrou5ce2a2f2023-10-19 09:09:00262 v8::MaybeLocal<v8::Value>,
263 v8::Local<v8::Value>>
264 ToV8(v8::Isolate* isolate, const v8::LocalVector<T>& val) {
265 v8::Local<v8::Context> context = isolate->GetCurrentContext();
266 v8::Local<v8::Array> result(
267 v8::Array::New(isolate, static_cast<int>(val.size())));
268 for (uint32_t i = 0; i < val.size(); ++i) {
269 v8::MaybeLocal<v8::Value> maybe =
270 Converter<v8::Local<T>>::ToV8(isolate, val[i]);
271 v8::Local<v8::Value> element;
272 if (!maybe.ToLocal(&element)) {
273 return {};
274 }
275 bool property_created;
276 if (!result->CreateDataProperty(context, i, element)
277 .To(&property_created) ||
278 !property_created) {
279 NOTREACHED() << "CreateDataProperty should always succeed here.";
280 }
281 }
282 return result;
283 }
284
285 static bool FromV8(v8::Isolate* isolate,
286 v8::Local<v8::Value> val,
287 v8::LocalVector<T>* out) {
288 if (!val->IsArray()) {
289 return false;
290 }
291
292 v8::LocalVector<T> result(isolate);
293 v8::Local<v8::Array> array(v8::Local<v8::Array>::Cast(val));
294 uint32_t length = array->Length();
295 for (uint32_t i = 0; i < length; ++i) {
296 v8::Local<v8::Value> v8_item;
297 if (!array->Get(isolate->GetCurrentContext(), i).ToLocal(&v8_item)) {
298 return false;
299 }
300 v8::Local<T> item;
301 if (!Converter<v8::Local<T>>::FromV8(isolate, v8_item, &item)) {
302 return false;
303 }
304 result.push_back(item);
305 }
306
307 out->swap(result);
308 return true;
309 }
310};
311
[email protected]a22998a2013-11-10 05:00:50312// Convenience functions that deduce T.
Jeremy Romaneb8a2f172018-01-29 17:33:40313template <typename T>
Jeremy Romanee67271a2023-11-14 16:36:22314std::conditional_t<internal::ToV8ReturnsMaybe<T>,
Jeremy Romaneb8a2f172018-01-29 17:33:40315 v8::MaybeLocal<v8::Value>,
316 v8::Local<v8::Value>>
Jeremy Apthorp6a3480292018-04-26 18:53:59317ConvertToV8(v8::Isolate* isolate, const T& input) {
[email protected]a22998a2013-11-10 05:00:50318 return Converter<T>::ToV8(isolate, input);
319}
320
Jeremy Roman44bda444b2018-03-16 17:33:45321template <typename T>
Jeremy Romanee67271a2023-11-14 16:36:22322bool TryConvertToV8(v8::Isolate* isolate,
323 const T& input,
324 v8::Local<v8::Value>* output) {
325 if constexpr (internal::ToV8ReturnsMaybe<T>) {
326 return ConvertToV8(isolate, input).ToLocal(output);
327 } else {
328 *output = ConvertToV8(isolate, input);
329 return true;
330 }
bashidbd2ef9bb2015-06-02 01:39:32331}
332
333// This crashes when input.size() > v8::String::kMaxLength.
deepak.sfaaa1b62015-04-30 07:30:48334GIN_EXPORT inline v8::Local<v8::String> StringToV8(
[email protected]48c21632013-12-12 21:32:34335 v8::Isolate* isolate,
336 const base::StringPiece& input) {
[email protected]a22998a2013-11-10 05:00:50337 return ConvertToV8(isolate, input).As<v8::String>();
338}
339
bashidbd2ef9bb2015-06-02 01:39:32340// This crashes when input.size() > v8::String::kMaxLength.
deepak.sfaaa1b62015-04-30 07:30:48341GIN_EXPORT v8::Local<v8::String> StringToSymbol(v8::Isolate* isolate,
[email protected]48c21632013-12-12 21:32:34342 const base::StringPiece& val);
[email protected]e87f3122013-11-12 00:41:27343
Shimi Zhang15708bfc2019-08-13 19:24:48344// This crashes when input.size() > v8::String::kMaxLength.
345GIN_EXPORT v8::Local<v8::String> StringToSymbol(v8::Isolate* isolate,
346 const base::StringPiece16& val);
347
François Doraybcd7d6b2024-02-26 16:49:52348GIN_EXPORT base::Location V8ToBaseLocation(const v8::SourceLocation& location);
349
[email protected]a22998a2013-11-10 05:00:50350template<typename T>
deepak.sfaaa1b62015-04-30 07:30:48351bool ConvertFromV8(v8::Isolate* isolate, v8::Local<v8::Value> input,
[email protected]7618ebbb2013-11-27 03:38:26352 T* result) {
Dan Elphick712beaa2018-07-24 17:37:24353 DCHECK(isolate);
[email protected]7618ebbb2013-11-27 03:38:26354 return Converter<T>::FromV8(isolate, input, result);
[email protected]a22998a2013-11-10 05:00:50355}
356
Dan Elphick38a508052018-07-23 22:19:53357GIN_EXPORT std::string V8ToString(v8::Isolate* isolate,
358 v8::Local<v8::Value> value);
[email protected]2f703422013-11-25 21:26:15359
[email protected]a22998a2013-11-10 05:00:50360} // namespace gin
361
362#endif // GIN_CONVERTER_H_