blob: 96a5b2c5b0f1739a86fc590020e59ae314fef2c1 [file] [log] [blame]
// 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 LIB_TONIC_DART_ARGS_H_
#define LIB_TONIC_DART_ARGS_H_
#include <type_traits>
#include <utility>
#include "third_party/dart/runtime/include/dart_api.h"
#include "tonic/converter/dart_converter.h"
#include "tonic/dart_wrappable.h"
namespace tonic {
class DartArgIterator {
public:
DartArgIterator(Dart_NativeArguments args, int start_index = 1)
: args_(args), index_(start_index), had_exception_(false) {}
template <typename T>
T GetNext() {
if (had_exception_)
return T();
Dart_Handle exception = nullptr;
T arg = DartConverter<T>::FromArguments(args_, index_++, exception);
if (exception) {
had_exception_ = true;
Dart_ThrowException(exception);
}
return arg;
}
bool had_exception() const { return had_exception_; }
Dart_NativeArguments args() const { return args_; }
private:
Dart_NativeArguments args_;
int index_;
bool had_exception_;
TONIC_DISALLOW_COPY_AND_ASSIGN(DartArgIterator);
};
// Classes for generating and storing an argument pack of integer indices
// (based on well-known "indices trick", see: http://goo.gl/bKKojn):
template <size_t... indices>
struct IndicesHolder {};
template <size_t requested_index, size_t... indices>
struct IndicesGenerator {
using type = typename IndicesGenerator<requested_index - 1,
requested_index - 1,
indices...>::type;
};
template <size_t... indices>
struct IndicesGenerator<0, indices...> {
using type = IndicesHolder<indices...>;
};
template <typename T>
class IndicesForSignature {};
template <typename ResultType, typename... ArgTypes>
struct IndicesForSignature<ResultType (*)(ArgTypes...)> {
static const size_t count = sizeof...(ArgTypes);
using type = typename IndicesGenerator<count>::type;
};
template <typename C, typename ResultType, typename... ArgTypes>
struct IndicesForSignature<ResultType (C::*)(ArgTypes...)> {
static const size_t count = sizeof...(ArgTypes);
using type = typename IndicesGenerator<count>::type;
};
template <typename C, typename ResultType, typename... ArgTypes>
struct IndicesForSignature<ResultType (C::*)(ArgTypes...) const> {
static const size_t count = sizeof...(ArgTypes);
using type = typename IndicesGenerator<count>::type;
};
template <size_t index, typename ArgType>
struct DartArgHolder {
using ValueType = typename std::remove_const<
typename std::remove_reference<ArgType>::type>::type;
ValueType value;
explicit DartArgHolder(DartArgIterator* it)
: value(it->GetNext<ValueType>()) {}
};
template <typename T>
void DartReturn(T result, Dart_NativeArguments args) {
DartConverter<T>::SetReturnValue(args, std::move(result));
}
template <typename IndicesType, typename T>
class DartDispatcher {};
template <size_t... indices, typename... ArgTypes>
struct DartDispatcher<IndicesHolder<indices...>, void (*)(ArgTypes...)>
: public DartArgHolder<indices, ArgTypes>... {
using FunctionPtr = void (*)(ArgTypes...);
DartArgIterator* it_;
explicit DartDispatcher(DartArgIterator* it)
: DartArgHolder<indices, ArgTypes>(it)..., it_(it) {}
void Dispatch(FunctionPtr func) {
(*func)(DartArgHolder<indices, ArgTypes>::value...);
}
};
template <size_t... indices, typename ResultType, typename... ArgTypes>
struct DartDispatcher<IndicesHolder<indices...>, ResultType (*)(ArgTypes...)>
: public DartArgHolder<indices, ArgTypes>... {
using FunctionPtr = ResultType (*)(ArgTypes...);
using CtorResultType = ResultType;
DartArgIterator* it_;
explicit DartDispatcher(DartArgIterator* it)
: DartArgHolder<indices, ArgTypes>(it)..., it_(it) {}
void Dispatch(FunctionPtr func) {
DartReturn((*func)(DartArgHolder<indices, ArgTypes>::value...),
it_->args());
}
ResultType DispatchCtor(FunctionPtr func) {
return (*func)(DartArgHolder<indices, ArgTypes>::value...);
}
};
template <size_t... indices, typename C, typename... ArgTypes>
struct DartDispatcher<IndicesHolder<indices...>, void (C::*)(ArgTypes...)>
: public DartArgHolder<indices, ArgTypes>... {
using FunctionPtr = void (C::*)(ArgTypes...);
DartArgIterator* it_;
explicit DartDispatcher(DartArgIterator* it)
: DartArgHolder<indices, ArgTypes>(it)..., it_(it) {}
void Dispatch(FunctionPtr func) {
(GetReceiver<C>(it_->args())->*func)(
DartArgHolder<indices, ArgTypes>::value...);
}
};
template <size_t... indices,
typename C,
typename ReturnType,
typename... ArgTypes>
struct DartDispatcher<IndicesHolder<indices...>,
ReturnType (C::*)(ArgTypes...) const>
: public DartArgHolder<indices, ArgTypes>... {
using FunctionPtr = ReturnType (C::*)(ArgTypes...) const;
DartArgIterator* it_;
explicit DartDispatcher(DartArgIterator* it)
: DartArgHolder<indices, ArgTypes>(it)..., it_(it) {}
void Dispatch(FunctionPtr func) {
DartReturn((GetReceiver<C>(it_->args())->*func)(
DartArgHolder<indices, ArgTypes>::value...),
it_->args());
}
};
template <size_t... indices,
typename C,
typename ResultType,
typename... ArgTypes>
struct DartDispatcher<IndicesHolder<indices...>, ResultType (C::*)(ArgTypes...)>
: public DartArgHolder<indices, ArgTypes>... {
using FunctionPtr = ResultType (C::*)(ArgTypes...);
DartArgIterator* it_;
explicit DartDispatcher(DartArgIterator* it)
: DartArgHolder<indices, ArgTypes>(it)..., it_(it) {}
void Dispatch(FunctionPtr func) {
DartReturn((GetReceiver<C>(it_->args())->*func)(
DartArgHolder<indices, ArgTypes>::value...),
it_->args());
}
};
template <typename Sig>
void DartCall(Sig func, Dart_NativeArguments args) {
DartArgIterator it(args);
using Indices = typename IndicesForSignature<Sig>::type;
DartDispatcher<Indices, Sig> decoder(&it);
if (it.had_exception())
return;
decoder.Dispatch(func);
}
template <typename Sig>
void DartCallStatic(Sig func, Dart_NativeArguments args) {
DartArgIterator it(args, 0);
using Indices = typename IndicesForSignature<Sig>::type;
DartDispatcher<Indices, Sig> decoder(&it);
if (it.had_exception())
return;
decoder.Dispatch(func);
}
template <typename Sig>
void DartCallConstructor(Sig func, Dart_NativeArguments args) {
DartArgIterator it(args);
using Indices = typename IndicesForSignature<Sig>::type;
using Wrappable = typename DartDispatcher<Indices, Sig>::CtorResultType;
Wrappable wrappable;
{
DartDispatcher<Indices, Sig> decoder(&it);
if (it.had_exception())
return;
wrappable = decoder.DispatchCtor(func);
}
Dart_Handle wrapper = Dart_GetNativeArgument(args, 0);
TONIC_CHECK(!LogIfError(wrapper));
intptr_t native_fields[DartWrappable::kNumberOfNativeFields];
TONIC_CHECK(!LogIfError(Dart_GetNativeFieldsOfArgument(
args, 0, DartWrappable::kNumberOfNativeFields, native_fields)));
TONIC_CHECK(!native_fields[DartWrappable::kPeerIndex]);
TONIC_CHECK(!native_fields[DartWrappable::kWrapperInfoIndex]);
wrappable->AssociateWithDartWrapper(wrapper);
}
} // namespace tonic
#endif // LIB_TONIC_DART_ARGS_H_