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_ARGS_H_
6#define LIB_TONIC_DART_ARGS_H_
7
8#include <type_traits>
9#include <utility>
10
11#include "third_party/dart/runtime/include/dart_api.h"
12#include "tonic/converter/dart_converter.h"
13#include "tonic/dart_wrappable.h"
14
15namespace tonic {
16
17class DartArgIterator {
18 public:
19 DartArgIterator(Dart_NativeArguments args, int start_index = 1)
20 : args_(args), index_(start_index), had_exception_(false) {}
21
22 template <typename T>
23 T GetNext() {
24 if (had_exception_)
25 return T();
26 Dart_Handle exception = nullptr;
27 T arg = DartConverter<T>::FromArguments(args_, index_++, exception);
28 if (exception) {
29 had_exception_ = true;
30 Dart_ThrowException(exception);
31 }
32 return arg;
33 }
34
35 bool had_exception() const { return had_exception_; }
36
37 Dart_NativeArguments args() const { return args_; }
38
39 private:
40 Dart_NativeArguments args_;
41 int index_;
42 bool had_exception_;
43
44 TONIC_DISALLOW_COPY_AND_ASSIGN(DartArgIterator);
45};
46
47// Classes for generating and storing an argument pack of integer indices
48// (based on well-known "indices trick", see: http://goo.gl/bKKojn):
49template <size_t... indices>
50struct IndicesHolder {};
51
52template <size_t requested_index, size_t... indices>
53struct IndicesGenerator {
54 using type = typename IndicesGenerator<requested_index - 1,
55 requested_index - 1,
56 indices...>::type;
57};
58
59template <size_t... indices>
60struct IndicesGenerator<0, indices...> {
61 using type = IndicesHolder<indices...>;
62};
63
64template <typename T>
65class IndicesForSignature {};
66
67template <typename ResultType, typename... ArgTypes>
68struct IndicesForSignature<ResultType (*)(ArgTypes...)> {
69 static const size_t count = sizeof...(ArgTypes);
70 using type = typename IndicesGenerator<count>::type;
71};
72
73template <typename C, typename ResultType, typename... ArgTypes>
74struct IndicesForSignature<ResultType (C::*)(ArgTypes...)> {
75 static const size_t count = sizeof...(ArgTypes);
76 using type = typename IndicesGenerator<count>::type;
77};
78
79template <typename C, typename ResultType, typename... ArgTypes>
80struct IndicesForSignature<ResultType (C::*)(ArgTypes...) const> {
81 static const size_t count = sizeof...(ArgTypes);
82 using type = typename IndicesGenerator<count>::type;
83};
84
85template <size_t index, typename ArgType>
86struct DartArgHolder {
87 using ValueType = typename std::remove_const<
88 typename std::remove_reference<ArgType>::type>::type;
89
90 ValueType value;
91
92 explicit DartArgHolder(DartArgIterator* it)
93 : value(it->GetNext<ValueType>()) {}
94};
95
96template <typename T>
97void DartReturn(T result, Dart_NativeArguments args) {
98 DartConverter<T>::SetReturnValue(args, std::move(result));
99}
100
101template <typename IndicesType, typename T>
102class DartDispatcher {};
103
104template <size_t... indices, typename... ArgTypes>
105struct DartDispatcher<IndicesHolder<indices...>, void (*)(ArgTypes...)>
106 : public DartArgHolder<indices, ArgTypes>... {
107 using FunctionPtr = void (*)(ArgTypes...);
108
109 DartArgIterator* it_;
110
111 explicit DartDispatcher(DartArgIterator* it)
112 : DartArgHolder<indices, ArgTypes>(it)..., it_(it) {}
113
114 void Dispatch(FunctionPtr func) {
115 (*func)(DartArgHolder<indices, ArgTypes>::value...);
116 }
117};
118
119template <size_t... indices, typename ResultType, typename... ArgTypes>
120struct DartDispatcher<IndicesHolder<indices...>, ResultType (*)(ArgTypes...)>
121 : public DartArgHolder<indices, ArgTypes>... {
122 using FunctionPtr = ResultType (*)(ArgTypes...);
123 using CtorResultType = ResultType;
124
125 DartArgIterator* it_;
126
127 explicit DartDispatcher(DartArgIterator* it)
128 : DartArgHolder<indices, ArgTypes>(it)..., it_(it) {}
129
130 void Dispatch(FunctionPtr func) {
131 DartReturn((*func)(DartArgHolder<indices, ArgTypes>::value...),
132 it_->args());
133 }
134
135 ResultType DispatchCtor(FunctionPtr func) {
136 return (*func)(DartArgHolder<indices, ArgTypes>::value...);
137 }
138};
139
140template <size_t... indices, typename C, typename... ArgTypes>
141struct DartDispatcher<IndicesHolder<indices...>, void (C::*)(ArgTypes...)>
142 : public DartArgHolder<indices, ArgTypes>... {
143 using FunctionPtr = void (C::*)(ArgTypes...);
144
145 DartArgIterator* it_;
146
147 explicit DartDispatcher(DartArgIterator* it)
148 : DartArgHolder<indices, ArgTypes>(it)..., it_(it) {}
149
150 void Dispatch(FunctionPtr func) {
151 (GetReceiver<C>(it_->args())->*func)(
152 DartArgHolder<indices, ArgTypes>::value...);
153 }
154};
155
156template <size_t... indices,
157 typename C,
158 typename ReturnType,
159 typename... ArgTypes>
160struct DartDispatcher<IndicesHolder<indices...>,
161 ReturnType (C::*)(ArgTypes...) const>
162 : public DartArgHolder<indices, ArgTypes>... {
163 using FunctionPtr = ReturnType (C::*)(ArgTypes...) const;
164
165 DartArgIterator* it_;
166
167 explicit DartDispatcher(DartArgIterator* it)
168 : DartArgHolder<indices, ArgTypes>(it)..., it_(it) {}
169
170 void Dispatch(FunctionPtr func) {
171 DartReturn((GetReceiver<C>(it_->args())->*func)(
172 DartArgHolder<indices, ArgTypes>::value...),
173 it_->args());
174 }
175};
176
177template <size_t... indices,
178 typename C,
179 typename ResultType,
180 typename... ArgTypes>
181struct DartDispatcher<IndicesHolder<indices...>, ResultType (C::*)(ArgTypes...)>
182 : public DartArgHolder<indices, ArgTypes>... {
183 using FunctionPtr = ResultType (C::*)(ArgTypes...);
184
185 DartArgIterator* it_;
186
187 explicit DartDispatcher(DartArgIterator* it)
188 : DartArgHolder<indices, ArgTypes>(it)..., it_(it) {}
189
190 void Dispatch(FunctionPtr func) {
191 DartReturn((GetReceiver<C>(it_->args())->*func)(
192 DartArgHolder<indices, ArgTypes>::value...),
193 it_->args());
194 }
195};
196
197template <typename Sig>
198void DartCall(Sig func, Dart_NativeArguments args) {
199 DartArgIterator it(args);
200 using Indices = typename IndicesForSignature<Sig>::type;
201 DartDispatcher<Indices, Sig> decoder(&it);
202 if (it.had_exception())
203 return;
204 decoder.Dispatch(func);
205}
206
207template <typename Sig>
208void DartCallStatic(Sig func, Dart_NativeArguments args) {
209 DartArgIterator it(args, 0);
210 using Indices = typename IndicesForSignature<Sig>::type;
211 DartDispatcher<Indices, Sig> decoder(&it);
212 if (it.had_exception())
213 return;
214 decoder.Dispatch(func);
215}
216
217template <typename Sig>
218void DartCallConstructor(Sig func, Dart_NativeArguments args) {
219 DartArgIterator it(args);
220 using Indices = typename IndicesForSignature<Sig>::type;
221 using Wrappable = typename DartDispatcher<Indices, Sig>::CtorResultType;
222 Wrappable wrappable;
223 {
224 DartDispatcher<Indices, Sig> decoder(&it);
225 if (it.had_exception())
226 return;
227 wrappable = decoder.DispatchCtor(func);
228 }
229
230 Dart_Handle wrapper = Dart_GetNativeArgument(args, 0);
231 TONIC_CHECK(!LogIfError(wrapper));
232
233 intptr_t native_fields[DartWrappable::kNumberOfNativeFields];
234 TONIC_CHECK(!LogIfError(Dart_GetNativeFieldsOfArgument(
235 args, 0, DartWrappable::kNumberOfNativeFields, native_fields)));
236 TONIC_CHECK(!native_fields[DartWrappable::kPeerIndex]);
237 TONIC_CHECK(!native_fields[DartWrappable::kWrapperInfoIndex]);
238
239 wrappable->AssociateWithDartWrapper(wrapper);
240}
241
242} // namespace tonic
243
244#endif // LIB_TONIC_DART_ARGS_H_
245