diff --git a/native_mate/arguments.h b/native_mate/arguments.h index 054e03abf84..ebe49e7c841 100644 --- a/native_mate/arguments.h +++ b/native_mate/arguments.h @@ -56,6 +56,10 @@ class Arguments { return true; } + v8::Handle GetThis() { + return info_->This(); + } + #if NODE_VERSION_AT_LEAST(0, 11, 0) template void Return(T val) { diff --git a/native_mate/constructor.cc b/native_mate/constructor.cc index 2ab6459e8d3..9c57fd09c31 100644 --- a/native_mate/constructor.cc +++ b/native_mate/constructor.cc @@ -4,39 +4,37 @@ #include "native_mate/constructor.h" +#include "base/bind.h" +#include "base/strings/string_piece.h" +#include "native_mate/arguments.h" #include "native_mate/function_template.h" -#include "native_mate/object_template_builder.h" namespace mate { -Constructor::Constructor(const base::StringPiece& name) : name_(name) { +Constructor::Constructor(const base::StringPiece& name, + const WrappableFactoryFunction& factory) + : name_(name), factory_(factory) { } -Constructor::~Constructor() { +virtual Constructor::~Constructor() { constructor_.Reset(); } -v8::Handle Constructor::GetFunction(v8::Isolate* isolate) { +v8::Handle Constructor::GetFunctionTemplate( + v8::Isolate* isolate) { if (constructor_.IsEmpty()) { v8::Local constructor = CreateFunctionTemplate( - isolate, - base::Bind(&Constructor::New, base::Unretained(this))); + isolate, base::Bind(&Constructor::New, base::Unretained(this))); constructor->InstanceTemplate()->SetInternalFieldCount(1); constructor->SetClassName(StringToV8(isolate, name_)); - SetPrototype(isolate, constructor->PrototypeTemplate()); - constructor_.Reset(isolate, constructor); } - return MATE_PERSISTENT_TO_LOCAL( - v8::FunctionTemplate, isolate, constructor_)->GetFunction(); + return MATE_PERSISTENT_TO_LOCAL(v8::FunctionTemplate, isolate, constructor_); } -void Constructor::New() { -} - -void Constructor::SetPrototype(v8::Isolate* isolate, - v8::Handle prototype) { +void Constructor::New(mate::Arguments* args) { + MATE_SET_INTERNAL_FIELD_POINTER(args->GetThis(), 0, factory_.Run()); } } // namespace mate diff --git a/native_mate/constructor.h b/native_mate/constructor.h index 45786fdb341..77446faee50 100644 --- a/native_mate/constructor.h +++ b/native_mate/constructor.h @@ -5,30 +5,176 @@ #ifndef NATIVE_MATE_WRAPPABLE_CLASS_H_ #define NATIVE_MATE_WRAPPABLE_CLASS_H_ -#include "native_mate/wrappable.h" +#include "base/bind.h" +#include "base/compiler_specific.h" +#include "base/strings/string_piece.h" +#include "native_mate/function_template.h" +#include "v8/include/v8.h" namespace mate { +class WrappableBase; + +namespace internal { + +// This set of templates invokes a base::Callback by converting the Arguments +// into native types. It relies on the function_template.h to provide helper +// templates. +inline WrappableBase* InvokeFactory( + Arguments* args, + const base::Callback& callback) { + return callback.Run(); +}; + +template +inline WrappableBase* InvokeFactory( + Arguments* args, + const base::Callback& callback) { + typename CallbackParamTraits::LocalType a1; + if (!GetNextArgument(args, 0, false, &a1)) + return NULL; + return callback.Run(a1); +}; + +template +inline WrappableBase* InvokeFactory( + Arguments* args, + const base::Callback& callback) { + typename CallbackParamTraits::LocalType a1; + typename CallbackParamTraits::LocalType a2; + if (!GetNextArgument(args, 0, true, &a1) || + !GetNextArgument(args, 0, false, &a2)) + return NULL; + return callback.Run(a1, a2); +}; + +template +inline WrappableBase* InvokeFactory( + Arguments* args, + const base::Callback& callback) { + typename CallbackParamTraits::LocalType a1; + typename CallbackParamTraits::LocalType a2; + typename CallbackParamTraits::LocalType a3; + if (!GetNextArgument(args, 0, true, &a1) || + !GetNextArgument(args, 0, false, &a2) || + !GetNextArgument(args, 0, false, &a3)) + return NULL; + return callback.Run(a1, a2, a3); +}; + +template +inline WrappableBase* InvokeFactory( + Arguments* args, + const base::Callback& callback) { + typename CallbackParamTraits::LocalType a1; + typename CallbackParamTraits::LocalType a2; + typename CallbackParamTraits::LocalType a3; + typename CallbackParamTraits::LocalType a4; + if (!GetNextArgument(args, 0, true, &a1) || + !GetNextArgument(args, 0, false, &a2) || + !GetNextArgument(args, 0, false, &a3) || + !GetNextArgument(args, 0, false, &a4)) + return NULL; + return callback.Run(a1, a2, a3, a4); +}; + +template +inline WrappableBase* InvokeFactory( + Arguments* args, + const base::Callback& callback) { + typename CallbackParamTraits::LocalType a1; + typename CallbackParamTraits::LocalType a2; + typename CallbackParamTraits::LocalType a3; + typename CallbackParamTraits::LocalType a4; + typename CallbackParamTraits::LocalType a5; + if (!GetNextArgument(args, 0, true, &a1) || + !GetNextArgument(args, 0, false, &a2) || + !GetNextArgument(args, 0, false, &a3) || + !GetNextArgument(args, 0, false, &a4) || + !GetNextArgument(args, 0, false, &a5)) + return NULL; + return callback.Run(a1, a2, a3, a4, a5); +}; + +template +inline WrappableBase* InvokeFactory( + Arguments* args, + const base::Callback& callback) { + typename CallbackParamTraits::LocalType a1; + typename CallbackParamTraits::LocalType a2; + typename CallbackParamTraits::LocalType a3; + typename CallbackParamTraits::LocalType a4; + typename CallbackParamTraits::LocalType a5; + typename CallbackParamTraits::LocalType a6; + if (!GetNextArgument(args, 0, true, &a1) || + !GetNextArgument(args, 0, false, &a2) || + !GetNextArgument(args, 0, false, &a3) || + !GetNextArgument(args, 0, false, &a4) || + !GetNextArgument(args, 0, false, &a5) || + !GetNextArgument(args, 0, false, &a6)) + return NULL; + return callback.Run(a1, a2, a3, a4, a5, a6); +}; + +} // namespace internal + + +template class Constructor { public: - v8::Handle GetFunction(v8::Isolate* isolate); + typedef base::Callback WrappableFactoryFunction; - protected: - Constructor(const base::StringPiece& name); - virtual ~Constructor(); + Constructor(const base::StringPiece& name) : name_(name) {} + virtual ~Constructor() { + constructor_.Reset(); + } - virtual void New() = 0; + v8::Handle GetFunctionTemplate( + v8::Isolate* isolate, const WrappableFactoryFunction& factory) { + if (constructor_.IsEmpty()) { + v8::Local constructor = CreateFunctionTemplate( + isolate, base::Bind(&Constructor::New, factory)); + constructor->InstanceTemplate()->SetInternalFieldCount(1); + constructor->SetClassName(StringToV8(isolate, name_)); + constructor_.Reset(isolate, constructor); + } - virtual void SetPrototype(v8::Isolate* isolate, - v8::Handle prototype); + return MATE_PERSISTENT_TO_LOCAL( + v8::FunctionTemplate, isolate, constructor_); + } private: + static void New(const WrappableFactoryFunction& factory, Arguments* args) { + WrappableBase* object = internal::InvokeFactory(args, factory); + if (object) + MATE_SET_INTERNAL_FIELD_POINTER(args->GetThis(), 0, object); + else + args->ThrowError(); + + MATE_METHOD_RETURN_UNDEFINED(); + } + base::StringPiece name_; v8::Persistent constructor_; DISALLOW_COPY_AND_ASSIGN(Constructor); }; + +template +WrappableBase* NewOperatorFactory() { + return new T; +} + +template +v8::Local CreateConstructor( + v8::Isolate* isolate, + const base::StringPiece& name, + const base::Callback& constructor) { + return Constructor(name).GetFunctionTemplate(isolate, constructor); +} + } // namespace mate #endif // NATIVE_MATE_WRAPPABLE_CLASS_H_ diff --git a/native_mate/wrappable.cc b/native_mate/wrappable.cc index 77bd721ad2f..e6dd876e966 100644 --- a/native_mate/wrappable.cc +++ b/native_mate/wrappable.cc @@ -9,26 +9,26 @@ namespace mate { -Wrappable::Wrappable() { +WrappableBase::WrappableBase() { } -Wrappable::~Wrappable() { +WrappableBase::~WrappableBase() { MATE_PERSISTENT_RESET(wrapper_); } -ObjectTemplateBuilder Wrappable::GetObjectTemplateBuilder( +ObjectTemplateBuilder WrappableBase::GetObjectTemplateBuilder( v8::Isolate* isolate) { return ObjectTemplateBuilder(isolate); } // static -MATE_WEAK_CALLBACK(Wrappable::WeakCallback, v8::Object, Wrappable) { - MATE_WEAK_CALLBACK_INIT(Wrappable); +MATE_WEAK_CALLBACK(WrappableBase::WeakCallback, v8::Object, WrappableBase) { + MATE_WEAK_CALLBACK_INIT(WrappableBase); MATE_PERSISTENT_RESET(self->wrapper_); delete self; } -v8::Handle Wrappable::GetWrapper(v8::Isolate* isolate) { +v8::Handle WrappableBase::GetWrapperImpl(v8::Isolate* isolate) { if (!wrapper_.IsEmpty()) { return MATE_PERSISTENT_TO_LOCAL(v8::Object, isolate, wrapper_); } diff --git a/native_mate/wrappable.h b/native_mate/wrappable.h index b6b80789887..10391fae1d1 100644 --- a/native_mate/wrappable.h +++ b/native_mate/wrappable.h @@ -18,12 +18,12 @@ void* FromV8Impl(v8::Isolate* isolate, v8::Handle val); } // namespace internal -// Wrappable is a base class for C++ objects that have corresponding v8 wrapper -// objects. To retain a Wrappable object on the stack, use a mate::Handle. +// WrappableBase is a base class for C++ objects that have corresponding v8 wrapper +// objects. To retain a WrappableBase object on the stack, use a mate::Handle. // // USAGE: // // my_class.h -// class MyClass : Wrappable { +// class MyClass : WrappableBase { // public: // // Optional, only required if non-empty template should be used. // virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder( @@ -33,7 +33,7 @@ void* FromV8Impl(v8::Isolate* isolate, v8::Handle val); // // mate::ObjectTemplateBuilder MyClass::GetObjectTemplateBuilder( // v8::Isolate* isolate) { -// return Wrappable::GetObjectTemplateBuilder(isolate).SetValue("foobar", 42); +// return WrappableBase::GetObjectTemplateBuilder(isolate).SetValue("foobar", 42); // } // // Subclasses should also typically have private constructors and expose a @@ -42,43 +42,57 @@ void* FromV8Impl(v8::Isolate* isolate, v8::Handle val); // wrapper for the object. If clients fail to create a wrapper for a wrappable // object, the object will leak because we use the weak callback from the // wrapper as the signal to delete the wrapped object. +template +class Wrappable; + class ObjectTemplateBuilder; // Non-template base class to share code between templates instances. -class Wrappable { - public: - // Retrieve (or create) the v8 wrapper object cooresponding to this object. - v8::Handle GetWrapper(v8::Isolate* isolate); - +class WrappableBase { protected: - Wrappable(); - virtual ~Wrappable(); + WrappableBase(); + virtual ~WrappableBase(); virtual ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate); - // Override to change how the v8 wrapper is built (by default it was built - // from the ObjectTemplateBuilder. - // virtual v8::Handle BuildObject(); + v8::Handle GetWrapperImpl(v8::Isolate* isolate); private: - static MATE_WEAK_CALLBACK(WeakCallback, v8::Object, Wrappable); + static MATE_WEAK_CALLBACK(WeakCallback, v8::Object, WrappableBase); v8::Persistent wrapper_; // Weak + DISALLOW_COPY_AND_ASSIGN(WrappableBase); +}; + + +template +class Wrappable : public WrappableBase { + public: + // Retrieve (or create) the v8 wrapper object cooresponding to this object. + v8::Handle GetWrapper(v8::Isolate* isolate) { + return GetWrapperImpl(isolate); + } + + protected: + Wrappable() {} + virtual ~Wrappable() {} + + private: DISALLOW_COPY_AND_ASSIGN(Wrappable); }; -// This converter handles any subclass of Wrappable. +// This converter handles any subclass of WrappableBase. template struct Converter::value>::type> { + is_convertible::value>::type> { static v8::Handle ToV8(v8::Isolate* isolate, T* val) { return val->GetWrapper(isolate); } static bool FromV8(v8::Isolate* isolate, v8::Handle val, T** out) { - *out = static_cast(static_cast( + *out = static_cast(static_cast( internal::FromV8Impl(isolate, val))); return *out != NULL; } diff --git a/native_mate_files.gypi b/native_mate_files.gypi index 934c91f2323..944483e4863 100644 --- a/native_mate_files.gypi +++ b/native_mate_files.gypi @@ -4,7 +4,7 @@ 'native_mate/arguments.cc', 'native_mate/arguments.h', 'native_mate/compat.h', - 'native_mate/constructor.cc', +# 'native_mate/constructor.cc', 'native_mate/constructor.h', 'native_mate/converter.cc', 'native_mate/converter.h',