Added static methods/getter/setter to LuaClasses

Former-commit-id: 8b2c0cf5812863c93cb1064b24b9bf396e7af30f
This commit is contained in:
Lynix 2014-05-28 00:31:34 +02:00
parent 15e62110cf
commit 8aaed03310
2 changed files with 156 additions and 15 deletions

View File

@ -24,6 +24,8 @@ class NzLuaClass
using ClassIndexFunc = bool (*)(NzLuaInstance& lua, T& instance);
using ConstructorFunc = T* (*)(NzLuaInstance& lua);
using FinalizerFunc = bool (*)(NzLuaInstance& lua, T& instance);
using StaticIndexFunc = bool (*)(NzLuaInstance& lua);
using StaticFunc = int (*)(NzLuaInstance& lua);
NzLuaClass(const NzString& name);
@ -31,11 +33,16 @@ class NzLuaClass
void Register(NzLuaInstance& lua);
void PushGlobalTable(NzLuaInstance& lua);
void SetConstructor(ConstructorFunc constructor);
void SetFinalizer(FinalizerFunc finalizer);
void SetGetter(ClassIndexFunc getter);
void SetMethod(const NzString& name, ClassFunc method);
void SetSetter(ClassIndexFunc setter);
void SetStaticGetter(StaticIndexFunc getter);
void SetStaticMethod(const NzString& name, StaticFunc func);
void SetStaticSetter(StaticIndexFunc getter);
private:
static int ConstructorProxy(lua_State* state);
@ -44,18 +51,26 @@ class NzLuaClass
static int GetterProxy(lua_State* state);
static int MethodProxy(lua_State* state);
static int SetterProxy(lua_State* state);
static int StaticGetterProxy(lua_State* state);
static int StaticMethodProxy(lua_State* state);
static int StaticSetterProxy(lua_State* state);
struct ClassInfo
{
std::vector<ClassFunc> methods;
std::vector<StaticFunc> staticMethods;
ClassIndexFunc getter = nullptr;
ClassIndexFunc setter = nullptr;
ConstructorFunc constructor = nullptr;
FinalizerFunc finalizer = nullptr;
StaticIndexFunc staticGetter = nullptr;
StaticIndexFunc staticSetter = nullptr;
NzString name;
int globalTableRef = -1;
};
std::map<NzString, ClassFunc> m_methods;
std::map<NzString, StaticFunc> m_staticMethods;
std::shared_ptr<ClassInfo> m_info;
};

View File

@ -3,6 +3,7 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Core/Error.hpp>
#include <iostream>
#include <Nazara/Lua/Debug.hpp>
template<class T>
@ -52,7 +53,8 @@ void NzLuaClass<T>::Register(NzLuaInstance& lua)
if (m_info->getter)
{
lua.PushValue(1);
lua.PushCFunction(GetterProxy, 1);
lua.PushValue(-2);
lua.PushCFunction(GetterProxy, 2);
}
else
// Optimisation, plutôt que de rediriger vers une fonction C qui ne fera rien d'autre que rechercher
@ -69,33 +71,84 @@ void NzLuaClass<T>::Register(NzLuaInstance& lua)
lua.SetField("__newindex"); // Setter
}
m_info->methods.resize(m_methods.size());
unsigned int index = 0;
m_info->methods.reserve(m_methods.size());
for (auto& pair : m_methods)
{
m_info->methods[index] = pair.second;
m_info->methods.push_back(pair.second);
lua.PushValue(1);
lua.PushInteger(index);
lua.PushInteger(m_info->methods.size() - 1);
lua.PushCFunction(MethodProxy, 2);
lua.SetField(pair.first); // Méthode
index++;
}
}
lua.Pop(); // On pop la metatable
if (m_info->constructor)
if (m_info->constructor || m_info->staticGetter || m_info->staticSetter || !m_info->staticMethods.empty())
{
lua.PushValue(1);
lua.PushCFunction(ConstructorProxy, 1);
lua.SetGlobal(m_info->name);
// Création de l'instance globale
lua.PushTable(); // Class = {}
// Création de la metatable associée à la table globale
lua.PushTable(); // ClassMeta = {}
if (m_info->constructor)
{
lua.PushValue(1); // ClassInfo
lua.PushCFunction(ConstructorProxy, 1);
lua.SetField("__call"); // ClassMeta.__call = ConstructorProxy
}
if (m_info->staticGetter)
{
lua.PushValue(1);
lua.PushValue(-2);
lua.PushCFunction(StaticGetterProxy, 2);
}
else
// Optimisation, plutôt que de rediriger vers une fonction C qui ne fera rien d'autre que rechercher
// dans la table, nous envoyons directement la table, de sorte que Lua fasse directement la recherche
// Ceci n'est possible que si nous n'avons ni getter, ni parent
lua.PushValue(-1);
lua.SetField("__index"); // ClassMeta.__index = StaticGetterProxy/ClassMeta
if (m_info->staticSetter)
{
lua.PushValue(1);
lua.PushCFunction(StaticSetterProxy, 1);
lua.SetField("__newindex"); // ClassMeta.__newindex = StaticSetterProxy
}
m_info->staticMethods.reserve(m_staticMethods.size());
for (auto& pair : m_staticMethods)
{
m_info->staticMethods.push_back(pair.second);
lua.PushValue(1);
lua.PushInteger(m_info->staticMethods.size() - 1);
lua.PushCFunction(StaticMethodProxy, 2);
lua.SetField(pair.first); // ClassMeta.method = StaticMethodProxy
}
lua.SetMetatable(-2); // setmetatable(Class, ClassMeta)
lua.PushValue(-1); // Copie
lua.SetGlobal(m_info->name); // Class
m_info->globalTableRef = lua.CreateReference();
}
lua.Pop(); // On pop l'Userdata (contenant nos informations)
}
template<class T>
void NzLuaClass<T>::PushGlobalTable(NzLuaInstance& lua)
{
lua.PushReference(m_info->globalTableRef);
}
template<class T>
void NzLuaClass<T>::SetConstructor(ConstructorFunc constructor)
{
@ -126,6 +179,24 @@ void NzLuaClass<T>::SetSetter(ClassIndexFunc setter)
m_info->setter = setter;
}
template<class T>
void NzLuaClass<T>::SetStaticGetter(StaticIndexFunc getter)
{
m_info->staticGetter = getter;
}
template<class T>
void NzLuaClass<T>::SetStaticMethod(const NzString& name, StaticFunc method)
{
m_staticMethods[name] = method;
}
template<class T>
void NzLuaClass<T>::SetStaticSetter(StaticIndexFunc setter)
{
m_info->staticSetter = setter;
}
template<class T>
int NzLuaClass<T>::ConstructorProxy(lua_State* state)
{
@ -134,6 +205,8 @@ int NzLuaClass<T>::ConstructorProxy(lua_State* state)
ClassInfo* info = *static_cast<ClassInfo**>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
ConstructorFunc constructor = info->constructor;
lua.Remove(1); // On enlève l'argument "table" du stack
T* instance = constructor(lua);
if (!instance)
{
@ -169,10 +242,11 @@ int NzLuaClass<T>::InfoDestructor(lua_State* state)
{
NzLuaInstance& lua = *NzLuaInstance::GetInstance(state);
std::shared_ptr<ClassInfo>* infoPtr = static_cast<std::shared_ptr<ClassInfo>*>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
std::shared_ptr<ClassInfo>& infoPtr = *static_cast<std::shared_ptr<ClassInfo>*>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
lua.DestroyReference(infoPtr->globalTableRef);
using namespace std; // Obligatoire pour le destructeur
infoPtr->~shared_ptr(); // Si vous voyez une autre façon de faire, je suis preneur
infoPtr.~shared_ptr(); // Si vous voyez une autre façon de faire, je suis preneur
return 0;
}
@ -190,7 +264,7 @@ int NzLuaClass<T>::GetterProxy(lua_State* state)
if (!getter(lua, instance))
{
// On accède alors à la table
lua.PushMetatable(info->name);
lua.PushValue(lua.GetIndexOfUpValue(2));
lua.PushValue(-2);
lua.GetTable();
}
@ -209,6 +283,8 @@ int NzLuaClass<T>::MethodProxy(lua_State* state)
T& instance = *(*static_cast<T**>(lua.CheckUserdata(1, info->name)));
lua.Remove(1); // On enlève l'argument "userdata" du stack
return method(lua, instance);
}
@ -233,4 +309,54 @@ int NzLuaClass<T>::SetterProxy(lua_State* state)
return 1;
}
template<class T>
int NzLuaClass<T>::StaticGetterProxy(lua_State* state)
{
NzLuaInstance& lua = *NzLuaInstance::GetInstance(state);
ClassInfo* info = *static_cast<ClassInfo**>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
StaticIndexFunc getter = info->staticGetter;
if (!getter(lua))
{
// On accède alors à la table
lua.PushValue(lua.GetIndexOfUpValue(2));
lua.PushValue(-2);
lua.GetTable();
}
return 1;
}
template<class T>
int NzLuaClass<T>::StaticMethodProxy(lua_State* state)
{
NzLuaInstance& lua = *NzLuaInstance::GetInstance(state);
ClassInfo* info = *static_cast<ClassInfo**>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
int index = lua.ToInteger(lua.GetIndexOfUpValue(2));
StaticFunc method = info->staticMethods[index];
return method(lua);
}
template<class T>
int NzLuaClass<T>::StaticSetterProxy(lua_State* state)
{
NzLuaInstance& lua = *NzLuaInstance::GetInstance(state);
ClassInfo* info = *static_cast<ClassInfo**>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
StaticIndexFunc setter = info->staticSetter;
if (!setter(lua))
{
std::size_t length;
const char* str = lua.ToString(2, &length);
lua.Error("Class \"" + info->name + "\" has no static field \"" + NzString(str, length) + ')');
}
return 1;
}
#include <Nazara/Lua/DebugOff.hpp>