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_TONIC_DART_WRAPPABLE_H_
6#define LIB_TONIC_DART_WRAPPABLE_H_
7
8#include "third_party/dart/runtime/include/dart_api.h"
9#include "tonic/common/macros.h"
10#include "tonic/converter/dart_converter.h"
11#include "tonic/dart_state.h"
12#include "tonic/dart_wrapper_info.h"
13#include "tonic/logging/dart_error.h"
14
15#include <type_traits>
16
17namespace tonic {
18
19// DartWrappable is a base class that you can inherit from in order to be
20// exposed to Dart code as an interface.
21class DartWrappable {
22 public:
23 enum DartNativeFields {
24 kPeerIndex, // Must be first to work with Dart_GetNativeReceiver.
25 kWrapperInfoIndex,
26 kNumberOfNativeFields,
27 };
28
29 DartWrappable() : dart_wrapper_(nullptr) {}
30
31 // Subclasses that wish to expose a new interface must override this function
32 // and provide information about their wrapper. There is no need to call your
33 // base class's implementation of this function.
34 // Implement using IMPLEMENT_WRAPPERTYPEINFO macro
35 virtual const DartWrapperInfo& GetDartWrapperInfo() const = 0;
36
37 // Override this to customize the object size reported to the Dart garbage
38 // collector.
39 // Implement using IMPLEMENT_WRAPPERTYPEINFO macro
40 virtual size_t GetAllocationSize() const;
41
42 virtual void RetainDartWrappableReference() const = 0;
43
44 virtual void ReleaseDartWrappableReference() const = 0;
45
46 // Use this method sparingly. It follows a slower path using Dart_New.
47 // Prefer constructing the object in Dart code and using
48 // AssociateWithDartWrapper.
49 Dart_Handle CreateDartWrapper(DartState* dart_state);
50 void AssociateWithDartWrapper(Dart_Handle wrappable);
51 void ClearDartWrapper(); // Warning: Might delete this.
52 Dart_WeakPersistentHandle dart_wrapper() const { return dart_wrapper_; }
53
54 protected:
55 virtual ~DartWrappable();
56
57 static Dart_PersistentHandle GetTypeForWrapper(
58 tonic::DartState* dart_state,
59 const tonic::DartWrapperInfo& wrapper_info);
60
61 private:
62 static void FinalizeDartWrapper(void* isolate_callback_data,
63 Dart_WeakPersistentHandle wrapper,
64 void* peer);
65
66 Dart_WeakPersistentHandle dart_wrapper_;
67
68 TONIC_DISALLOW_COPY_AND_ASSIGN(DartWrappable);
69};
70
71#define DEFINE_WRAPPERTYPEINFO() \
72 public: \
73 const tonic::DartWrapperInfo& GetDartWrapperInfo() const override { \
74 return dart_wrapper_info_; \
75 } \
76 static Dart_PersistentHandle GetDartType(tonic::DartState* dart_state) { \
77 return GetTypeForWrapper(dart_state, dart_wrapper_info_); \
78 } \
79 \
80 private: \
81 static const tonic::DartWrapperInfo& dart_wrapper_info_
82
83#define IMPLEMENT_WRAPPERTYPEINFO(LibraryName, ClassName) \
84 static const tonic::DartWrapperInfo \
85 kDartWrapperInfo_##LibraryName_##ClassName = { \
86 #LibraryName, \
87 #ClassName, \
88 sizeof(ClassName), \
89 }; \
90 const tonic::DartWrapperInfo& ClassName::dart_wrapper_info_ = \
91 kDartWrapperInfo_##LibraryName_##ClassName;
92
93struct DartConverterWrappable {
94 static DartWrappable* FromDart(Dart_Handle handle);
95 static DartWrappable* FromArguments(Dart_NativeArguments args,
96 int index,
97 Dart_Handle& exception);
98};
99
100template <typename T>
101struct DartConverter<
102 T*,
103 typename std::enable_if<
104 std::is_convertible<T*, const DartWrappable*>::value>::type> {
105 static Dart_Handle ToDart(DartWrappable* val) {
106 if (!val)
107 return Dart_Null();
108 if (Dart_WeakPersistentHandle wrapper = val->dart_wrapper())
109 return Dart_HandleFromWeakPersistent(wrapper);
110 return val->CreateDartWrapper(DartState::Current());
111 }
112
113 static void SetReturnValue(Dart_NativeArguments args,
114 DartWrappable* val,
115 bool auto_scope = true) {
116 if (!val)
117 Dart_SetReturnValue(args, Dart_Null());
118 else if (Dart_WeakPersistentHandle wrapper = val->dart_wrapper())
119 Dart_SetWeakHandleReturnValue(args, wrapper);
120 else
121 Dart_SetReturnValue(args, val->CreateDartWrapper(DartState::Current()));
122 }
123
124 static T* FromDart(Dart_Handle handle) {
125 // TODO(abarth): We're missing a type check.
126 return static_cast<T*>(DartConverterWrappable::FromDart(handle));
127 }
128
129 static T* FromArguments(Dart_NativeArguments args,
130 int index,
131 Dart_Handle& exception,
132 bool auto_scope = true) {
133 // TODO(abarth): We're missing a type check.
134 return static_cast<T*>(
135 DartConverterWrappable::FromArguments(args, index, exception));
136 }
137};
138
139////////////////////////////////////////////////////////////////////////////////
140// Support for generic smart pointers that have a "get" method that returns a
141// pointer to a type that is Dart convertible as well as a constructor that
142// adopts a raw pointer to that type.
143
144template <template <typename T> class PTR, typename T>
145struct DartConverter<PTR<T>> {
146 static Dart_Handle ToDart(const PTR<T>& val) {
147 return DartConverter<T*>::ToDart(val.get());
148 }
149
150 static PTR<T> FromDart(Dart_Handle handle) {
151 return DartConverter<T*>::FromDart(handle);
152 }
153
154 static PTR<T> FromArguments(Dart_NativeArguments args,
155 int index,
156 Dart_Handle& exception,
157 bool auto_scope = true) {
158 return PTR<T>(
159 DartConverter<T*>::FromArguments(args, index, exception, auto_scope));
160 }
161
162 static void SetReturnValue(Dart_NativeArguments args,
163 const PTR<T>& val,
164 bool auto_scope = true) {
165 DartConverter<T*>::SetReturnValue(args, val.get());
166 }
167};
168
169template <template <typename T> class PTR, typename T>
170struct DartListFactory<
171 PTR<T>,
172 typename std::enable_if<
173 std::is_convertible<T*, const DartWrappable*>::value>::type> {
174 static Dart_Handle NewList(intptr_t length) {
175 Dart_PersistentHandle type = T::GetDartType(DartState::Current());
176 TONIC_DCHECK(!LogIfError(type));
177 return Dart_NewListOfType(Dart_HandleFromPersistent(type), length);
178 }
179};
180
181template <typename T>
182inline T* GetReceiver(Dart_NativeArguments args) {
183 intptr_t receiver;
184 Dart_Handle result = Dart_GetNativeReceiver(args, &receiver);
185 TONIC_DCHECK(!Dart_IsError(result));
186 if (!receiver)
187 Dart_ThrowException(ToDart("Object has been disposed."));
188 return static_cast<T*>(reinterpret_cast<DartWrappable*>(receiver));
189}
190
191} // namespace tonic
192
193#endif // LIB_TONIC_DART_WRAPPABLE_H_
194