Skip to content

Instantly share code, notes, and snippets.

@terryjsmith
Created September 14, 2016 19:58
Show Gist options
  • Save terryjsmith/c1f4a039459662010217c5455d6e107e to your computer and use it in GitHub Desktop.
Save terryjsmith/c1f4a039459662010217c5455d6e107e to your computer and use it in GitHub Desktop.
//
// scripttype.hpp
// eternity
//
// Created by Terry Smith on 2016-09-13.
// Copyright © 2016 Terry Smith. All rights reserved.
//
#ifndef scripttype_hpp
#define scripttype_hpp
/**
* Getter and setter functions for our classes to V8
*/
typedef v8::Local<v8::Value> (*ScriptTypeGetterFunc)(v8::Isolate*,void*);
typedef void (*ScriptTypeSetterFunc)(void*,v8::Local<v8::Value>);
/**
* A storage for getter and setter to variable pairs
*/
class ScriptTypeCallbackPair {
public:
ScriptTypeCallbackPair() : variableName(0), getter(0), setter(0), next(0) { }
~ScriptTypeCallbackPair() { }
public:
char* variableName;
ScriptTypeGetterFunc getter;
ScriptTypeSetterFunc setter;
ScriptTypeCallbackPair* next;
};
/**
* A scripted global object that can be accessed and created in JS
*/
template<class T>
class ScriptType : public ScriptObject {
public:
ScriptType() { }
~ScriptType() { }
static void StartTemplate(v8::Isolate* isolate) {
// Start template
v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(isolate, New);
m_functionTemplate.Reset(isolate, tpl);
m_isolate = isolate;
}
static void SetTypeName(char* name) {
m_typeName = (char*)malloc(strlen(name) + 1);
strcpy(m_typeName, name);
v8::Local<v8::FunctionTemplate> tpl = m_functionTemplate.Get(m_isolate);
tpl->SetClassName(v8::String::NewFromUtf8(m_isolate, m_typeName));
}
static void AddVariable(char* name, ScriptTypeGetterFunc getter, ScriptTypeSetterFunc setter) {
// Create a new variable function callback
ScriptTypeCallbackPair* pair = new ScriptTypeCallbackPair();
// Copy params
pair->variableName = (char*)malloc(strlen(name) + 1);
strcpy(pair->variableName, name);
pair->getter = getter;
pair->setter = setter;
// Set this up as an accessible variable name
v8::Local<v8::FunctionTemplate> tpl = m_functionTemplate.Get(m_isolate);
tpl->InstanceTemplate()->SetAccessor(v8::String::NewFromUtf8(m_isolate, name), Getter, Setter);
if(m_varList == 0) {
m_varList = pair;
return;
}
ScriptTypeCallbackPair* current = m_varList;
while(current->next) {
current = current->next;
}
current->next = pair;
}
static void EndTemplate(v8::Local<v8::Context> context) {
// Set our internal field count to 1 to we can house our "this" object for reference later
v8::Local<v8::FunctionTemplate> tpl = m_functionTemplate.Get(m_isolate);
tpl->InstanceTemplate()->SetInternalFieldCount(1);
// Get our constructor for this type
m_constructor.Reset(m_isolate, tpl->GetFunction());
v8::Local<v8::Function> constructor = m_constructor.Get(m_isolate);
// Inject this type name into V8
context->Global()->Set(v8::String::NewFromUtf8(m_isolate, m_typeName), constructor);
}
static void AddFunction(char* name, v8::FunctionCallback func) {
v8::Local<v8::FunctionTemplate> tpl = m_functionTemplate.Get(m_isolate);
tpl->PrototypeTemplate()->Set(v8::String::NewFromUtf8(m_isolate, name),
v8::FunctionTemplate::New(m_isolate, func));
}
static void New(const v8::FunctionCallbackInfo<v8::Value>& info) {
v8::HandleScope scope(info.GetIsolate());
T* obj = new T(info);
obj->Wrap(info.This());
return info.GetReturnValue().Set(info.This());
}
static v8::Local<v8::Object> NewInstance() {
v8::HandleScope scope(m_isolate);
v8::Local<v8::Function> constructor = m_constructor.Get(m_isolate);
v8::Local<v8::Object> instance = constructor->NewInstance();
return instance;
}
static void Getter(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
// Unwrap our object
const T* obj = ScriptObject::Unwrap<T>(info.This());
// Iterate through the callback list, looking for a registered callback function
ScriptTypeCallbackPair* current = m_varList;
while(current) {
v8::String::Utf8Value propName(property);
if(strcmp(current->variableName, *propName) == 0) {
if(current->getter != 0) {
v8::Local<v8::Value> val = current->getter(m_isolate, (void*)obj);
info.GetReturnValue().Set(val);
return;
}
}
}
}
static void Setter(v8::Local<v8::String> property, v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<void>& info) {
T* obj = ScriptObject::Unwrap<T>(info.This());
// Iterate through the callback list, looking for a registered callback function
ScriptTypeCallbackPair* current = m_varList;
while(current) {
v8::String::Utf8Value propName(property);
if(strcmp(current->variableName, *propName) == 0) {
if(current->setter != 0) {
current->setter((void*)obj, value);
return;
}
}
}
}
protected:
// Our constructor to create new objects of this type
static v8::Persistent<v8::Function> m_constructor;
// The function template
static v8::Persistent<v8::FunctionTemplate> m_functionTemplate;
// The name of this type inside the JS context
static char* m_typeName;
// The current isolate
static v8::Isolate* m_isolate;
// Linked list of getter/setter combinations for vars
static ScriptTypeCallbackPair* m_varList;
};
template<class T> v8::Persistent<v8::Function> ScriptType<T>::m_constructor;
template<class T> v8::Persistent<v8::FunctionTemplate> ScriptType<T>::m_functionTemplate;
template<class T> char* ScriptType<T>::m_typeName = 0;
template<class T> v8::Isolate* ScriptType<T>::m_isolate = 0;
template<class T> ScriptTypeCallbackPair* ScriptType<T>::m_varList = 0;
#endif /* scripttype_hpp */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment