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 <vector>
10
11#include "third_party/dart/runtime/include/dart_api.h"
12#include "tonic/common/macros.h"
13
14namespace tonic {
15
16// DartConvert converts types back and forth from Sky to Dart. The template
17// parameter |T| determines what kind of type conversion to perform.
18template <typename T, typename Enable = void>
19struct DartConverter {};
20
21// This is to work around the fact that typedefs do not create new types. If you
22// have a typedef, and want it to use a different converter, specialize this
23// template and override the types here.
24// Ex:
25// typedef int ColorType; // Want to use a different converter.
26// class ColorConverterType {}; // Dummy type.
27// template<> struct DartConvertType<ColorConverterType> {
28// using ConverterType = ColorConverterType;
29// using ValueType = ColorType;
30// };
31template <typename T>
32struct DartConverterTypes {
33 using ConverterType = T;
34 using ValueType = T;
35};
36
37////////////////////////////////////////////////////////////////////////////////
38// Boolean
39
40template <>
41struct DartConverter<bool> {
42 static Dart_Handle ToDart(bool val) { return Dart_NewBoolean(val); }
43
44 static void SetReturnValue(Dart_NativeArguments args, bool val) {
45 Dart_SetBooleanReturnValue(args, val);
46 }
47
48 static bool FromDart(Dart_Handle handle) {
49 bool result = 0;
50 Dart_BooleanValue(handle, &result);
51 return result;
52 }
53
54 static bool FromArguments(Dart_NativeArguments args,
55 int index,
56 Dart_Handle& exception) {
57 bool result = false;
58 Dart_GetNativeBooleanArgument(args, index, &result);
59 return result;
60 }
61};
62
63////////////////////////////////////////////////////////////////////////////////
64// Numbers
65
66template <typename T>
67struct DartConverterInteger {
68 static Dart_Handle ToDart(T val) { return Dart_NewInteger(val); }
69
70 static void SetReturnValue(Dart_NativeArguments args, T val) {
71 Dart_SetIntegerReturnValue(args, val);
72 }
73
74 static T FromDart(Dart_Handle handle) {
75 int64_t result = 0;
76 Dart_IntegerToInt64(handle, &result);
77 return static_cast<T>(result);
78 }
79
80 static T FromArguments(Dart_NativeArguments args,
81 int index,
82 Dart_Handle& exception) {
83 int64_t result = 0;
84 Dart_GetNativeIntegerArgument(args, index, &result);
85 return static_cast<T>(result);
86 }
87};
88
89template <>
90struct DartConverter<int> : public DartConverterInteger<int> {};
91
92template <>
93struct DartConverter<long int> : public DartConverterInteger<long int> {};
94
95template <>
96struct DartConverter<unsigned> : public DartConverterInteger<unsigned> {};
97
98template <>
99struct DartConverter<long long> : public DartConverterInteger<long long> {};
100
101template <>
102struct DartConverter<unsigned long>
103 : public DartConverterInteger<unsigned long> {};
104
105template <>
106struct DartConverter<unsigned long long> {
107 // TODO(abarth): The Dart VM API doesn't yet have an entry-point for
108 // an unsigned 64-bit type. We will need to add a Dart API for
109 // constructing an integer from uint64_t.
110 //
111 // (In the meantime, we have asserts below to check that we're never
112 // converting values that have the 64th bit set.)
113
114 static Dart_Handle ToDart(unsigned long long val) {
115 TONIC_DCHECK(val <= 0x7fffffffffffffffLL);
116 return Dart_NewInteger(static_cast<int64_t>(val));
117 }
118
119 static void SetReturnValue(Dart_NativeArguments args,
120 unsigned long long val) {
121 TONIC_DCHECK(val <= 0x7fffffffffffffffLL);
122 Dart_SetIntegerReturnValue(args, val);
123 }
124
125 static unsigned long long FromDart(Dart_Handle handle) {
126 int64_t result = 0;
127 Dart_IntegerToInt64(handle, &result);
128 return result;
129 }
130
131 static unsigned long long FromArguments(Dart_NativeArguments args,
132 int index,
133 Dart_Handle& exception) {
134 int64_t result = 0;
135 Dart_GetNativeIntegerArgument(args, index, &result);
136 return result;
137 }
138};
139
140template <typename T>
141struct DartConverterFloatingPoint {
142 static Dart_Handle ToDart(T val) { return Dart_NewDouble(val); }
143
144 static void SetReturnValue(Dart_NativeArguments args, T val) {
145 Dart_SetDoubleReturnValue(args, val);
146 }
147
148 static T FromDart(Dart_Handle handle) {
149 double result = 0;
150 Dart_DoubleValue(handle, &result);
151 return result;
152 }
153
154 static T FromArguments(Dart_NativeArguments args,
155 int index,
156 Dart_Handle& exception) {
157 double result = 0;
158 Dart_GetNativeDoubleArgument(args, index, &result);
159 return result;
160 }
161};
162
163template <>
164struct DartConverter<float> : public DartConverterFloatingPoint<float> {};
165
166template <>
167struct DartConverter<double> : public DartConverterFloatingPoint<double> {};
168
169////////////////////////////////////////////////////////////////////////////////
170// Enum Classes
171
172template <typename T>
173struct DartConverter<T, typename std::enable_if<std::is_enum<T>::value>::type> {
174 static Dart_Handle ToDart(T val) {
175 return Dart_NewInteger(
176 static_cast<typename std::underlying_type<T>::type>(val));
177 }
178
179 static void SetReturnValue(Dart_NativeArguments args, T val) {
180 Dart_SetIntegerReturnValue(
181 args, static_cast<typename std::underlying_type<T>::type>(val));
182 }
183
184 static T FromDart(Dart_Handle handle) {
185 int64_t result = 0;
186 Dart_IntegerToInt64(handle, &result);
187 return static_cast<T>(result);
188 }
189
190 static T FromArguments(Dart_NativeArguments args,
191 int index,
192 Dart_Handle& exception) {
193 int64_t result = 0;
194 Dart_GetNativeIntegerArgument(args, index, &result);
195 return static_cast<T>(result);
196 }
197};
198
199////////////////////////////////////////////////////////////////////////////////
200// Strings
201
202template <>
203struct DartConverter<std::string> {
204 static Dart_Handle ToDart(const std::string& val) {
205 return Dart_NewStringFromUTF8(reinterpret_cast<const uint8_t*>(val.data()),
206 val.length());
207 }
208
209 static void SetReturnValue(Dart_NativeArguments args,
210 const std::string& val) {
211 Dart_SetReturnValue(args, ToDart(val));
212 }
213
214 static std::string FromDart(Dart_Handle handle) {
215 uint8_t* data = nullptr;
216 intptr_t length = 0;
217 if (Dart_IsError(Dart_StringToUTF8(handle, &data, &length)))
218 return std::string();
219 return std::string(reinterpret_cast<char*>(data), length);
220 }
221
222 static std::string FromArguments(Dart_NativeArguments args,
223 int index,
224 Dart_Handle& exception) {
225 return FromDart(Dart_GetNativeArgument(args, index));
226 }
227};
228
229template <>
230struct DartConverter<std::u16string> {
231 static Dart_Handle ToDart(const std::u16string& val) {
232 return Dart_NewStringFromUTF16(
233 reinterpret_cast<const uint16_t*>(val.data()), val.length());
234 }
235
236 static void SetReturnValue(Dart_NativeArguments args,
237 const std::u16string& val) {
238 Dart_SetReturnValue(args, ToDart(val));
239 }
240
241 static std::u16string FromDart(Dart_Handle handle) {
242 intptr_t length = 0;
243 Dart_StringLength(handle, &length);
244 std::vector<uint16_t> data(length);
245 Dart_StringToUTF16(handle, data.data(), &length);
246 return std::u16string(reinterpret_cast<char16_t*>(data.data()), length);
247 }
248
249 static std::u16string FromArguments(Dart_NativeArguments args,
250 int index,
251 Dart_Handle& exception) {
252 return FromDart(Dart_GetNativeArgument(args, index));
253 }
254};
255
256template <>
257struct DartConverter<const char*> {
258 static Dart_Handle ToDart(const char* val) {
259 return Dart_NewStringFromCString(val);
260 }
261
262 static void SetReturnValue(Dart_NativeArguments args, const char* val) {
263 Dart_SetReturnValue(args, ToDart(val));
264 }
265
266 static const char* FromDart(Dart_Handle handle) {
267 const char* result = nullptr;
268 Dart_StringToCString(handle, &result);
269 return result;
270 }
271
272 static const char* FromArguments(Dart_NativeArguments args,
273 int index,
274 Dart_Handle& exception) {
275 return FromDart(Dart_GetNativeArgument(args, index));
276 }
277};
278
279////////////////////////////////////////////////////////////////////////////////
280// Collections
281
282template <typename T, typename Enable = void>
283struct DartListFactory {
284 static Dart_Handle NewList(intptr_t length) { return Dart_NewList(length); }
285};
286
287template <>
288struct DartListFactory<std::string> {
289 static Dart_Handle NewList(intptr_t length) {
290 return Dart_NewListOf(Dart_CoreType_String, length);
291 }
292};
293
294template <typename T>
295struct DartConverter<std::vector<T>> {
296 using ValueType = typename DartConverterTypes<T>::ValueType;
297 using ConverterType = typename DartConverterTypes<T>::ConverterType;
298
299 static Dart_Handle ToDart(const std::vector<ValueType>& val) {
300 Dart_Handle list = DartListFactory<ValueType>::NewList(val.size());
301 if (Dart_IsError(list))
302 return list;
303 for (size_t i = 0; i < val.size(); i++) {
304 Dart_Handle result =
305 Dart_ListSetAt(list, i, DartConverter<ConverterType>::ToDart(val[i]));
306 if (Dart_IsError(result))
307 return result;
308 }
309 return list;
310 }
311
312 static void SetReturnValue(Dart_NativeArguments args,
313 const std::vector<ValueType>& val) {
314 Dart_SetReturnValue(args, ToDart(val));
315 }
316
317 static std::vector<ValueType> FromDart(Dart_Handle handle) {
318 std::vector<ValueType> result;
319
320 if (!Dart_IsList(handle))
321 return result;
322
323 intptr_t length = 0;
324 Dart_ListLength(handle, &length);
325
326 if (length == 0)
327 return result;
328
329 result.reserve(length);
330
331 std::vector<Dart_Handle> items(length);
332 Dart_Handle items_result =
333 Dart_ListGetRange(handle, 0, length, items.data());
334 TONIC_DCHECK(!Dart_IsError(items_result));
335
336 for (intptr_t i = 0; i < length; ++i) {
337 TONIC_DCHECK(items[i]);
338 result.push_back(DartConverter<ConverterType>::FromDart(items[i]));
339 }
340 return result;
341 }
342
343 static std::vector<ValueType> FromArguments(Dart_NativeArguments args,
344 int index,
345 Dart_Handle& exception) {
346 return FromDart(Dart_GetNativeArgument(args, index));
347 }
348};
349
350////////////////////////////////////////////////////////////////////////////////
351// Dart_Handle
352
353template <>
354struct DartConverter<Dart_Handle> {
355 static Dart_Handle ToDart(Dart_Handle val) { return val; }
356
357 static void SetReturnValue(Dart_NativeArguments args, Dart_Handle val) {
358 Dart_SetReturnValue(args, val);
359 }
360
361 static Dart_Handle FromDart(Dart_Handle handle) { return handle; }
362
363 static Dart_Handle FromArguments(Dart_NativeArguments args,
364 int index,
365 Dart_Handle& exception) {
366 return Dart_GetNativeArgument(args, index);
367 }
368};
369
370////////////////////////////////////////////////////////////////////////////////
371// Convience wrappers using type inference
372
373template <typename T>
374Dart_Handle ToDart(const T& object) {
375 return DartConverter<T>::ToDart(object);
376}
377
378////////////////////////////////////////////////////////////////////////////////
379// std::string support
380
381inline Dart_Handle StdStringToDart(const std::string& val) {
382 return DartConverter<std::string>::ToDart(val);
383}
384
385inline std::string StdStringFromDart(Dart_Handle handle) {
386 return DartConverter<std::string>::FromDart(handle);
387}
388
389// Alias Dart_NewStringFromCString for less typing.
390inline Dart_Handle ToDart(const char* val) {
391 return Dart_NewStringFromCString(val);
392}
393
394} // namespace tonic
395
396#endif // LIB_CONVERTER_TONIC_DART_CONVERTER_H_
397