Make the Constructor accept arbitrary callback.

This commit is contained in:
Cheng Zhao 2014-04-16 09:50:51 +08:00
parent 78ab726ec7
commit e2e1faa225
6 changed files with 210 additions and 48 deletions

View file

@ -56,6 +56,10 @@ class Arguments {
return true; return true;
} }
v8::Handle<v8::Object> GetThis() {
return info_->This();
}
#if NODE_VERSION_AT_LEAST(0, 11, 0) #if NODE_VERSION_AT_LEAST(0, 11, 0)
template<typename T> template<typename T>
void Return(T val) { void Return(T val) {

View file

@ -4,39 +4,37 @@
#include "native_mate/constructor.h" #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/function_template.h"
#include "native_mate/object_template_builder.h"
namespace mate { 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(); constructor_.Reset();
} }
v8::Handle<v8::Function> Constructor::GetFunction(v8::Isolate* isolate) { v8::Handle<v8::FunctionTemplate> Constructor::GetFunctionTemplate(
v8::Isolate* isolate) {
if (constructor_.IsEmpty()) { if (constructor_.IsEmpty()) {
v8::Local<v8::FunctionTemplate> constructor = CreateFunctionTemplate( v8::Local<v8::FunctionTemplate> constructor = CreateFunctionTemplate(
isolate, isolate, base::Bind(&Constructor::New, base::Unretained(this)));
base::Bind(&Constructor::New, base::Unretained(this)));
constructor->InstanceTemplate()->SetInternalFieldCount(1); constructor->InstanceTemplate()->SetInternalFieldCount(1);
constructor->SetClassName(StringToV8(isolate, name_)); constructor->SetClassName(StringToV8(isolate, name_));
SetPrototype(isolate, constructor->PrototypeTemplate());
constructor_.Reset(isolate, constructor); constructor_.Reset(isolate, constructor);
} }
return MATE_PERSISTENT_TO_LOCAL( return MATE_PERSISTENT_TO_LOCAL(v8::FunctionTemplate, isolate, constructor_);
v8::FunctionTemplate, isolate, constructor_)->GetFunction();
} }
void Constructor::New() { void Constructor::New(mate::Arguments* args) {
} MATE_SET_INTERNAL_FIELD_POINTER(args->GetThis(), 0, factory_.Run());
void Constructor::SetPrototype(v8::Isolate* isolate,
v8::Handle<v8::ObjectTemplate> prototype) {
} }
} // namespace mate } // namespace mate

View file

@ -5,30 +5,176 @@
#ifndef NATIVE_MATE_WRAPPABLE_CLASS_H_ #ifndef NATIVE_MATE_WRAPPABLE_CLASS_H_
#define 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 { 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<WrappableBase*()>& callback) {
return callback.Run();
};
template<typename P1>
inline WrappableBase* InvokeFactory(
Arguments* args,
const base::Callback<WrappableBase*(P1)>& callback) {
typename CallbackParamTraits<P1>::LocalType a1;
if (!GetNextArgument(args, 0, false, &a1))
return NULL;
return callback.Run(a1);
};
template<typename P1, typename P2>
inline WrappableBase* InvokeFactory(
Arguments* args,
const base::Callback<WrappableBase*(P1, P2)>& callback) {
typename CallbackParamTraits<P1>::LocalType a1;
typename CallbackParamTraits<P2>::LocalType a2;
if (!GetNextArgument(args, 0, true, &a1) ||
!GetNextArgument(args, 0, false, &a2))
return NULL;
return callback.Run(a1, a2);
};
template<typename P1, typename P2, typename P3>
inline WrappableBase* InvokeFactory(
Arguments* args,
const base::Callback<WrappableBase*(P1, P2, P3)>& callback) {
typename CallbackParamTraits<P1>::LocalType a1;
typename CallbackParamTraits<P2>::LocalType a2;
typename CallbackParamTraits<P3>::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<typename P1, typename P2, typename P3, typename P4>
inline WrappableBase* InvokeFactory(
Arguments* args,
const base::Callback<WrappableBase*(P1, P2, P3, P4)>& callback) {
typename CallbackParamTraits<P1>::LocalType a1;
typename CallbackParamTraits<P2>::LocalType a2;
typename CallbackParamTraits<P3>::LocalType a3;
typename CallbackParamTraits<P4>::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<typename P1, typename P2, typename P3, typename P4, typename P5>
inline WrappableBase* InvokeFactory(
Arguments* args,
const base::Callback<WrappableBase*(P1, P2, P3, P4, P5)>& callback) {
typename CallbackParamTraits<P1>::LocalType a1;
typename CallbackParamTraits<P2>::LocalType a2;
typename CallbackParamTraits<P3>::LocalType a3;
typename CallbackParamTraits<P4>::LocalType a4;
typename CallbackParamTraits<P5>::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<typename P1, typename P2, typename P3, typename P4, typename P5,
typename P6>
inline WrappableBase* InvokeFactory(
Arguments* args,
const base::Callback<WrappableBase*(P1, P2, P3, P4, P5, P6)>& callback) {
typename CallbackParamTraits<P1>::LocalType a1;
typename CallbackParamTraits<P2>::LocalType a2;
typename CallbackParamTraits<P3>::LocalType a3;
typename CallbackParamTraits<P4>::LocalType a4;
typename CallbackParamTraits<P5>::LocalType a5;
typename CallbackParamTraits<P6>::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<typename Sig>
class Constructor { class Constructor {
public: public:
v8::Handle<v8::Function> GetFunction(v8::Isolate* isolate); typedef base::Callback<Sig> WrappableFactoryFunction;
protected: Constructor(const base::StringPiece& name) : name_(name) {}
Constructor(const base::StringPiece& name); virtual ~Constructor() {
virtual ~Constructor(); constructor_.Reset();
}
virtual void New() = 0; v8::Handle<v8::FunctionTemplate> GetFunctionTemplate(
v8::Isolate* isolate, const WrappableFactoryFunction& factory) {
if (constructor_.IsEmpty()) {
v8::Local<v8::FunctionTemplate> 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, return MATE_PERSISTENT_TO_LOCAL(
v8::Handle<v8::ObjectTemplate> prototype); v8::FunctionTemplate, isolate, constructor_);
}
private: 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_; base::StringPiece name_;
v8::Persistent<v8::FunctionTemplate> constructor_; v8::Persistent<v8::FunctionTemplate> constructor_;
DISALLOW_COPY_AND_ASSIGN(Constructor); DISALLOW_COPY_AND_ASSIGN(Constructor);
}; };
template<typename T>
WrappableBase* NewOperatorFactory() {
return new T;
}
template<typename Sig>
v8::Local<v8::FunctionTemplate> CreateConstructor(
v8::Isolate* isolate,
const base::StringPiece& name,
const base::Callback<Sig>& constructor) {
return Constructor<Sig>(name).GetFunctionTemplate(isolate, constructor);
}
} // namespace mate } // namespace mate
#endif // NATIVE_MATE_WRAPPABLE_CLASS_H_ #endif // NATIVE_MATE_WRAPPABLE_CLASS_H_

View file

@ -9,26 +9,26 @@
namespace mate { namespace mate {
Wrappable::Wrappable() { WrappableBase::WrappableBase() {
} }
Wrappable::~Wrappable() { WrappableBase::~WrappableBase() {
MATE_PERSISTENT_RESET(wrapper_); MATE_PERSISTENT_RESET(wrapper_);
} }
ObjectTemplateBuilder Wrappable::GetObjectTemplateBuilder( ObjectTemplateBuilder WrappableBase::GetObjectTemplateBuilder(
v8::Isolate* isolate) { v8::Isolate* isolate) {
return ObjectTemplateBuilder(isolate); return ObjectTemplateBuilder(isolate);
} }
// static // static
MATE_WEAK_CALLBACK(Wrappable::WeakCallback, v8::Object, Wrappable) { MATE_WEAK_CALLBACK(WrappableBase::WeakCallback, v8::Object, WrappableBase) {
MATE_WEAK_CALLBACK_INIT(Wrappable); MATE_WEAK_CALLBACK_INIT(WrappableBase);
MATE_PERSISTENT_RESET(self->wrapper_); MATE_PERSISTENT_RESET(self->wrapper_);
delete self; delete self;
} }
v8::Handle<v8::Object> Wrappable::GetWrapper(v8::Isolate* isolate) { v8::Handle<v8::Object> WrappableBase::GetWrapperImpl(v8::Isolate* isolate) {
if (!wrapper_.IsEmpty()) { if (!wrapper_.IsEmpty()) {
return MATE_PERSISTENT_TO_LOCAL(v8::Object, isolate, wrapper_); return MATE_PERSISTENT_TO_LOCAL(v8::Object, isolate, wrapper_);
} }

View file

@ -18,12 +18,12 @@ void* FromV8Impl(v8::Isolate* isolate, v8::Handle<v8::Value> val);
} // namespace internal } // namespace internal
// Wrappable is a base class for C++ objects that have corresponding v8 wrapper // WrappableBase 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. // objects. To retain a WrappableBase object on the stack, use a mate::Handle.
// //
// USAGE: // USAGE:
// // my_class.h // // my_class.h
// class MyClass : Wrappable { // class MyClass : WrappableBase {
// public: // public:
// // Optional, only required if non-empty template should be used. // // Optional, only required if non-empty template should be used.
// virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder( // virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
@ -33,7 +33,7 @@ void* FromV8Impl(v8::Isolate* isolate, v8::Handle<v8::Value> val);
// //
// mate::ObjectTemplateBuilder MyClass::GetObjectTemplateBuilder( // mate::ObjectTemplateBuilder MyClass::GetObjectTemplateBuilder(
// v8::Isolate* isolate) { // 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 // Subclasses should also typically have private constructors and expose a
@ -42,43 +42,57 @@ void* FromV8Impl(v8::Isolate* isolate, v8::Handle<v8::Value> val);
// wrapper for the object. If clients fail to create a wrapper for a wrappable // 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 // object, the object will leak because we use the weak callback from the
// wrapper as the signal to delete the wrapped object. // wrapper as the signal to delete the wrapped object.
template<typename T>
class Wrappable;
class ObjectTemplateBuilder; class ObjectTemplateBuilder;
// Non-template base class to share code between templates instances. // Non-template base class to share code between templates instances.
class Wrappable { class WrappableBase {
public:
// Retrieve (or create) the v8 wrapper object cooresponding to this object.
v8::Handle<v8::Object> GetWrapper(v8::Isolate* isolate);
protected: protected:
Wrappable(); WrappableBase();
virtual ~Wrappable(); virtual ~WrappableBase();
virtual ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate); virtual ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate);
// Override to change how the v8 wrapper is built (by default it was built v8::Handle<v8::Object> GetWrapperImpl(v8::Isolate* isolate);
// from the ObjectTemplateBuilder.
// virtual v8::Handle<v8::Object> BuildObject();
private: private:
static MATE_WEAK_CALLBACK(WeakCallback, v8::Object, Wrappable); static MATE_WEAK_CALLBACK(WeakCallback, v8::Object, WrappableBase);
v8::Persistent<v8::Object> wrapper_; // Weak v8::Persistent<v8::Object> wrapper_; // Weak
DISALLOW_COPY_AND_ASSIGN(WrappableBase);
};
template<typename T>
class Wrappable : public WrappableBase {
public:
// Retrieve (or create) the v8 wrapper object cooresponding to this object.
v8::Handle<v8::Object> GetWrapper(v8::Isolate* isolate) {
return GetWrapperImpl(isolate);
}
protected:
Wrappable() {}
virtual ~Wrappable() {}
private:
DISALLOW_COPY_AND_ASSIGN(Wrappable); DISALLOW_COPY_AND_ASSIGN(Wrappable);
}; };
// This converter handles any subclass of Wrappable. // This converter handles any subclass of WrappableBase.
template<typename T> template<typename T>
struct Converter<T*, typename enable_if< struct Converter<T*, typename enable_if<
is_convertible<T*, Wrappable*>::value>::type> { is_convertible<T*, WrappableBase*>::value>::type> {
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate, T* val) { static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate, T* val) {
return val->GetWrapper(isolate); return val->GetWrapper(isolate);
} }
static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val, T** out) { static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val, T** out) {
*out = static_cast<T*>(static_cast<Wrappable*>( *out = static_cast<T*>(static_cast<WrappableBase*>(
internal::FromV8Impl(isolate, val))); internal::FromV8Impl(isolate, val)));
return *out != NULL; return *out != NULL;
} }

View file

@ -4,7 +4,7 @@
'native_mate/arguments.cc', 'native_mate/arguments.cc',
'native_mate/arguments.h', 'native_mate/arguments.h',
'native_mate/compat.h', 'native_mate/compat.h',
'native_mate/constructor.cc', # 'native_mate/constructor.cc',
'native_mate/constructor.h', 'native_mate/constructor.h',
'native_mate/converter.cc', 'native_mate/converter.cc',
'native_mate/converter.h', 'native_mate/converter.h',