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 ClassIndexFunc = bool (*)(NzLuaInstance& lua, T& instance);
|
||||||
using ConstructorFunc = T* (*)(NzLuaInstance& lua);
|
using ConstructorFunc = T* (*)(NzLuaInstance& lua);
|
||||||
using FinalizerFunc = bool (*)(NzLuaInstance& lua, T& instance);
|
using FinalizerFunc = bool (*)(NzLuaInstance& lua, T& instance);
|
||||||
|
using StaticIndexFunc = bool (*)(NzLuaInstance& lua);
|
||||||
|
using StaticFunc = int (*)(NzLuaInstance& lua);
|
||||||
|
|
||||||
NzLuaClass(const NzString& name);
|
NzLuaClass(const NzString& name);
|
||||||
|
|
||||||
|
|
@ -31,11 +33,16 @@ class NzLuaClass
|
||||||
|
|
||||||
void Register(NzLuaInstance& lua);
|
void Register(NzLuaInstance& lua);
|
||||||
|
|
||||||
|
void PushGlobalTable(NzLuaInstance& lua);
|
||||||
|
|
||||||
void SetConstructor(ConstructorFunc constructor);
|
void SetConstructor(ConstructorFunc constructor);
|
||||||
void SetFinalizer(FinalizerFunc finalizer);
|
void SetFinalizer(FinalizerFunc finalizer);
|
||||||
void SetGetter(ClassIndexFunc getter);
|
void SetGetter(ClassIndexFunc getter);
|
||||||
void SetMethod(const NzString& name, ClassFunc method);
|
void SetMethod(const NzString& name, ClassFunc method);
|
||||||
void SetSetter(ClassIndexFunc setter);
|
void SetSetter(ClassIndexFunc setter);
|
||||||
|
void SetStaticGetter(StaticIndexFunc getter);
|
||||||
|
void SetStaticMethod(const NzString& name, StaticFunc func);
|
||||||
|
void SetStaticSetter(StaticIndexFunc getter);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static int ConstructorProxy(lua_State* state);
|
static int ConstructorProxy(lua_State* state);
|
||||||
|
|
@ -44,18 +51,26 @@ class NzLuaClass
|
||||||
static int GetterProxy(lua_State* state);
|
static int GetterProxy(lua_State* state);
|
||||||
static int MethodProxy(lua_State* state);
|
static int MethodProxy(lua_State* state);
|
||||||
static int SetterProxy(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
|
struct ClassInfo
|
||||||
{
|
{
|
||||||
std::vector<ClassFunc> methods;
|
std::vector<ClassFunc> methods;
|
||||||
|
std::vector<StaticFunc> staticMethods;
|
||||||
ClassIndexFunc getter = nullptr;
|
ClassIndexFunc getter = nullptr;
|
||||||
ClassIndexFunc setter = nullptr;
|
ClassIndexFunc setter = nullptr;
|
||||||
ConstructorFunc constructor = nullptr;
|
ConstructorFunc constructor = nullptr;
|
||||||
FinalizerFunc finalizer = nullptr;
|
FinalizerFunc finalizer = nullptr;
|
||||||
|
StaticIndexFunc staticGetter = nullptr;
|
||||||
|
StaticIndexFunc staticSetter = nullptr;
|
||||||
NzString name;
|
NzString name;
|
||||||
|
int globalTableRef = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::map<NzString, ClassFunc> m_methods;
|
std::map<NzString, ClassFunc> m_methods;
|
||||||
|
std::map<NzString, StaticFunc> m_staticMethods;
|
||||||
std::shared_ptr<ClassInfo> m_info;
|
std::shared_ptr<ClassInfo> m_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
#include <Nazara/Core/Error.hpp>
|
#include <Nazara/Core/Error.hpp>
|
||||||
|
#include <iostream>
|
||||||
#include <Nazara/Lua/Debug.hpp>
|
#include <Nazara/Lua/Debug.hpp>
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
|
|
@ -52,7 +53,8 @@ void NzLuaClass<T>::Register(NzLuaInstance& lua)
|
||||||
if (m_info->getter)
|
if (m_info->getter)
|
||||||
{
|
{
|
||||||
lua.PushValue(1);
|
lua.PushValue(1);
|
||||||
lua.PushCFunction(GetterProxy, 1);
|
lua.PushValue(-2);
|
||||||
|
lua.PushCFunction(GetterProxy, 2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
// Optimisation, plutôt que de rediriger vers une fonction C qui ne fera rien d'autre que rechercher
|
// 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
|
lua.SetField("__newindex"); // Setter
|
||||||
}
|
}
|
||||||
|
|
||||||
m_info->methods.resize(m_methods.size());
|
m_info->methods.reserve(m_methods.size());
|
||||||
|
|
||||||
unsigned int index = 0;
|
|
||||||
for (auto& pair : m_methods)
|
for (auto& pair : m_methods)
|
||||||
{
|
{
|
||||||
m_info->methods[index] = pair.second;
|
m_info->methods.push_back(pair.second);
|
||||||
|
|
||||||
lua.PushValue(1);
|
lua.PushValue(1);
|
||||||
lua.PushInteger(index);
|
lua.PushInteger(m_info->methods.size() - 1);
|
||||||
|
|
||||||
lua.PushCFunction(MethodProxy, 2);
|
lua.PushCFunction(MethodProxy, 2);
|
||||||
lua.SetField(pair.first); // Méthode
|
lua.SetField(pair.first); // Méthode
|
||||||
|
|
||||||
index++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lua.Pop(); // On pop la metatable
|
lua.Pop(); // On pop la metatable
|
||||||
|
|
||||||
|
if (m_info->constructor || m_info->staticGetter || m_info->staticSetter || !m_info->staticMethods.empty())
|
||||||
|
{
|
||||||
|
// 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)
|
if (m_info->constructor)
|
||||||
{
|
{
|
||||||
lua.PushValue(1);
|
lua.PushValue(1); // ClassInfo
|
||||||
lua.PushCFunction(ConstructorProxy, 1);
|
lua.PushCFunction(ConstructorProxy, 1);
|
||||||
lua.SetGlobal(m_info->name);
|
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)
|
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>
|
template<class T>
|
||||||
void NzLuaClass<T>::SetConstructor(ConstructorFunc constructor)
|
void NzLuaClass<T>::SetConstructor(ConstructorFunc constructor)
|
||||||
{
|
{
|
||||||
|
|
@ -126,6 +179,24 @@ void NzLuaClass<T>::SetSetter(ClassIndexFunc setter)
|
||||||
m_info->setter = 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>
|
template<class T>
|
||||||
int NzLuaClass<T>::ConstructorProxy(lua_State* state)
|
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)));
|
ClassInfo* info = *static_cast<ClassInfo**>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
|
||||||
ConstructorFunc constructor = info->constructor;
|
ConstructorFunc constructor = info->constructor;
|
||||||
|
|
||||||
|
lua.Remove(1); // On enlève l'argument "table" du stack
|
||||||
|
|
||||||
T* instance = constructor(lua);
|
T* instance = constructor(lua);
|
||||||
if (!instance)
|
if (!instance)
|
||||||
{
|
{
|
||||||
|
|
@ -169,10 +242,11 @@ int NzLuaClass<T>::InfoDestructor(lua_State* state)
|
||||||
{
|
{
|
||||||
NzLuaInstance& lua = *NzLuaInstance::GetInstance(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
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -190,7 +264,7 @@ int NzLuaClass<T>::GetterProxy(lua_State* state)
|
||||||
if (!getter(lua, instance))
|
if (!getter(lua, instance))
|
||||||
{
|
{
|
||||||
// On accède alors à la table
|
// On accède alors à la table
|
||||||
lua.PushMetatable(info->name);
|
lua.PushValue(lua.GetIndexOfUpValue(2));
|
||||||
lua.PushValue(-2);
|
lua.PushValue(-2);
|
||||||
lua.GetTable();
|
lua.GetTable();
|
||||||
}
|
}
|
||||||
|
|
@ -209,6 +283,8 @@ int NzLuaClass<T>::MethodProxy(lua_State* state)
|
||||||
|
|
||||||
T& instance = *(*static_cast<T**>(lua.CheckUserdata(1, info->name)));
|
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);
|
return method(lua, instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,4 +309,54 @@ int NzLuaClass<T>::SetterProxy(lua_State* state)
|
||||||
return 1;
|
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>
|
#include <Nazara/Lua/DebugOff.hpp>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue