| // Copyright 2015 The Chromium 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 TONIC_DART_WRAPPABLE_H_ |
| #define TONIC_DART_WRAPPABLE_H_ |
| |
| #include "base/logging.h" |
| #include "base/template_util.h" |
| #include "dart/runtime/include/dart_api.h" |
| #include "tonic/dart_converter.h" |
| #include "tonic/dart_error.h" |
| #include "tonic/dart_state.h" |
| #include "tonic/dart_wrapper_info.h" |
| |
| namespace tonic { |
| class DartGCVisitor; |
| struct DartWrapperInfo; |
| |
| // DartWrappable is a base class that you can inherit from in order to be |
| // exposed to Dart code as an interface. |
| class DartWrappable { |
| public: |
| enum DartNativeFields { |
| kPeerIndex, // Must be first to work with Dart_GetNativeReceiver. |
| kWrapperInfoIndex, |
| kNumberOfNativeFields, |
| }; |
| |
| DartWrappable() : dart_wrapper_(nullptr) {} |
| |
| // Subclasses that wish to expose a new interface must override this function |
| // and provide information about their wrapper. There is no need to call your |
| // base class's implementation of this function. |
| virtual const DartWrapperInfo& GetDartWrapperInfo() const = 0; |
| |
| // Subclasses that wish to integrate with the Dart garbage collector should |
| // override this function. Please call your base class's AcceptDartGCVisitor |
| // at the end of your override. |
| virtual void AcceptDartGCVisitor(DartGCVisitor& visitor) const; |
| |
| Dart_Handle CreateDartWrapper(DartState* dart_state); |
| void AssociateWithDartWrapper(Dart_NativeArguments args); |
| Dart_WeakPersistentHandle dart_wrapper() const { return dart_wrapper_; } |
| |
| protected: |
| virtual ~DartWrappable(); |
| |
| private: |
| static void FinalizeDartWrapper(void* isolate_callback_data, |
| Dart_WeakPersistentHandle wrapper, |
| void* peer); |
| |
| Dart_WeakPersistentHandle dart_wrapper_; |
| |
| DISALLOW_COPY_AND_ASSIGN(DartWrappable); |
| }; |
| |
| #define DEFINE_WRAPPERTYPEINFO() \ |
| public: \ |
| const DartWrapperInfo& GetDartWrapperInfo() const override { \ |
| return dart_wrapper_info_; \ |
| } \ |
| private: \ |
| static const DartWrapperInfo& dart_wrapper_info_ |
| |
| struct DartConverterWrappable { |
| static DartWrappable* FromDart(Dart_Handle handle); |
| static DartWrappable* FromArguments(Dart_NativeArguments args, |
| int index, |
| Dart_Handle& exception); |
| static DartWrappable* FromArgumentsWithNullCheck(Dart_NativeArguments args, |
| int index, |
| Dart_Handle& exception); |
| }; |
| |
| template<typename T> |
| struct DartConverter< |
| T*, |
| typename base::enable_if< |
| base::is_convertible<T*, DartWrappable*>::value>::type> { |
| static Dart_Handle ToDart(DartWrappable* val) { |
| if (!val) |
| return Dart_Null(); |
| if (Dart_WeakPersistentHandle wrapper = val->dart_wrapper()) |
| return Dart_HandleFromWeakPersistent(wrapper); |
| return val->CreateDartWrapper(DartState::Current()); |
| } |
| |
| static void SetReturnValue(Dart_NativeArguments args, |
| DartWrappable* val, |
| bool auto_scope = true) { |
| if (!val) |
| Dart_SetReturnValue(args, Dart_Null()); |
| else if (Dart_WeakPersistentHandle wrapper = val->dart_wrapper()) |
| Dart_SetWeakHandleReturnValue(args, wrapper); |
| else |
| Dart_SetReturnValue(args, val->CreateDartWrapper(DartState::Current())); |
| } |
| |
| static T* FromDart(Dart_Handle handle) { |
| // TODO(abarth): We're missing a type check. |
| return static_cast<T*>(DartConverterWrappable::FromDart(handle)); |
| } |
| |
| static T* FromArguments(Dart_NativeArguments args, |
| int index, |
| Dart_Handle& exception, |
| bool auto_scope = true) { |
| // TODO(abarth): We're missing a type check. |
| return static_cast<T*>(DartConverterWrappable::FromArguments( |
| args, index, exception)); |
| } |
| |
| static T* FromArgumentsWithNullCheck(Dart_NativeArguments args, |
| int index, |
| Dart_Handle& exception, |
| bool auto_scope = true) { |
| // TODO(abarth): We're missing a type check. |
| return static_cast<T*>(DartConverterWrappable::FromArgumentsWithNullCheck( |
| args, index, exception)); |
| } |
| }; |
| |
| template<typename T> |
| inline T* GetReceiver(Dart_NativeArguments args) { |
| intptr_t receiver; |
| Dart_Handle result = Dart_GetNativeReceiver(args, &receiver); |
| DCHECK(!Dart_IsError(result)); |
| return static_cast<T*>(reinterpret_cast<DartWrappable*>(receiver)); |
| } |
| |
| } // namespace tonic |
| |
| #endif // TONIC_DART_WRAPPABLE_H_ |