Added static methods/getter/setter to LuaClasses
Former-commit-id: 8b2c0cf5812863c93cb1064b24b9bf396e7af30f
This commit is contained in:
parent
15e62110cf
commit
8aaed03310
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue