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;
}
v8::Handle<v8::Object> GetThis() {
return info_->This();
}
#if NODE_VERSION_AT_LEAST(0, 11, 0)
template<typename T>
void Return(T val) {

View file

@ -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<v8::Function> Constructor::GetFunction(v8::Isolate* isolate) {
v8::Handle<v8::FunctionTemplate> Constructor::GetFunctionTemplate(
v8::Isolate* isolate) {
if (constructor_.IsEmpty()) {
v8::Local<v8::FunctionTemplate> 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<v8::ObjectTemplate> prototype) {
void Constructor::New(mate::Arguments* args) {
MATE_SET_INTERNAL_FIELD_POINTER(args->GetThis(), 0, factory_.Run());
}
} // namespace mate

View file

@ -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<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 {
public:
v8::Handle<v8::Function> GetFunction(v8::Isolate* isolate);
typedef base::Callback<Sig> 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<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,
v8::Handle<v8::ObjectTemplate> 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<v8::FunctionTemplate> 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
#endif // NATIVE_MATE_WRAPPABLE_CLASS_H_

View file

@ -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<v8::Object> Wrappable::GetWrapper(v8::Isolate* isolate) {
v8::Handle<v8::Object> WrappableBase::GetWrapperImpl(v8::Isolate* isolate) {
if (!wrapper_.IsEmpty()) {
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
// 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<v8::Value> 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<v8::Value> 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<typename T>
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<v8::Object> 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<v8::Object> BuildObject();
v8::Handle<v8::Object> GetWrapperImpl(v8::Isolate* isolate);
private:
static MATE_WEAK_CALLBACK(WeakCallback, v8::Object, Wrappable);
static MATE_WEAK_CALLBACK(WeakCallback, v8::Object, WrappableBase);
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);
};
// This converter handles any subclass of Wrappable.
// This converter handles any subclass of WrappableBase.
template<typename T>
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) {
return val->GetWrapper(isolate);
}
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)));
return *out != NULL;
}

View file

@ -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',