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 | |
16 | namespace 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. |
20 | template <typename T, typename Enable = void> |
21 | struct 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 | // }; |
33 | template <typename T> |
34 | struct DartConverterTypes { |
35 | using ConverterType = T; |
36 | using ValueType = T; |
37 | }; |
38 | |
39 | template <> |
40 | struct 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 | |
53 | template <> |
54 | struct 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 | |
91 | template <typename T> |
92 | struct 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 | |
136 | template <> |
137 | struct DartConverter<int> : public DartConverterInteger<int> {}; |
138 | |
139 | template <> |
140 | struct DartConverter<long int> : public DartConverterInteger<long int> {}; |
141 | |
142 | template <> |
143 | struct DartConverter<unsigned> : public DartConverterInteger<unsigned> {}; |
144 | |
145 | template <> |
146 | struct DartConverter<long long> : public DartConverterInteger<long long> {}; |
147 | |
148 | template <> |
149 | struct DartConverter<unsigned long> |
150 | : public DartConverterInteger<unsigned long> {}; |
151 | |
152 | template <> |
153 | struct 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. |
207 | template <> |
208 | struct 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 | |
245 | template <typename T> |
246 | struct 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 | |
285 | template <> |
286 | struct 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 | |
326 | template <> |
327 | struct 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 | |
367 | template <> |
368 | struct 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 | |
396 | inline 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 | |
414 | template <typename T, |
415 | std::enable_if_t<std::is_same<std::string, T>::value, int> = 0> |
416 | Dart_Handle ToDartTypeHandle() { |
417 | return LookupNonNullableType(library_name: "dart:core" , type_name: "String" ); |
418 | } |
419 | |
420 | template <typename T, std::enable_if_t<std::is_integral<T>::value, int> = 0> |
421 | Dart_Handle ToDartTypeHandle() { |
422 | return LookupNonNullableType(library_name: "dart:core" , type_name: "int" ); |
423 | } |
424 | |
425 | template <typename T, |
426 | std::enable_if_t<std::is_floating_point<T>::value, int> = 0> |
427 | Dart_Handle ToDartTypeHandle() { |
428 | return LookupNonNullableType(library_name: "dart:core" , type_name: "double" ); |
429 | } |
430 | |
431 | template <typename T> |
432 | Dart_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 | |
448 | template <typename T, typename Enable = void> |
449 | struct 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 | |
473 | template <typename T> |
474 | struct 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 | |
544 | template <> |
545 | struct 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 | |
578 | template <typename T> |
579 | Dart_Handle ToDart(const T& object) { |
580 | return DartConverter<T>::ToDart(object); |
581 | } |
582 | |
583 | //////////////////////////////////////////////////////////////////////////////// |
584 | // std::string support |
585 | |
586 | inline Dart_Handle StdStringToDart(const std::string& val) { |
587 | return DartConverter<std::string>::ToDart(val); |
588 | } |
589 | |
590 | inline std::string StdStringFromDart(Dart_Handle handle) { |
591 | return DartConverter<std::string>::FromDart(handle); |
592 | } |
593 | |
594 | // Alias Dart_NewStringFromCString for less typing. |
595 | inline 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 | |