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 | |
17 | namespace 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. |
21 | class 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 | |
93 | struct DartConverterWrappable { |
94 | static DartWrappable* FromDart(Dart_Handle handle); |
95 | static DartWrappable* FromArguments(Dart_NativeArguments args, |
96 | int index, |
97 | Dart_Handle& exception); |
98 | }; |
99 | |
100 | template <typename T> |
101 | struct 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 | |
144 | template <template <typename T> class PTR, typename T> |
145 | struct 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 | |
169 | template <template <typename T> class PTR, typename T> |
170 | struct 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 | |
181 | template <typename T> |
182 | inline 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 | |