| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef FLUTTER_FML_DART_DART_CONVERTER_H_ |
| #define FLUTTER_FML_DART_DART_CONVERTER_H_ |
| |
| #include <memory> |
| #include <vector> |
| |
| #include "flutter/fml/mapping.h" |
| #include "third_party/dart/runtime/include/dart_api.h" |
| #include "third_party/tonic/converter/dart_converter.h" |
| |
| namespace tonic { |
| |
| using DartConverterMapping = std::unique_ptr<fml::Mapping>; |
| |
| template <> |
| struct DartConverter<DartConverterMapping> { |
| static Dart_Handle ToDart(const DartConverterMapping& val) { |
| if (!val) { |
| return Dart_Null(); |
| } |
| |
| auto dart_list_handle = Dart_NewListOfTypeFilled( |
| ToDartTypeHandle<size_t>(), // type |
| CreateZeroInitializedDartObject<size_t>(), // sentinel |
| val->GetSize() // size |
| ); |
| |
| if (Dart_IsError(dart_list_handle)) { |
| FML_LOG(ERROR) << "Error while attempting to allocate a list: " |
| << Dart_GetError(dart_list_handle); |
| return dart_list_handle; |
| } |
| |
| if (val->GetSize() == 0) { |
| // Nothing to copy. Just return the zero sized list. |
| return dart_list_handle; |
| } |
| |
| auto result = Dart_ListSetAsBytes(dart_list_handle, // list |
| 0, // offset |
| val->GetMapping(), // native array, |
| val->GetSize() // length |
| ); |
| |
| if (Dart_IsError(result)) { |
| FML_LOG(ERROR) << "Error while attempting to create a Dart list: " |
| << Dart_GetError(result); |
| return result; |
| } |
| |
| return dart_list_handle; |
| } |
| |
| static void SetReturnValue(Dart_NativeArguments args, |
| const DartConverterMapping& val) { |
| Dart_SetReturnValue(args, ToDart(val)); |
| } |
| |
| static DartConverterMapping FromDart(Dart_Handle dart_list) { |
| if (Dart_IsNull(dart_list)) { |
| return nullptr; |
| } |
| |
| if (Dart_IsError(dart_list)) { |
| FML_LOG(ERROR) << "Cannot convert an error handle to a list: " |
| << Dart_GetError(dart_list); |
| return nullptr; |
| } |
| |
| if (!Dart_IsList(dart_list)) { |
| FML_LOG(ERROR) << "Dart handle was not a list."; |
| return nullptr; |
| } |
| |
| intptr_t length = 0; |
| auto handle = Dart_ListLength(dart_list, &length); |
| |
| if (Dart_IsError(handle)) { |
| FML_LOG(ERROR) << "Could not get the length of the Dart list: " |
| << Dart_GetError(handle); |
| return nullptr; |
| } |
| |
| if (length == 0) { |
| // Return a valid zero sized mapping. |
| return std::make_unique<fml::NonOwnedMapping>(nullptr, 0); |
| } |
| |
| auto mapping_buffer = ::malloc(length); |
| |
| if (!mapping_buffer) { |
| FML_LOG(ERROR) |
| << "Out of memory while attempting to allocate a mapping of size: " |
| << length; |
| return nullptr; |
| } |
| |
| auto mapping = std::make_unique<fml::NonOwnedMapping>( |
| static_cast<const uint8_t*>(mapping_buffer), length, |
| [](const uint8_t* data, size_t size) { |
| ::free(const_cast<uint8_t*>(data)); |
| }); |
| |
| handle = Dart_ListGetAsBytes( |
| dart_list, // list |
| 0, // offset |
| static_cast<uint8_t*>(mapping_buffer), // native array |
| length // length |
| ); |
| |
| if (Dart_IsError(handle)) { |
| FML_LOG(ERROR) << "Could not copy Dart list to native buffer: " |
| << Dart_GetError(handle); |
| return nullptr; |
| } |
| |
| return mapping; |
| } |
| }; |
| |
| } // namespace tonic |
| |
| #endif // FLUTTER_FML_DART_DART_CONVERTER_H_ |