1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef LIB_CONVERTER_TONIC_DART_CONVERTER_H_
6#define LIB_CONVERTER_TONIC_DART_CONVERTER_H_
7
8#include <string>
9#include <type_traits>
10#include <vector>
11
12#include "third_party/dart/runtime/include/dart_api.h"
13#include "tonic/common/macros.h"
14#include "tonic/logging/dart_error.h"
15
16namespace tonic {
17
18// DartConvert converts types back and forth from Sky to Dart. The template
19// parameter |T| determines what kind of type conversion to perform.
20template <typename T, typename Enable = void>
21struct DartConverter {};
22
23// This is to work around the fact that typedefs do not create new types. If you
24// have a typedef, and want it to use a different converter, specialize this
25// template and override the types here.
26// Ex:
27// typedef int ColorType; // Want to use a different converter.
28// class ColorConverterType {}; // Dummy type.
29// template<> struct DartConvertType<ColorConverterType> {
30// using ConverterType = ColorConverterType;
31// using ValueType = ColorType;
32// };
33template <typename T>
34struct DartConverterTypes {
35 using ConverterType = T;
36 using ValueType = T;
37};
38
39template <>
40struct DartConverter<void> {
41 using FfiType = void;
42 static constexpr const char* kFfiRepresentation = "Void";
43 static constexpr const char* kDartRepresentation = "void";
44 static constexpr bool kAllowedInLeafCall = true;
45 static const char* GetFfiRepresentation() { return kFfiRepresentation; }
46 static const char* GetDartRepresentation() { return kDartRepresentation; }
47 static bool AllowedInLeafCall() { return kAllowedInLeafCall; }
48};
49
50////////////////////////////////////////////////////////////////////////////////
51// Boolean
52
53template <>
54struct DartConverter<bool> {
55 using NativeType = bool;
56 using FfiType = bool;
57 static constexpr const char* kFfiRepresentation = "Bool";
58 static constexpr const char* kDartRepresentation = "bool";
59 static constexpr bool kAllowedInLeafCall = true;
60
61 static Dart_Handle ToDart(NativeType val) { return Dart_NewBoolean(value: val); }
62
63 static void SetReturnValue(Dart_NativeArguments args, bool val) {
64 Dart_SetBooleanReturnValue(args, retval: val);
65 }
66
67 static NativeType FromDart(Dart_Handle handle) {
68 bool result = 0;
69 Dart_BooleanValue(boolean_obj: handle, value: &result);
70 return result;
71 }
72
73 static NativeType FromArguments(Dart_NativeArguments args,
74 int index,
75 Dart_Handle& exception) {
76 bool result = false;
77 Dart_GetNativeBooleanArgument(args, index, value: &result);
78 return result;
79 }
80
81 static NativeType FromFfi(FfiType val) { return val; }
82 static FfiType ToFfi(NativeType val) { return val; }
83 static const char* GetFfiRepresentation() { return kFfiRepresentation; }
84 static const char* GetDartRepresentation() { return kDartRepresentation; }
85 static bool AllowedInLeafCall() { return kAllowedInLeafCall; }
86};
87
88////////////////////////////////////////////////////////////////////////////////
89// Numbers
90
91template <typename T>
92struct DartConverterInteger {
93 using FfiType = T;
94 static constexpr const char* kDartRepresentation = "int";
95 static constexpr bool kAllowedInLeafCall = true;
96
97 static Dart_Handle ToDart(T val) { return Dart_NewInteger(val); }
98
99 static void SetReturnValue(Dart_NativeArguments args, T val) {
100 Dart_SetIntegerReturnValue(args, val);
101 }
102
103 static T FromDart(Dart_Handle handle) {
104 int64_t result = 0;
105 Dart_IntegerToInt64(integer: handle, value: &result);
106 return static_cast<T>(result);
107 }
108
109 static T FromArguments(Dart_NativeArguments args,
110 int index,
111 Dart_Handle& exception) {
112 int64_t result = 0;
113 Dart_GetNativeIntegerArgument(args, index, value: &result);
114 return static_cast<T>(result);
115 }
116 static T FromFfi(FfiType val) { return val; }
117 static FfiType ToFfi(T val) { return val; }
118 static const char* GetDartRepresentation() { return kDartRepresentation; }
119 // Note: Returns the correct bit-width for the host architecture.
120 static const char* GetFfiRepresentation() {
121 if (sizeof(T) == 4) {
122 if (std::is_signed<T>()) {
123 return "Int32";
124 }
125 return "Uint32";
126 }
127 TONIC_DCHECK(sizeof(T) == 8);
128 if (std::is_signed<T>()) {
129 return "Int64";
130 }
131 return "Uint64";
132 }
133 static bool AllowedInLeafCall() { return kAllowedInLeafCall; }
134};
135
136template <>
137struct DartConverter<int> : public DartConverterInteger<int> {};
138
139template <>
140struct DartConverter<long int> : public DartConverterInteger<long int> {};
141
142template <>
143struct DartConverter<unsigned> : public DartConverterInteger<unsigned> {};
144
145template <>
146struct DartConverter<long long> : public DartConverterInteger<long long> {};
147
148template <>
149struct DartConverter<unsigned long>
150 : public DartConverterInteger<unsigned long> {};
151
152template <>
153struct DartConverter<unsigned long long> {
154 using FfiType = unsigned long long;
155 static constexpr const char* kFfiRepresentation = "Uint64";
156 static constexpr const char* kDartRepresentation = "int";
157 static constexpr bool kAllowedInLeafCall = true;
158
159 // TODO(abarth): The Dart VM API doesn't yet have an entry-point for
160 // an unsigned 64-bit type. We will need to add a Dart API for
161 // constructing an integer from uint64_t.
162 //
163 // (In the meantime, we have asserts below to check that we're never
164 // converting values that have the 64th bit set.)
165
166 static Dart_Handle ToDart(unsigned long long val) {
167 TONIC_DCHECK(val <= 0x7fffffffffffffffLL);
168 return Dart_NewInteger(value: static_cast<int64_t>(val));
169 }
170
171 static void SetReturnValue(Dart_NativeArguments args,
172 unsigned long long val) {
173 TONIC_DCHECK(val <= 0x7fffffffffffffffLL);
174 Dart_SetIntegerReturnValue(args, retval: val);
175 }
176
177 static unsigned long long FromDart(Dart_Handle handle) {
178 int64_t result = 0;
179 Dart_IntegerToInt64(integer: handle, value: &result);
180 return result;
181 }
182
183 static unsigned long long FromArguments(Dart_NativeArguments args,
184 int index,
185 Dart_Handle& exception) {
186 int64_t result = 0;
187 Dart_GetNativeIntegerArgument(args, index, value: &result);
188 return result;
189 }
190
191 static const char* GetFfiRepresentation() { return kFfiRepresentation; }
192 static const char* GetDartRepresentation() { return kDartRepresentation; }
193 static bool AllowedInLeafCall() { return kAllowedInLeafCall; }
194 static FfiType FromFfi(FfiType val) {
195 TONIC_DCHECK(val <= 0x7fffffffffffffffLL);
196 return val;
197 }
198 // FFI does a bitwise conversion from uint64_t in C to int64 in Dart.
199 static FfiType ToFfi(FfiType val) {
200 TONIC_DCHECK(val <= 0x7fffffffffffffffLL);
201 return val;
202 }
203};
204
205// There is intentionally no DartConverter<float>, to avoid UB when Dart code
206// gives us a double that is greater than the max float or less than -max float.
207template <>
208struct DartConverter<double> {
209 using FfiType = double;
210 static constexpr const char* kFfiRepresentation = "Double";
211 static constexpr const char* kDartRepresentation = "double";
212 static constexpr bool kAllowedInLeafCall = true;
213
214 static Dart_Handle ToDart(double val) { return Dart_NewDouble(value: val); }
215
216 static void SetReturnValue(Dart_NativeArguments args, double val) {
217 Dart_SetDoubleReturnValue(args, retval: val);
218 }
219
220 static double FromDart(Dart_Handle handle) {
221 double result = 0;
222 Dart_DoubleValue(double_obj: handle, value: &result);
223 return result;
224 }
225
226 static double FromArguments(Dart_NativeArguments args,
227 int index,
228 Dart_Handle& exception) {
229 double result = 0;
230 Dart_GetNativeDoubleArgument(args, index, value: &result);
231 return result;
232 }
233
234 static double FromFfi(FfiType val) { return val; }
235 static FfiType ToFfi(double val) { return val; }
236 static bool AllowedInLeafCall() { return kAllowedInLeafCall; }
237
238 static const char* GetFfiRepresentation() { return kFfiRepresentation; }
239 static const char* GetDartRepresentation() { return kDartRepresentation; }
240};
241
242////////////////////////////////////////////////////////////////////////////////
243// Enum Classes
244
245template <typename T>
246struct DartConverter<T, typename std::enable_if<std::is_enum<T>::value>::type> {
247 using FfiType = int32_t;
248 static constexpr const char* kFfiRepresentation = "Int32";
249 static constexpr const char* kDartRepresentation = "int";
250 static constexpr bool kAllowedInLeafCall = true;
251
252 static Dart_Handle ToDart(T val) {
253 return Dart_NewInteger(
254 static_cast<typename std::underlying_type<T>::type>(val));
255 }
256
257 static void SetReturnValue(Dart_NativeArguments args, T val) {
258 Dart_SetIntegerReturnValue(
259 args, static_cast<typename std::underlying_type<T>::type>(val));
260 }
261
262 static T FromDart(Dart_Handle handle) {
263 int64_t result = 0;
264 Dart_IntegerToInt64(integer: handle, value: &result);
265 return static_cast<T>(result);
266 }
267
268 static T FromArguments(Dart_NativeArguments args,
269 int index,
270 Dart_Handle& exception) {
271 int64_t result = 0;
272 Dart_GetNativeIntegerArgument(args, index, value: &result);
273 return static_cast<T>(result);
274 }
275
276 static T FromFfi(FfiType val) { return static_cast<T>(val); }
277 static const char* GetFfiRepresentation() { return kFfiRepresentation; }
278 static const char* GetDartRepresentation() { return kDartRepresentation; }
279 static bool AllowedInLeafCall() { return kAllowedInLeafCall; }
280};
281
282////////////////////////////////////////////////////////////////////////////////
283// Strings
284
285template <>
286struct DartConverter<std::string> {
287 using NativeType = std::string;
288 using FfiType = Dart_Handle;
289 static constexpr const char* kFfiRepresentation = "Handle";
290 static constexpr const char* kDartRepresentation = "String";
291 static constexpr bool kAllowedInLeafCall = false;
292
293 static Dart_Handle ToDart(const NativeType& val) {
294 return Dart_NewStringFromUTF8(utf8_array: reinterpret_cast<const uint8_t*>(val.data()),
295 length: val.length());
296 }
297
298 static void SetReturnValue(Dart_NativeArguments args, const NativeType& val) {
299 Dart_SetReturnValue(args, retval: ToDart(val));
300 }
301
302 static NativeType FromDart(Dart_Handle handle) {
303 if (Dart_IsNull(object: handle)) {
304 return std::string();
305 }
306 uint8_t* data = nullptr;
307 intptr_t length = 0;
308 if (Dart_IsError(handle: Dart_StringToUTF8(str: handle, utf8_array: &data, length: &length)))
309 return std::string();
310 return std::string(reinterpret_cast<char*>(data), length);
311 }
312
313 static NativeType FromArguments(Dart_NativeArguments args,
314 int index,
315 Dart_Handle& exception) {
316 return FromDart(handle: Dart_GetNativeArgument(args, index));
317 }
318
319 static NativeType FromFfi(FfiType val) { return FromDart(handle: val); }
320 static FfiType ToFfi(NativeType val) { return ToDart(val); }
321 static const char* GetFfiRepresentation() { return kFfiRepresentation; }
322 static const char* GetDartRepresentation() { return kDartRepresentation; }
323 static bool AllowedInLeafCall() { return kAllowedInLeafCall; }
324};
325
326template <>
327struct DartConverter<std::u16string> {
328 using NativeType = std::u16string;
329 using FfiType = Dart_Handle;
330 static constexpr const char* kFfiRepresentation = "Handle";
331 static constexpr const char* kDartRepresentation = "String";
332 static constexpr bool kAllowedInLeafCall = false;
333
334 static Dart_Handle ToDart(const NativeType& val) {
335 return Dart_NewStringFromUTF16(
336 utf16_array: reinterpret_cast<const uint16_t*>(val.data()), length: val.length());
337 }
338
339 static void SetReturnValue(Dart_NativeArguments args, const NativeType& val) {
340 Dart_SetReturnValue(args, retval: ToDart(val));
341 }
342
343 static NativeType FromDart(Dart_Handle handle) {
344 if (Dart_IsNull(object: handle)) {
345 return std::u16string();
346 }
347 intptr_t length = 0;
348 Dart_StringLength(str: handle, length: &length);
349 std::vector<uint16_t> data(length);
350 Dart_StringToUTF16(str: handle, utf16_array: data.data(), length: &length);
351 return std::u16string(reinterpret_cast<char16_t*>(data.data()), length);
352 }
353
354 static NativeType FromArguments(Dart_NativeArguments args,
355 int index,
356 Dart_Handle& exception) {
357 return FromDart(handle: Dart_GetNativeArgument(args, index));
358 }
359
360 static NativeType FromFfi(FfiType val) { return FromDart(handle: val); }
361 static FfiType ToFfi(NativeType val) { return ToDart(val); }
362 static const char* GetFfiRepresentation() { return kFfiRepresentation; }
363 static const char* GetDartRepresentation() { return kDartRepresentation; }
364 static bool AllowedInLeafCall() { return kAllowedInLeafCall; }
365};
366
367template <>
368struct DartConverter<const char*> {
369 static Dart_Handle ToDart(const char* val) {
370 return Dart_NewStringFromCString(str: val);
371 }
372
373 static void SetReturnValue(Dart_NativeArguments args, const char* val) {
374 Dart_SetReturnValue(args, retval: ToDart(val));
375 }
376
377 static const char* FromDart(Dart_Handle handle) {
378 if (Dart_IsNull(object: handle)) {
379 return nullptr;
380 }
381 const char* result = nullptr;
382 Dart_StringToCString(str: handle, cstr: &result);
383 return result;
384 }
385
386 static const char* FromArguments(Dart_NativeArguments args,
387 int index,
388 Dart_Handle& exception) {
389 return FromDart(handle: Dart_GetNativeArgument(args, index));
390 }
391};
392
393////////////////////////////////////////////////////////////////////////////////
394// Collections
395
396inline Dart_Handle LookupNonNullableType(const std::string& library_name,
397 const std::string& type_name) {
398 auto library =
399 Dart_LookupLibrary(url: DartConverter<std::string>::ToDart(val: library_name));
400 if (CheckAndHandleError(handle: library)) {
401 return library;
402 }
403 auto type_string = DartConverter<std::string>::ToDart(val: type_name);
404 if (CheckAndHandleError(handle: type_string)) {
405 return type_string;
406 }
407 auto type = Dart_GetNonNullableType(library, class_name: type_string, number_of_type_arguments: 0, type_arguments: nullptr);
408 if (CheckAndHandleError(handle: type)) {
409 return type;
410 }
411 return type;
412}
413
414template <typename T,
415 std::enable_if_t<std::is_same<std::string, T>::value, int> = 0>
416Dart_Handle ToDartTypeHandle() {
417 return LookupNonNullableType(library_name: "dart:core", type_name: "String");
418}
419
420template <typename T, std::enable_if_t<std::is_integral<T>::value, int> = 0>
421Dart_Handle ToDartTypeHandle() {
422 return LookupNonNullableType(library_name: "dart:core", type_name: "int");
423}
424
425template <typename T,
426 std::enable_if_t<std::is_floating_point<T>::value, int> = 0>
427Dart_Handle ToDartTypeHandle() {
428 return LookupNonNullableType(library_name: "dart:core", type_name: "double");
429}
430
431template <typename T>
432Dart_Handle CreateZeroInitializedDartObject(
433 Dart_Handle type_handle_or_null = ::Dart_Null()) {
434 if constexpr (std::is_same<std::string, T>::value) {
435 return ::Dart_EmptyString();
436 } else if constexpr (std::is_integral<T>::value) {
437 return ::Dart_NewIntegerFromUint64(value: 0u);
438 } else if constexpr (std::is_floating_point<T>::value) {
439 return ::Dart_NewDouble(value: 0.0);
440 } else {
441 auto object = ::Dart_New(type: type_handle_or_null, constructor_name: ::Dart_Null(), number_of_arguments: 0, arguments: nullptr);
442 CheckAndHandleError(handle: object);
443 return object;
444 }
445 return ::Dart_Null();
446}
447
448template <typename T, typename Enable = void>
449struct DartListFactory {
450 static Dart_Handle NewList(Dart_Handle type_handle, intptr_t length) {
451 bool is_nullable = false;
452 auto is_nullable_handle = ::Dart_IsNullableType(type: type_handle, result: &is_nullable);
453 if (CheckAndHandleError(handle: is_nullable_handle)) {
454 return is_nullable_handle;
455 }
456 if (is_nullable) {
457 auto list = ::Dart_NewListOfType(element_type: type_handle, length);
458 CheckAndHandleError(handle: list);
459 return list;
460 } else {
461 auto sentinel = CreateZeroInitializedDartObject<T>(type_handle);
462 if (CheckAndHandleError(sentinel)) {
463 return sentinel;
464 }
465 auto list = ::Dart_NewListOfTypeFilled(element_type: type_handle, fill_object: sentinel, length);
466 CheckAndHandleError(list);
467 return list;
468 }
469 return ::Dart_Null();
470 }
471};
472
473template <typename T>
474struct DartConverter<std::vector<T>> {
475 using FfiType = Dart_Handle;
476 static constexpr const char* kFfiRepresentation = "Handle";
477 static constexpr const char* kDartRepresentation = "List";
478 static constexpr bool kAllowedInLeafCall = false;
479
480 using ValueType = typename DartConverterTypes<T>::ValueType;
481 using ConverterType = typename DartConverterTypes<T>::ConverterType;
482
483 static Dart_Handle ToDart(const std::vector<ValueType>& val) {
484 Dart_Handle list = DartListFactory<ValueType>::NewList(
485 ToDartTypeHandle<ValueType>(), val.size());
486 if (Dart_IsError(handle: list))
487 return list;
488 for (size_t i = 0; i < val.size(); i++) {
489 Dart_Handle result =
490 Dart_ListSetAt(list, i, DartConverter<ConverterType>::ToDart(val[i]));
491 if (Dart_IsError(handle: result))
492 return result;
493 }
494 return list;
495 }
496
497 static void SetReturnValue(Dart_NativeArguments args,
498 const std::vector<ValueType>& val) {
499 Dart_SetReturnValue(args, ToDart(val));
500 }
501
502 static std::vector<ValueType> FromDart(Dart_Handle handle) {
503 std::vector<ValueType> result;
504
505 if (!Dart_IsList(object: handle))
506 return result;
507
508 intptr_t length = 0;
509 Dart_ListLength(list: handle, length: &length);
510
511 if (length == 0)
512 return result;
513
514 result.reserve(length);
515
516 std::vector<Dart_Handle> items(length);
517 Dart_Handle items_result =
518 Dart_ListGetRange(list: handle, offset: 0, length, result: items.data());
519 TONIC_DCHECK(!Dart_IsError(items_result));
520
521 for (intptr_t i = 0; i < length; ++i) {
522 TONIC_DCHECK(items[i]);
523 result.push_back(DartConverter<ConverterType>::FromDart(items[i]));
524 }
525 return result;
526 }
527
528 static std::vector<ValueType> FromArguments(Dart_NativeArguments args,
529 int index,
530 Dart_Handle& exception) {
531 return FromDart(handle: Dart_GetNativeArgument(args, index));
532 }
533
534 static std::vector<ValueType> FromFfi(FfiType val) { return FromDart(handle: val); }
535 static FfiType ToFfi(std::vector<ValueType> val) { return ToDart(val); }
536 static const char* GetFfiRepresentation() { return kFfiRepresentation; }
537 static const char* GetDartRepresentation() { return kDartRepresentation; }
538 static bool AllowedInLeafCall() { return kAllowedInLeafCall; }
539};
540
541////////////////////////////////////////////////////////////////////////////////
542// Dart_Handle
543
544template <>
545struct DartConverter<Dart_Handle> {
546 using NativeType = Dart_Handle;
547 using FfiType = Dart_Handle;
548 static constexpr const char* kFfiRepresentation = "Handle";
549 static constexpr const char* kDartRepresentation = "Object";
550 static constexpr bool kAllowedInLeafCall = false;
551
552 static Dart_Handle ToDart(NativeType val) { return val; }
553
554 static void SetReturnValue(Dart_NativeArguments args, Dart_Handle val) {
555 Dart_SetReturnValue(args, retval: val);
556 }
557
558 static NativeType FromDart(Dart_Handle handle) { return handle; }
559
560 static NativeType FromArguments(Dart_NativeArguments args,
561 int index,
562 Dart_Handle& exception) {
563 Dart_Handle result = Dart_GetNativeArgument(args, index);
564 TONIC_DCHECK(!Dart_IsError(result));
565 return result;
566 }
567
568 static NativeType FromFfi(FfiType val) { return val; }
569 static FfiType ToFfi(NativeType val) { return val; }
570 static const char* GetFfiRepresentation() { return kFfiRepresentation; }
571 static const char* GetDartRepresentation() { return kDartRepresentation; }
572 static bool AllowedInLeafCall() { return kAllowedInLeafCall; }
573};
574
575////////////////////////////////////////////////////////////////////////////////
576// Convenience wrappers using type inference
577
578template <typename T>
579Dart_Handle ToDart(const T& object) {
580 return DartConverter<T>::ToDart(object);
581}
582
583////////////////////////////////////////////////////////////////////////////////
584// std::string support
585
586inline Dart_Handle StdStringToDart(const std::string& val) {
587 return DartConverter<std::string>::ToDart(val);
588}
589
590inline std::string StdStringFromDart(Dart_Handle handle) {
591 return DartConverter<std::string>::FromDart(handle);
592}
593
594// Alias Dart_NewStringFromCString for less typing.
595inline Dart_Handle ToDart(const char* val) {
596 return Dart_NewStringFromCString(str: val);
597}
598
599} // namespace tonic
600
601#endif // LIB_CONVERTER_TONIC_DART_CONVERTER_H_
602

source code of flutter_engine/flutter/third_party/tonic/converter/dart_converter.h