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 FLUTTER_FML_DART_DART_CONVERTER_H_
6#define FLUTTER_FML_DART_DART_CONVERTER_H_
7
8#include <memory>
9#include <vector>
10
11#include "flutter/fml/mapping.h"
12#include "third_party/dart/runtime/include/dart_api.h"
13#include "third_party/tonic/converter/dart_converter.h"
14
15namespace tonic {
16
17using DartConverterMapping = std::unique_ptr<fml::Mapping>;
18
19template <>
20struct DartConverter<DartConverterMapping> {
21 static Dart_Handle ToDart(const DartConverterMapping& val) {
22 if (!val) {
23 return Dart_Null();
24 }
25
26 auto dart_list_handle = Dart_NewListOf(Dart_CoreType_Int, val->GetSize());
27
28 if (Dart_IsError(dart_list_handle)) {
29 FML_LOG(ERROR) << "Error while attempting to allocate a list: "
30 << Dart_GetError(dart_list_handle);
31 return dart_list_handle;
32 }
33
34 if (val->GetSize() == 0) {
35 // Nothing to copy. Just return the zero sized list.
36 return dart_list_handle;
37 }
38
39 auto result = Dart_ListSetAsBytes(dart_list_handle, // list
40 0, // offset
41 val->GetMapping(), // native array,
42 val->GetSize() // length
43 );
44
45 if (Dart_IsError(result)) {
46 FML_LOG(ERROR) << "Error while attempting to create a Dart list: "
47 << Dart_GetError(result);
48 return result;
49 }
50
51 return dart_list_handle;
52 }
53
54 static void SetReturnValue(Dart_NativeArguments args,
55 const DartConverterMapping& val) {
56 Dart_SetReturnValue(args, ToDart(val));
57 }
58
59 static DartConverterMapping FromDart(Dart_Handle dart_list) {
60 if (Dart_IsNull(dart_list)) {
61 return nullptr;
62 }
63
64 if (Dart_IsError(dart_list)) {
65 FML_LOG(ERROR) << "Cannot convert an error handle to a list: "
66 << Dart_GetError(dart_list);
67 return nullptr;
68 }
69
70 if (!Dart_IsList(dart_list)) {
71 FML_LOG(ERROR) << "Dart handle was not a list.";
72 return nullptr;
73 }
74
75 intptr_t length = 0;
76 auto handle = Dart_ListLength(dart_list, &length);
77
78 if (Dart_IsError(handle)) {
79 FML_LOG(ERROR) << "Could not get the length of the Dart list: "
80 << Dart_GetError(handle);
81 return nullptr;
82 }
83
84 if (length == 0) {
85 // Return a valid zero sized mapping.
86 return std::make_unique<fml::NonOwnedMapping>(nullptr, 0);
87 }
88
89 auto mapping_buffer = ::malloc(length);
90
91 if (!mapping_buffer) {
92 FML_LOG(ERROR)
93 << "Out of memory while attempting to allocate a mapping of size: "
94 << length;
95 return nullptr;
96 }
97
98 auto mapping = std::make_unique<fml::NonOwnedMapping>(
99 static_cast<const uint8_t*>(mapping_buffer), length,
100 [](const uint8_t* data, size_t size) {
101 ::free(const_cast<uint8_t*>(data));
102 });
103
104 handle = Dart_ListGetAsBytes(
105 dart_list, // list
106 0, // offset
107 static_cast<uint8_t*>(mapping_buffer), // native array
108 length // length
109 );
110
111 if (Dart_IsError(handle)) {
112 FML_LOG(ERROR) << "Could not copy Dart list to native buffer: "
113 << Dart_GetError(handle);
114 return nullptr;
115 }
116
117 return mapping;
118 }
119};
120
121} // namespace tonic
122
123#endif // FLUTTER_FML_DART_DART_CONVERTER_H_
124