Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Copyright 2015 Sammy James
- #pragma once
- #include <lua.hpp>
- #include <utility>
- #include <functional>
- #include <list>
- template< class T >
- class TLuaClass
- {
- public:
- struct PropertyType
- {
- const char* Name;
- int32 ( T::*Getter )( lua_State* );
- int32 ( T::*Setter )( lua_State* );
- };
- struct FunctionType
- {
- const char* Name;
- int32 Call( lua_State* L, void* Object ) const
- {
- return InternalCall( L, Object );
- }
- FunctionType( const char* InName )
- : Name( InName )
- {
- }
- private:
- virtual int32 InternalCall( lua_State* L, void* Object ) const { return 0; }
- };
- template< typename >
- struct TFunctionType : public FunctionType
- {
- };
- template< typename Result, typename C, typename... Args >
- struct TFunctionType< Result( C::* )( Args... ) > : public FunctionType
- {
- typedef Result( C::*Type )( Args... );
- TFunctionType( const char* Name, Type Method )
- : FunctionType( Name )
- , m_Method( Method )
- {
- }
- private:
- Type m_Method;
- virtual int32 InternalCall( lua_State* L, void* Object ) const override
- {
- TLuaFunction< Type >::ArgType Arguments = TLuaFunction< Type >::Call( L );
- Result RetVal = Apply( Object, Arguments, std::make_index_sequence< std::tuple_size< TLuaFunction< Type >::ArgType >::value >{} );
- TLuaPush< Result >::Push( L, RetVal );
- return 1;
- }
- template< typename Tup, size_t... Index >
- Result Apply( void* Object, Tup&& Tuple, std::index_sequence< Index... > ) const
- {
- C* ClassObject = static_cast<C*>( Object );
- return ( ClassObject->*(m_Method) )( std::get< Index >( Tuple )... );
- }
- };
- template< typename C, typename... Args >
- struct TFunctionType< void( C::* )( Args... ) > : public FunctionType
- {
- typedef void( C::*Type )( Args... );
- TFunctionType( const char* Name, Type Method )
- : FunctionType( Name )
- , m_Method( Method )
- {
- }
- private:
- Type m_Method;
- virtual int32 InternalCall( lua_State* L, void* Object ) const override
- {
- TLuaFunction< Type >::ArgType Arguments = TLuaFunction< Type >::Call( L );
- Apply( Object, Arguments, std::make_index_sequence< std::tuple_size< TLuaFunction< Type >::ArgType >::value >{} );
- return 0;
- }
- template< typename Tup, size_t... Index >
- void Apply( void* Object, Tup&& Tuple, std::index_sequence< Index... > ) const
- {
- C* ClassObject = static_cast<C*>( Object );
- ( ClassObject->*( m_Method ) )( std::get< Index >( Tuple )... );
- }
- };
- template< typename Result, typename C >
- struct TFunctionType< Result( C::* )( void ) > : public FunctionType
- {
- typedef Result( C::*Type )( void );
- TFunctionType( const char* Name, Type Method )
- : FunctionType( Name )
- , m_Method( Method )
- {
- }
- private:
- Type m_Method;
- virtual int32 InternalCall( lua_State* L, void* Object ) const override
- {
- if ( !TEqualType< Result, void >::Value )
- {
- Result RetVal = Apply( Object );
- TLuaPush< Result >::Push( L, RetVal );
- return 1;
- }
- else
- {
- Apply( Object );
- return 0;
- }
- }
- Result Apply( void* Object ) const
- {
- C* ClassObject = static_cast<C*>( Object );
- return ( ClassObject->*( m_Method ) )();
- }
- };
- template< typename C >
- struct TFunctionType< void( C::* )( void ) > : public FunctionType
- {
- typedef void( C::*Type )( void );
- TFunctionType( const char* Name, Type Method )
- : FunctionType( Name )
- , m_Method( Method )
- {}
- private:
- Type m_Method;
- virtual int32 InternalCall( lua_State* L, void* Object ) const override
- {
- Apply( Object );
- return 0;
- }
- void Apply( void* Object ) const
- {
- C* ClassObject = static_cast<C*>( Object );
- ( ClassObject->*( m_Method ) )( );
- }
- };
- template< typename Result, typename C, typename... Args >
- struct TFunctionType< Result( C::* )( Args... ) const > : public FunctionType
- {
- typedef Result( C::*Type )( Args... ) const;
- TFunctionType( const char* Name, Type Method )
- : FunctionType( Name )
- , m_Method( Method )
- {
- }
- private:
- Type m_Method;
- virtual void InternalCall( lua_State* L, void* Object ) const override
- {
- TLuaFunction< Type >::ArgType Arguments = TLuaFunction< Type >::Call( L );
- if ( !TEqualType< Result, void >::Value )
- {
- Result RetVal = Apply( Object, Arguments, std::make_index_sequence< std::tuple_size< TLuaFunction< Type >::ArgType >::value >{} );
- TLuaPush< Result >::Push( L, RetVal );
- return 1;
- }
- else
- {
- Apply( Object, Arguments, std::make_index_sequence< std::tuple_size< TLuaFunction< Type >::ArgType >::value >{} );
- return 0;
- }
- return 0;
- }
- template< typename Tup, size_t... Index >
- Result Apply( void* Object, Tup&& Tuple, std::index_sequence< Index... > ) const
- {
- C* ClassObject = static_cast<C*>( Object );
- return ( ClassObject->*( m_Method ) )( std::get< Index >( Tuple )... );
- }
- };
- template< typename C, typename... Args >
- struct TFunctionType< void( C::* )( Args... ) const > : public FunctionType
- {
- typedef void( C::*Type )( Args... ) const;
- TFunctionType( const char* Name, Type Method )
- : FunctionType( Name )
- , m_Method( Method )
- {}
- private:
- Type m_Method;
- virtual int32 InternalCall( lua_State* L, void* Object ) const override
- {
- TLuaFunction< Type >::ArgType Arguments = TLuaFunction< Type >::Call( L );
- Apply( Object, Arguments, std::make_index_sequence< std::tuple_size< TLuaFunction< Type >::ArgType >::value >{} );
- return 0;
- }
- template< typename Tup, size_t... Index >
- void Apply( void* Object, Tup&& Tuple, std::index_sequence< Index... > ) const
- {
- C* ClassObject = static_cast<C*>( Object );
- ( ClassObject->*( m_Method ) )( std::get< Index >( Tuple )... );
- }
- };
- template< typename Result, typename C >
- struct TFunctionType< Result( C::* )( void ) const > : public FunctionType
- {
- typedef Result( C::*Type )( void ) const;
- TFunctionType( const char* Name, Type Method )
- : FunctionType( Name )
- , m_Method( Method )
- {}
- private:
- Type m_Method;
- virtual int32 InternalCall( lua_State* L, void* Object ) const override
- {
- if ( !TEqualType< Result, void >::Value )
- {
- Result RetVal = Apply( Object );
- TLuaPush< Result >::Push( L, RetVal );
- return 1;
- }
- else
- {
- Apply( Object );
- return 0;
- }
- }
- Result Apply( void* Object ) const
- {
- C* ClassObject = static_cast<C*>( Object );
- return ( ClassObject->*( m_Method ) )( );
- }
- };
- template< typename C >
- struct TFunctionType< void( C::* )( void ) const > : public FunctionType
- {
- typedef void( C::*Type )( void ) const;
- TFunctionType( const char* Name, Type Method )
- : FunctionType( Name )
- , m_Method( Method )
- {}
- private:
- Type m_Method;
- virtual int32 InternalCall( lua_State* L, void* Object ) const override
- {
- Apply( Object );
- return 0;
- }
- void Apply( void* Object ) const
- {
- C* ClassObject = static_cast<C*>( Object );
- ( ClassObject->*( m_Method ) )( );
- }
- };
- static void Register( lua_State* L, const char* Namespace = nullptr )
- {
- if ( Namespace && strlen( Namespace ) )
- {
- lua_getglobal( L, Namespace );
- if ( lua_isnil( L, -1 ) )
- {
- lua_newtable( L );
- lua_pushvalue( L, -1 );
- lua_setglobal( L, Namespace );
- }
- lua_pushcfunction( L, &TLuaClass< T >::New );
- lua_setfield( L, -2, T::GetClassName() );
- lua_pop( L, 1 );
- }
- else
- {
- lua_pushcfunction( L, &TLuaClass< T >::New );
- lua_setglobal( L, T::GetClassName() );
- }
- luaL_newmetatable( L, T::GetClassName() );
- const int32 Metatable = lua_gettop( L );
- lua_pushstring( L, "__gc" );
- lua_pushcfunction( L, &TLuaClass< T >::Collect );
- lua_settable( L, Metatable );
- lua_pushstring( L, "__tostring" );
- lua_pushcfunction( L, &TLuaClass< T >::ToString );
- lua_settable( L, Metatable );
- lua_pushstring( L, "__eq" );
- lua_pushcfunction( L, &TLuaClass< T >::Equals );
- lua_settable( L, Metatable );
- lua_pushstring( L, "__index" );
- lua_pushcfunction( L, &TLuaClass< T >::Get );
- lua_settable( L, Metatable );
- lua_pushstring( L, "__newindex" );
- lua_pushcfunction( L, &TLuaClass< T >::Set );
- lua_settable( L, Metatable );
- const PropertyType* Properties = T::GetProperties();
- for ( int32 i = 0; Properties[ i ].Name; ++i )
- {
- lua_pushstring( L, Properties[ i ].Name );
- lua_pushinteger( L, i );
- lua_settable( L, Metatable );
- }
- const FunctionType** Functions = T::GetFunctions();
- for ( int32 i = 0; Functions[ i ]->Name; ++i )
- {
- lua_pushstring( L, Functions[ i ]->Name );
- lua_pushinteger( L, i | ( 1 << 8 ) );
- lua_settable( L, Metatable );
- }
- }
- static int32 New( lua_State* L )
- {
- T* Result = new T();
- T** Light = static_cast<T**>( lua_newuserdata( L, sizeof( T* ) ) );
- *Light = Result;
- luaL_getmetatable( L, T::GetClassName() );
- lua_setmetatable( L, -2 );
- return 1;
- }
- static int32 Get( lua_State* L )
- {
- lua_getmetatable( L, 1 );
- lua_pushvalue( L, 2 );
- lua_rawget( L, -2 );
- if ( lua_isinteger( L, -1 ) )
- {
- const int32 Index = (int32)lua_tointeger( L, -1 );
- T** Object = static_cast<T**>( lua_touserdata( L, 1 ) );
- lua_pushvalue( L, 3 );
- if ( Index & ( 1 << 8 ) ) // function
- {
- lua_pushinteger( L, Index ^ ( 1 << 8 ) );
- lua_pushlightuserdata( L, Object );
- lua_pushcclosure( L, &TLuaClass< T >::Apply, 2 );
- return 1;
- }
- lua_pop( L, 2 );
- lua_remove( L, 1 );
- lua_remove( L, 1 );
- return ( ( *Object )->*( T::GetProperties()[ Index ].Getter ) )( L );
- }
- return 1;
- }
- static int32 Set( lua_State* L )
- {
- lua_getmetatable( L, 1 );
- lua_pushvalue( L, 2 );
- lua_rawget( L, -2 );
- if ( lua_isinteger( L, -1 ) )
- {
- const int32 Index = (int32)lua_tointeger( L, -1 );
- T** Object = static_cast<T**>( lua_touserdata( L, 1 ) );
- if ( !Object || !*Object )
- {
- luaL_error( L, "Error: No object provided to setter." );
- return 0;
- }
- if ( Index >> 8 ) // function
- {
- char buffer[ 128 ];
- sprintf_s( buffer, "Error: Trying to set the method [%s] of class [%s].", ( *Object )->T::GetFunctions()[ Index ^ ( 1 << 8 ) ]->Name, T::GetClassName() );
- luaL_error( L, buffer );
- return 0;
- }
- lua_pop( L, 2 );
- lua_remove( L, 1 );
- lua_remove( L, 1 );
- return ( ( *Object )->*( T::GetProperties()[ Index ].Setter ) )( L );
- }
- return 0;
- }
- static int32 Apply( lua_State* L )
- {
- const int32 Index = (int32)lua_tointeger( L, lua_upvalueindex( 1 ) );
- T** Object = static_cast<T**>( lua_touserdata( L, lua_upvalueindex( 2 ) ) );
- const TLuaClass< T >::FunctionType** Functions = T::GetFunctions();
- const TLuaClass< T >::FunctionType* Func = Functions[ Index ];
- return Func->Call( L, *Object );
- }
- static int32 Collect( lua_State* L )
- {
- T** Object = static_cast<T**>( lua_touserdata( L, -1 ) );
- if ( Object && *Object )
- {
- delete *Object;
- }
- return 0;
- }
- static int32 ToString( lua_State* L )
- {
- T** Object = static_cast<T**>( lua_touserdata( L, -1 ) );
- if ( Object )
- {
- lua_pushfstring( L, "%s (%p)", T::GetClassName(), (void*)*Object );
- }
- else
- {
- lua_pushstring( L, "Empty" );
- }
- return 1;
- }
- static int32 Equals( lua_State* L )
- {
- T** Left = static_cast<T**>( lua_touserdata( L, -1 ) );
- T** Right = static_cast<T**>( lua_touserdata( L, 1 ) );
- lua_pushboolean( L, *Left == *Right );
- return 1;
- }
- };
- template< typename T >
- struct TLuaFunction
- {
- public:
- typedef typename TFunctionArgs< T >::Type ArgType;
- typedef typename TFunctionResult< T >::Type ResultType;
- static ArgType Call( lua_State* L )
- {
- return Helper( L, std::make_index_sequence< std::tuple_size< ArgType >::value >{} );
- }
- private:
- template< typename U >
- static std::tuple< U > Work( int32& Index, lua_State* L )
- {
- return std::make_tuple( TLuaRead< U >::Read( L, Index++ ) );
- }
- template< typename U1, typename U2, typename... US >
- static std::tuple< U1, U2, US... > Work( int32& Index, lua_State* L )
- {
- std::tuple< U1 > Start = Work< U1 >( Index, L );
- return std::tuple_cat( Start, Work< U2, US... >( Index, L ) );
- }
- template< size_t... Index >
- static ArgType Helper( lua_State* L, std::index_sequence< Index... > )
- {
- int32 IndexHelper = 1;
- return Work< std::tuple_element_t< Index, ArgType >... >( IndexHelper, L );
- }
- };
- #define DECLARE_LUA_CLASS( ClassType ) \
- private: \
- using TProperty = TLuaClass< class ClassType >::PropertyType; \
- using TFunction = TLuaClass< class ClassType >::FunctionType; \
- static const TProperty Properties[]; \
- static const TFunction* Functions[]; \
- public: \
- static const char* GetClassName() { return #ClassType; } \
- static const TProperty* GetProperties() { return Properties; } \
- static const TFunction** GetFunctions() { return Functions; } \
- private:
- #define INITIALIZE_LUA_PROPERTIES( ClassType ) const ClassType::TProperty ClassType::Properties[] = { { nullptr } };
- #define INITIALIZE_LUA_FUNCTIONS( ClassType ) const ClassType::TFunction* ClassType::Functions[] = {
- #define FINALIZE_LUA_FUNCTIONS( ClassType ) new ClassType::TFunction{ nullptr } };
- #define DECLARE_LUA_FUNCTION( ClassType, Function ) new TLuaClass< ClassType >::TFunctionType< decltype( &ClassType::Function ) >{ #Function, &ClassType::Function }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement