Browse files

1.2: support instanceof for C++ embedded types and vu8::NoFactory.

  • Loading branch information...
1 parent 11e42b0 commit 1a154f224beb2e2a20b7fc42caa5cd3c43386f7c jpike committed Jun 27, 2012
Showing with 66 additions and 22 deletions.
  1. +4 −2 README.markdown
  2. +54 −15 src/vu8/Class.hpp
  3. +3 −0 src/vu8/Factory.hpp
  4. +3 −5 src/vu8/Module.hpp
  5. +2 −0 src/vu8/test/file.js
View
6 README.markdown
@@ -164,7 +164,9 @@ console.println("exit")
## Create a handle to an externally referenced C++ class.
```c++
// Memory for C++ class will remain when JavaScript object is deleted.
-typedef vu8::Class<MyClass> classWrapper;
+// vu8::NoFactory avoids creating any constructor for your C++ class from
+// JavaScript, useful for classes you only wish to inject.
+typedef vu8::Class<MyClass, vu8::NoFactory> classWrapper;
v8::Handle<v8::Value> val = classWrapper::ReferenceExternal(&MyClass::instance());
// Assuming MyClass::instance() returns reference to class
```
@@ -173,7 +175,7 @@ v8::Handle<v8::Value> val = classWrapper::ReferenceExternal(&MyClass::instance()
```c++
// Memory for c++ object will be reclaimed by JavaScript using "delete" when
// JavaScript class is deleted.
-typedef vu8::Class<MyClass> classWrapper;
+typedef vu8::Class<MyClass, vu8::NoFactory> classWrapper;
v8::Handle<v8::Value> val = classWrapper::ImportExternal(new MyClass());
```
View
69 src/vu8/Class.hpp
@@ -29,23 +29,57 @@ struct Class;
template <class T>
struct Singleton;
+template <class M, class Factory>
+class ClassSingletonFactory {
+
+ M& mixin() { return static_cast<M &>(*this); }
+
+ static inline ValueHandle ConstructorFunction(const v8::Arguments& args) {
+ return M::Instance().WrapObject(args);
+ }
+
+ public:
+ v8::Persistent<v8::FunctionTemplate>& JSFunctionTemplateHelper() {
+ return mixin().jsFunc_;
+ }
+
+ enum { HAS_NULL_FACTORY = false };
+
+ ClassSingletonFactory()
+ : jsFunc_(v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(
+ &ConstructorFunction)))
+ {}
+
+ v8::Persistent<v8::FunctionTemplate> jsFunc_;
+};
+
+template <class M>
+struct ClassSingletonFactory<M, NoFactory> {
+ enum { HAS_NULL_FACTORY = true };
+
+ v8::Persistent<v8::FunctionTemplate>& JSFunctionTemplateHelper() {
+ return static_cast<M &>(*this).func_;
+ }
+};
+
template <class T, class Factory>
-class ClassSingleton : detail::LazySingleton< ClassSingleton<T, Factory> > {
+class ClassSingleton
+ : detail::LazySingleton< ClassSingleton<T, Factory> >,
+ public ClassSingletonFactory<ClassSingleton<T, Factory>, Factory>
+{
+ friend class ClassSingletonFactory<ClassSingleton<T, Factory>, Factory>;
typedef ClassSingleton<T, Factory> self;
typedef ValueHandle (T::*MethodCallback)(const v8::Arguments& args);
- v8::Persistent<v8::FunctionTemplate>& FunctionTemplate() {
+ v8::Persistent<v8::FunctionTemplate>& ClassFunctionTemplate() {
return func_;
}
- public:
- static inline ValueHandle ConstructorFunction(const v8::Arguments& args) {
- return self::Instance().WrapObject(args);
+ v8::Persistent<v8::FunctionTemplate>& JSFunctionTemplate() {
+ return this->JSFunctionTemplateHelper();
}
- private:
-
// invoke passing javascript object argument directly
template <class P>
static inline typename boost::enable_if<
@@ -116,9 +150,10 @@ class ClassSingleton : detail::LazySingleton< ClassSingleton<T, Factory> > {
}
ClassSingleton()
- : func_(v8::Persistent<v8::FunctionTemplate>::New(
- v8::FunctionTemplate::New()))
+ : func_(v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New()))
{
+ if (! this->HAS_NULL_FACTORY)
+ func_->Inherit(JSFunctionTemplate());
func_->InstanceTemplate()->SetInternalFieldCount(1);
}
@@ -145,7 +180,7 @@ struct Class {
// method helper
template <class P>
inline Class& Method(char const *name) {
- FunctionTemplate()->PrototypeTemplate()->Set(
+ ClassFunctionTemplate()->PrototypeTemplate()->Set(
v8::String::New(name),
v8::FunctionTemplate::New(&singleton_t::template Forward<P>));
return *this;
@@ -175,8 +210,12 @@ struct Class {
return Method<ValueHandle(const v8::Arguments&), Ptr>(name);
}
- inline v8::Persistent<v8::FunctionTemplate>& FunctionTemplate() {
- return Instance().FunctionTemplate();
+ inline v8::Persistent<v8::FunctionTemplate>& ClassFunctionTemplate() {
+ return Instance().ClassFunctionTemplate();
+ }
+
+ inline v8::Persistent<v8::FunctionTemplate>& JSFunctionTemplate() {
+ return Instance().JSFunctionTemplate();
}
// create javascript object which references externally created C++
@@ -207,7 +246,7 @@ struct Class {
template <class U, class V>
Class(Class<U, V>& parent) {
- FunctionTemplate()->Inherit(parent.FunctionTemplate());
+ JSFunctionTemplate()->Inherit(parent.ClassFunctionTemplate());
}
Class() {}
@@ -216,12 +255,12 @@ struct Class {
// Wrap a C++ singleton
template <class T>
-struct Singleton : Class<T> {
+struct Singleton : Class<T, NoFactory> {
typedef Class<T> base;
template <class U, class V>
Singleton(Class<U, V>& parent, T* instance) : instance_(instance) {
- base::FunctionTemplate()->Inherit(parent.FunctionTemplate());
+ base::JSFunctionTemplate()->Inherit(parent.ClassFunctionTemplate());
}
Singleton(T *instance) : instance_(instance) {}
View
3 src/vu8/Factory.hpp
@@ -26,6 +26,9 @@ struct none {};
// Factory that calls C++ constructor with v8::Arguments directly
struct V8ArgFactory {};
+// Factory that prevents class from being constructed in JavaScript
+struct NoFactory {};
+
// primary template
template <BOOST_PP_ENUM(VU8_FACTORY_MAX_SIZE, VU8_FACTORY_header, ~)>
struct Factory;
View
8 src/vu8/Module.hpp
@@ -33,19 +33,17 @@ struct Module {
template <class T, class F>
inline Module& operator()(char const *name, Class<T, F>& clss) {
- obj_->Set(v8::String::New(name),
- v8::FunctionTemplate::New(
- &Class<T, F>::singleton_t::ConstructorFunction));
+ obj_->Set(v8::String::New(name), clss.JSFunctionTemplate()->GetFunction());
- clss.FunctionTemplate()->SetClassName(v8::String::New(name));
+ clss.ClassFunctionTemplate()->SetClassName(v8::String::New(name));
return *this;
}
template <class T>
inline Module& operator()(char const *name, Singleton<T>& singleton) {
obj_->Set(v8::String::New(name), singleton.NewInstance());
- singleton.FunctionTemplate()->SetClassName(v8::String::New(name));
+ singleton.ClassFunctionTemplate()->SetClassName(v8::String::New(name));
return *this;
}
View
2 src/vu8/test/file.js
@@ -4,6 +4,8 @@ var file = vu8.load('file'),
var write1 = new file.Writer()
var write2 = new file.Writer("bunko")
+console.log("write1 is Writer", file.Writer, write1, (write1 instanceof file.Writer))
+
if (! write1.open("punko") || ! write2.is_open()) {
console.log("could not load file for write")
}

0 comments on commit 1a154f2

Please sign in to comment.