Skip to content

Instantly share code, notes, and snippets.

@laurie71
Created May 20, 2011 01:18
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save laurie71/982157 to your computer and use it in GitHub Desktop.
Save laurie71/982157 to your computer and use it in GitHub Desktop.
test harness for proxying c++ classes in v8/node
#include <v8.h>
#include <node.h>
#include <node_object_wrap.h>
#include "Vector.h"
using namespace v8;
using namespace node;
extern "C" {
static void init (Handle<Object> target) {
Vector::Initialize(target);
}
NODE_MODULE(test, init);
}
#include "Vector.h"
Persistent<FunctionTemplate> Vector::ctor;
void
Vector::Initialize(Handle<Object> target) {
HandleScope scope;
ctor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(New));
ctor->InstanceTemplate()->SetInternalFieldCount(1);
ctor->SetClassName(String::NewSymbol("Vector"));
// ctor->PrototypeTemplate()->SetAccessor(String::NewSymbol("x"), GetX, SetX);
ctor->InstanceTemplate()->SetAccessor(String::NewSymbol("x"), GetX, SetX);
target->Set(String::NewSymbol("Vector"), ctor->GetFunction());
}
Handle<Value>
Vector::New(const Arguments &args) {
float x, y, z;
HandleScope scope;
if (args.Length() == 1 && args[0]->IsArray()) {
x = args[0]->ToObject()->Get(0)->NumberValue();
y = args[0]->ToObject()->Get(1)->NumberValue();
z = args[0]->ToObject()->Get(2)->NumberValue();
} else {
x = args[0]->IsNumber() ? args[0]->NumberValue() : 0;
y = args[1]->IsNumber() ? args[1]->NumberValue() : 0;
z = args[2]->IsNumber() ? args[2]->NumberValue() : 0;
}
Vector* obj = new Vector(x, y, z);
obj->Wrap(args.This());
return args.This();
}
Vector::Vector(btScalar &x, btScalar &y, btScalar &z) {
// m_btVector3 = new btVector3(x, y, z);
m_btVector3 = new VectorNative(x, y, z);
}
Handle<Value>
Vector::GetX(Local<String> property, const AccessorInfo& info) {
HandleScope scope;
// Vector* v = ObjectWrap::Unwrap<Vector>(info.This()); // This vs. Holder?
Vector* v = ObjectWrap::Unwrap<Vector>(info.Holder()); // This vs. Holder?
Local<Number> result = Number::New(v->m_btVector3->getX());
return scope.Close(result);
}
void
Vector::SetX(Local<String> property, Local<Value> value, const AccessorInfo& info) {
Vector* v = ObjectWrap::Unwrap<Vector>(info.Holder());
v->m_btVector3->setX(value->NumberValue());
}
#ifndef __NODE_VECTOR_H__
#define __NODE_VECTOR_H__
#include <node.h>
// #include "btBulletDynamicsCommon.h"
#include "VectorNative.h"
using namespace v8;
using namespace node;
class Vector: public node::ObjectWrap {
public:
static Persistent<FunctionTemplate> ctor;
static void Initialize(Handle<Object> target);
static Handle<Value> GetX(Local<String> property, const AccessorInfo& info);
static void SetX(Local<String> property, Local<Value> value, const AccessorInfo& info);
protected:
static Handle<Value> New(const Arguments &args);
Vector(btScalar &x, btScalar &y, btScalar &z);
private:
// btVector3* m_btVector3;
VectorNative* m_btVector3;
};
#endif
// Trivial mock of the class being wrapped/proxied
#define btScalar float
class VectorNative {
public:
VectorNative(btScalar _x, btScalar _y, btScalar _z) : x(_x), y(_y), z(_z) {}
btScalar getX() { return x; }
btScalar getY() { return y; }
btScalar getZ() { return z; }
btScalar setX(btScalar v) { x = v; }
btScalar setY(btScalar v) { y = v; }
btScalar setZ(btScalar v) { z = v; }
private:
btScalar x, y, z;
};
var Vector = require('./build/default/test.node').Vector;
console.log('Vector is '+Vector);
console.log('Vector.proto is '+Vector.prototype);
var v = new Vector(1,2,3);
console.log('v is',v);
console.log('v.x is ',v.x);
v.x = 9;
console.log('v is',v);
console.log('v.x is ',v.x);
// create sub-type
function f() {}; f.prototype = Vector.prototype;
function g() { Vector.apply(this, arguments) };
g.prototype = new f();
v = new g(1,2,3);
console.log('v is',v);
console.log('v.x is ',v.x);
srcdir = '.'
blddir = 'build'
VERSION = '0.0.1'
def set_options(opt):
opt.tool_options('compiler_cxx')
def configure(conf):
conf.check_tool('compiler_cxx')
conf.check_tool('node_addon')
def build(bld):
obj = bld.new_task_gen('cxx', 'shlib', 'node_addon')
obj.source = bld.glob('*.cc')
obj.target = 'test'
@laurie71
Copy link
Author

This code supports questions I'm asking on the Node and v8 mailing lists:

http://groups.google.com/group/nodejs/browse_thread/thread/1af07a2b193fc93
http://groups.google.com/group/v8-users/browse_thread/thread/3d473ed223a4139f

To try it locally (assuming you have Node installed):

$ git clone git://gist.github.com/######.git
$ cd 982157
$ node-waf configure build
$ node VectorTests.js

where ###### is the appropriate gist version (982157 currently).

@laurie71
Copy link
Author

UPDATE: this looked promising but doesn't fix anything really; it gets rid of one assertion crash, but has no useful effect...


A possible work-around for fixing inheritance: essentially, a c++ emulation of this pattern:

function f(args...) { if (! (this instanceof f)) return new f(args...) }

I suspect there must be a better way though... here's the code (insert at beginning of Vector::New):

if (! args.IsConstructCall()) {
    const int argc = args.Length();
    Handle<Function> rctor(Function::Cast(*args.Callee()));
    // return rctor->NewInstance(argc, args);
    std::vector<Handle<Value> > av(static_cast<size_t>(argc), Undefined());
    for (int i = 0; i < argc; i++) av[i] = args[i];
    return rctor->NewInstance(argc, &av[0]);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment