| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 | /* * LuaWrapper.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */#pragma once#include "LuaCallWrapper.h"/* * Original code is LunaWrapper by nornagon. * https://lua-users.org/wiki/LunaWrapper * Published under the BSD 2-clause license * https://opensource.org/licenses/BSD-2-Clause * */VCMI_LIB_NAMESPACE_BEGINnamespace scripting{namespace detail{	struct CustomRegType	{		const char * name;		lua_CFunction functor;		bool isStatic;	};	template <typename P, typename U>	struct Dispatcher	{		using ProxyType = P;		using UDataType = U;		static void setIndexTable(lua_State * L)		{			lua_pushstring(L, "__index");			lua_newtable(L);			for(auto & reg : ProxyType::REGISTER_CUSTOM)			{				if(!reg.isStatic)				{					lua_pushstring(L, reg.name);					lua_pushcclosure(L, reg.functor, 0);					lua_rawset(L, -3);				}			}			lua_rawset(L, -3);		}		static void pushStaticTable(lua_State * L)		{			lua_newtable(L);			lua_newtable(L);			lua_pushstring(L, "__index");			{				lua_newtable(L);				for(auto & reg : ProxyType::REGISTER_CUSTOM)				{					if(reg.isStatic)					{						lua_pushstring(L, reg.name);						lua_pushcclosure(L, reg.functor, 0);						lua_rawset(L, -3);					}				}			}			lua_rawset(L, -3);			lua_pushstring(L, "__newindex");			lua_pushnil(L);			lua_rawset(L, -3);			lua_setmetatable(L, -2);		}		static int destructor(lua_State * L)		{			static auto KEY = api::TypeRegistry::get()->getKey<UDataType>();			void * objPtr = luaL_checkudata(L, 1, KEY);			if(objPtr)			{				auto obj = static_cast<UDataType *>(objPtr);				obj->reset();			}			lua_settop(L, 0);			return 0;		}	};}class RegistarBase : public api::Registar{public:protected:	virtual void adjustMetatable(lua_State * L) const	{	}	virtual void adjustStaticTable(lua_State * L) const	{	}};template<class T, class Proxy = T>class OpaqueWrapper : public RegistarBase{public:	using ObjectType = typename std::remove_cv<T>::type;	using UDataType = ObjectType *;	using CUDataType = const ObjectType *;	using CustomRegType = detail::CustomRegType;	void pushMetatable(lua_State * L) const override final	{		static auto KEY = api::TypeRegistry::get()->getKey<UDataType>();		static auto S_KEY = api::TypeRegistry::get()->getKey<CUDataType>();		LuaStack S(L);		if(luaL_newmetatable(L, KEY) != 0)			adjustMetatable(L);		S.balance();		if(luaL_newmetatable(L, S_KEY) != 0)			adjustMetatable(L);		S.balance();		detail::Dispatcher<Proxy, UDataType>::pushStaticTable(L);		adjustStaticTable(L);	}protected:	void adjustMetatable(lua_State * L) const override	{		detail::Dispatcher<Proxy, UDataType>::setIndexTable(L);	}};template<class T, class Proxy = T>class SharedWrapper : public RegistarBase{public:	using ObjectType = typename std::remove_cv<T>::type;	using UDataType = std::shared_ptr<T>;	using CustomRegType = detail::CustomRegType;	static int constructor(lua_State * L)	{		LuaStack S(L);		S.clear();//we do not accept any parameters in constructor		auto obj = std::make_shared<T>();		S.push(obj);		return 1;	}	void pushMetatable(lua_State * L) const override final	{		static auto KEY = api::TypeRegistry::get()->getKey<UDataType>();		LuaStack S(L);		if(luaL_newmetatable(L, KEY) != 0)		{			adjustMetatable(L);			S.push("__gc");			lua_pushcfunction(L, &(detail::Dispatcher<Proxy, UDataType>::destructor));			lua_rawset(L, -3);		}		S.balance();		detail::Dispatcher<Proxy, UDataType>::pushStaticTable(L);		adjustStaticTable(L);	}protected:	void adjustMetatable(lua_State * L) const override	{		detail::Dispatcher<Proxy, UDataType>::setIndexTable(L);	}};template<class T, class Proxy = T>class UniqueOpaqueWrapper : public api::Registar{public:	using ObjectType = typename std::remove_cv<T>::type;	using UDataType = std::unique_ptr<T>;	using CustomRegType = detail::CustomRegType;	void pushMetatable(lua_State * L) const override final	{		static auto KEY = api::TypeRegistry::get()->getKey<UDataType>();		LuaStack S(L);		if(luaL_newmetatable(L, KEY) != 0)		{//			detail::Dispatcher<Proxy, UDataType>::setIndexTable(L);			S.push("__gc");			lua_pushcfunction(L, &(detail::Dispatcher<Proxy, UDataType>::destructor));			lua_rawset(L, -3);		}		S.balance();		detail::Dispatcher<Proxy, UDataType>::pushStaticTable(L);	}};}VCMI_LIB_NAMESPACE_END
 |