1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef GIN_WRAPPABLE_H_
6 #define GIN_WRAPPABLE_H_
10 #include "gin/converter.h"
11 #include "gin/gin_export.h"
12 #include "gin/public/wrapper_info.h"
16 // Wrappable is a base class for C++ objects that have corresponding v8 wrapper
17 // objects. To retain a Wrappable object on the stack, use a gin::Handle.
21 // class MyClass : Wrappable<MyClass> {
23 // static WrapperInfo kWrapperInfo;
25 // // Optional, only required if non-empty template should be used.
26 // virtual gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
27 // v8::Isolate* isolate);
32 // WrapperInfo MyClass::kWrapperInfo = {kEmbedderNativeGin};
34 // gin::ObjectTemplateBuilder MyClass::GetObjectTemplateBuilder(
35 // v8::Isolate* isolate) {
36 // return Wrappable<MyClass>::GetObjectTemplateBuilder(isolate)
37 // .SetValue("foobar", 42);
40 // Subclasses should also typically have private constructors and expose a
41 // static Create function that returns a gin::Handle. Forcing creators through
42 // this static Create function will enforce that clients actually create a
43 // wrapper for the object. If clients fail to create a wrapper for a wrappable
44 // object, the object will leak because we use the weak callback from the
45 // wrapper as the signal to delete the wrapped object.
47 // Wrappable<T> explicitly does not support further subclassing of T.
48 // Subclasses of Wrappable<T> should be declared final. Because Wrappable<T>
49 // caches the object template using &T::kWrapperInfo as the key, all subclasses
50 // would share a single object template. This will lead to hard to debug crashes
51 // that look like use-after-free errors.
55 GIN_EXPORT void* FromV8Impl(v8::Isolate* isolate,
56 v8::Local<v8::Value> val,
59 } // namespace internal
61 class ObjectTemplateBuilder;
63 // Non-template base class to share code between templates instances.
64 class GIN_EXPORT WrappableBase {
66 WrappableBase(const WrappableBase&) = delete;
67 WrappableBase& operator=(const WrappableBase&) = delete;
71 virtual ~WrappableBase();
73 // Overrides of this method should be declared final and not overridden again.
74 virtual ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate);
76 // Returns a readable type name that will be used in surfacing errors. The
77 // default implementation returns nullptr, which results in a generic error.
78 virtual const char* GetTypeName();
80 v8::MaybeLocal<v8::Object> GetWrapperImpl(v8::Isolate* isolate,
81 WrapperInfo* wrapper_info);
84 static void FirstWeakCallback(
85 const v8::WeakCallbackInfo<WrappableBase>& data);
86 static void SecondWeakCallback(
87 const v8::WeakCallbackInfo<WrappableBase>& data);
90 v8::Global<v8::Object> wrapper_; // Weak
95 class Wrappable : public WrappableBase {
97 Wrappable(const Wrappable&) = delete;
98 Wrappable& operator=(const Wrappable&) = delete;
100 // Retrieve (or create) the v8 wrapper object corresponding to this object.
101 v8::MaybeLocal<v8::Object> GetWrapper(v8::Isolate* isolate) {
102 return GetWrapperImpl(isolate, &T::kWrapperInfo);
106 Wrappable() = default;
107 ~Wrappable() override = default;
110 template <typename T>
111 struct ToV8ReturnsMaybe<
113 typename std::enable_if<
114 std::is_convertible<T*, WrappableBase*>::value>::type> {
115 static const bool value = true;
118 // This converter handles any subclass of Wrappable.
119 template <typename T>
121 typename std::enable_if<
122 std::is_convertible<T*, WrappableBase*>::value>::type> {
123 static v8::MaybeLocal<v8::Value> ToV8(v8::Isolate* isolate, T* val) {
125 return v8::Null(isolate);
126 v8::Local<v8::Object> wrapper;
127 if (!val->GetWrapper(isolate).ToLocal(&wrapper))
128 return v8::MaybeLocal<v8::Value>();
129 return v8::MaybeLocal<v8::Value>(wrapper);
132 static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val, T** out) {
133 *out = static_cast<T*>(static_cast<WrappableBase*>(
134 internal::FromV8Impl(isolate, val, &T::kWrapperInfo)));
141 #endif // GIN_WRAPPABLE_H_