Created
September 14, 2016 19:58
-
-
Save terryjsmith/c1f4a039459662010217c5455d6e107e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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