Compare commits
	
		
			8 Commits
		
	
	
		
			v10.5.3
			...
			feature/lu
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 22fc8e981d | ||
|  | fb0de53efd | ||
|  | 62a7483e41 | ||
|  | 36fbdd0daa | ||
|  | feff2e38c0 | ||
|  | a040ff06e8 | ||
|  | 755493eaf3 | ||
|  | 4c61aede2e | 
							
								
								
									
										9
									
								
								.github/workflows/ccpp.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								.github/workflows/ccpp.yml
									
									
									
									
										vendored
									
									
								
							| @@ -19,15 +19,6 @@ jobs: | ||||
|     - name: make test_tsan | ||||
|       run: make test_tsan | ||||
|  | ||||
|   mac_tsan_openssl: | ||||
|     runs-on: macOS-latest | ||||
|     steps: | ||||
|     - uses: actions/checkout@v1 | ||||
|     - name: install openssl | ||||
|       run: brew install openssl@1.1 | ||||
|     - name: make test | ||||
|       run: make test_tsan_openssl | ||||
|  | ||||
|   mac_tsan_mbedtls: | ||||
|     runs-on: macOS-latest | ||||
|     steps: | ||||
|   | ||||
| @@ -251,3 +251,7 @@ if (USE_WS OR USE_TEST) | ||||
|       add_subdirectory(test) | ||||
|   endif() | ||||
| endif() | ||||
|  | ||||
| if (USE_LUAROCKS) | ||||
|     add_subdirectory(luarocks) | ||||
| endif() | ||||
|   | ||||
							
								
								
									
										30
									
								
								luarocks/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								luarocks/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| # | ||||
| # Author: Benjamin Sergeant | ||||
| # Copyright (c) 2020 Machine Zone, Inc. All rights reserved. | ||||
| # | ||||
|  | ||||
| cmake_minimum_required (VERSION 3.4.1) | ||||
| project (luarocks) | ||||
|  | ||||
| # There's -Weverything too for clang | ||||
| if (NOT WIN32) | ||||
|   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic") | ||||
| endif() | ||||
|  | ||||
| set (CMAKE_CXX_STANDARD 14) | ||||
|  | ||||
| option(USE_TLS "Add TLS support" ON) | ||||
|  | ||||
| include_directories(luarocks .) | ||||
|  | ||||
| add_executable(luarocks main.cpp) | ||||
|  | ||||
| include(FindLua) | ||||
| find_package(lua REQUIRED) | ||||
| target_link_libraries(luarocks ${LUA_LIBRARIES}) | ||||
| target_include_directories(luarocks PRIVATE ${LUA_INCLUDE_DIR}) | ||||
|  | ||||
| # library with the most dependencies come first | ||||
| target_link_libraries(luarocks ixwebsocket) | ||||
|  | ||||
| install(TARGETS luarocks RUNTIME DESTINATION bin) | ||||
							
								
								
									
										163
									
								
								luarocks/LuaWebSocket.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								luarocks/LuaWebSocket.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,163 @@ | ||||
| /* | ||||
|  *  LuaWebSocket.h | ||||
|  *  Author: Benjamin Sergeant | ||||
|  *  Copyright (c) 2020 Machine Zone, Inc. All rights reserved. | ||||
|  */ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <iostream> | ||||
| #include <string> | ||||
|  | ||||
| extern "C" | ||||
| { | ||||
|     #include "lua.h" | ||||
|     #include "lauxlib.h" | ||||
| } | ||||
|  | ||||
| #include "luawrapper.hpp" | ||||
| #include <ixwebsocket/IXWebSocket.h> | ||||
| #include <chrono> | ||||
| #include <thread> | ||||
| #include <queue> | ||||
| #include <mutex> | ||||
|  | ||||
| namespace ix | ||||
| { | ||||
|     class LuaWebSocket | ||||
|     { | ||||
|         public: | ||||
|             LuaWebSocket() | ||||
|             { | ||||
|                 _webSocket.setOnMessageCallback([this](const WebSocketMessagePtr& msg) { | ||||
|                     if (msg->type == ix::WebSocketMessageType::Message) | ||||
|                     { | ||||
|                         std::lock_guard<std::mutex> lock(_queueMutex); | ||||
|                         _queue.push(msg->str); | ||||
|                     } | ||||
|                 }); | ||||
|             } | ||||
|  | ||||
|             void setUrl(const std::string& url) { _webSocket.setUrl(url); } | ||||
|             const std::string& getUrl() { return _webSocket.getUrl(); } | ||||
|             void start() { _webSocket.start(); } | ||||
|             void send(const std::string& msg) { _webSocket.send(msg); } | ||||
|  | ||||
|             const std::string& getMessage() | ||||
|             { | ||||
|                 std::lock_guard<std::mutex> lock(_queueMutex); | ||||
|                 return _queue.front(); | ||||
|             } | ||||
|  | ||||
|             bool hasMessage() | ||||
|             { | ||||
|                 std::lock_guard<std::mutex> lock(_queueMutex); | ||||
|                 return !_queue.empty(); | ||||
|             } | ||||
|  | ||||
|             void popMessage() | ||||
|             { | ||||
|                 std::lock_guard<std::mutex> lock(_queueMutex); | ||||
|                 _queue.pop(); | ||||
|             } | ||||
|  | ||||
|         private: | ||||
|             WebSocket _webSocket; | ||||
|  | ||||
|             std::queue<std::string> _queue; | ||||
|             std::mutex _queueMutex; | ||||
|     }; | ||||
|  | ||||
|     LuaWebSocket* WebSocket_new(lua_State* /*L*/) | ||||
|     { | ||||
|         LuaWebSocket* webSocket = new LuaWebSocket(); | ||||
|         return webSocket; | ||||
|     } | ||||
|  | ||||
|     int WebSocket_getUrl(lua_State* L) | ||||
|     { | ||||
|         LuaWebSocket* luaWebSocket = luaW_check<LuaWebSocket>(L, 1); | ||||
|         lua_pushstring(L, luaWebSocket->getUrl().c_str()); | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     int WebSocket_setUrl(lua_State* L) | ||||
|     { | ||||
|         LuaWebSocket* luaWebSocket = luaW_check<LuaWebSocket>(L, 1); | ||||
|         const char* url = luaL_checkstring(L, 2); | ||||
|         luaWebSocket->setUrl(url); | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     int WebSocket_start(lua_State* L) | ||||
|     { | ||||
|         LuaWebSocket* luaWebSocket = luaW_check<LuaWebSocket>(L, 1); | ||||
|         luaWebSocket->start(); | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     int WebSocket_send(lua_State* L) | ||||
|     { | ||||
|         LuaWebSocket* luaWebSocket = luaW_check<LuaWebSocket>(L, 1); | ||||
|         const char* msg = luaL_checkstring(L, 2); | ||||
|         luaWebSocket->send(msg); | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     int WebSocket_getMessage(lua_State* L) | ||||
|     { | ||||
|         LuaWebSocket* luaWebSocket = luaW_check<LuaWebSocket>(L, 1); | ||||
|         lua_pushstring(L, luaWebSocket->getMessage().c_str()); | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     int WebSocket_hasMessage(lua_State* L) | ||||
|     { | ||||
|         LuaWebSocket* luaWebSocket = luaW_check<LuaWebSocket>(L, 1); | ||||
|         lua_pushboolean(L, luaWebSocket->hasMessage()); | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     int WebSocket_popMessage(lua_State* L) | ||||
|     { | ||||
|         LuaWebSocket* luaWebSocket = luaW_check<LuaWebSocket>(L, 1); | ||||
|         luaWebSocket->popMessage(); | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     // FIXME: This should be a static method, or be part of a different module | ||||
|     int WebSocket_sleep(lua_State* L) | ||||
|     { | ||||
|         // LuaWebSocket* luaWebSocket = luaW_check<LuaWebSocket>(L, 1); | ||||
|         auto duration = luaL_checkinteger(L, 2); | ||||
|         std::this_thread::sleep_for(std::chrono::milliseconds(duration)); | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     static luaL_Reg WebSocket_table[] = { | ||||
|         { NULL, NULL } | ||||
|     }; | ||||
|  | ||||
|     static luaL_Reg WebSocket_metatable[] = { | ||||
|         { "getUrl", WebSocket_getUrl }, | ||||
|         { "setUrl", WebSocket_setUrl }, | ||||
|         { "start", WebSocket_start }, | ||||
|         { "send", WebSocket_send }, | ||||
|         { "getMessage", WebSocket_getMessage }, | ||||
|         { "hasMessage", WebSocket_hasMessage }, | ||||
|         { "popMessage", WebSocket_popMessage }, | ||||
|         { "sleep", WebSocket_sleep }, | ||||
|         { NULL, NULL } | ||||
|     }; | ||||
|  | ||||
|     int luaopen_WebSocket(lua_State* L) | ||||
|     { | ||||
|         luaW_register<LuaWebSocket>(L, | ||||
|             "WebSocket", | ||||
|             WebSocket_table, | ||||
|             WebSocket_metatable, | ||||
|             WebSocket_new | ||||
|             ); | ||||
|         return 1; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										56
									
								
								luarocks/Player.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								luarocks/Player.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| #ifndef PLAYER_HPP | ||||
| #define PLAYER_HPP | ||||
|  | ||||
| #include <iostream> | ||||
|  | ||||
| class Player | ||||
| { | ||||
| public: | ||||
|     Player(const char* name, unsigned int health) : | ||||
|         m_Name(name), | ||||
|         m_Health(health) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     void info() | ||||
|     { | ||||
|         std::cout << m_Name << " have " << m_Health << " HP" << std::endl; | ||||
|     } | ||||
|  | ||||
|     void say(const char* text) | ||||
|     { | ||||
|         std::cout << m_Name << ": " << text << std::endl; | ||||
|     } | ||||
|  | ||||
|     void heal(Player* target) | ||||
|     { | ||||
|         target->setHealth(100); | ||||
|     } | ||||
|  | ||||
|     const char* getName() | ||||
|     { | ||||
|         return m_Name; | ||||
|     } | ||||
|  | ||||
|     unsigned int getHealth() | ||||
|     { | ||||
|         return m_Health; | ||||
|     } | ||||
|  | ||||
|     bool setHealth(unsigned int health) | ||||
|     { | ||||
|         if (health >= 0 && health <= 100) | ||||
|         { | ||||
|             m_Health = health; | ||||
|             return true; | ||||
|         } | ||||
|         else | ||||
|             return false; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     const char* m_Name; | ||||
|     unsigned int m_Health; | ||||
| }; | ||||
|  | ||||
| #endif // PLAYER_HPP | ||||
							
								
								
									
										7
									
								
								luarocks/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								luarocks/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| Wrapper based on https://github.com/LuaxY/cpp-lua | ||||
|  | ||||
| Examples to build C++ | ||||
| https://github.com/siffiejoe/lua-fltk4lua/blob/master/fltk4lua-scm-0.rockspec | ||||
| https://github.com/lua4web/refser/blob/master/rockspecs/refser-0.2-1.rockspec | ||||
|  | ||||
|  | ||||
							
								
								
									
										30
									
								
								luarocks/echo_client.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								luarocks/echo_client.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| -- | ||||
| -- make luarocks && (cd luarocks ; ../build/luarocks/luarocks) | ||||
| -- | ||||
| -- ... git push test with ssh key | ||||
| -- | ||||
| local webSocket = WebSocket.new() | ||||
|  | ||||
| webSocket:setUrl("ws://localhost:8008") | ||||
| print("Url: " .. webSocket:getUrl()) | ||||
|  | ||||
| -- Start the background thread | ||||
| webSocket:start() | ||||
|  | ||||
| local i = 0 | ||||
|  | ||||
| while true | ||||
| do | ||||
|     print("Sending message...") | ||||
|     webSocket:send("msg_" .. tostring(i)); | ||||
|     i = i + 1 | ||||
|  | ||||
|     print("Waiting 1s...") | ||||
|     webSocket:sleep(1000) | ||||
|  | ||||
|     if webSocket:hasMessage() then | ||||
|         local msg = webSocket:getMessage() | ||||
|         print("Received: " .. msg) | ||||
|         webSocket:popMessage() | ||||
|     end | ||||
| end | ||||
							
								
								
									
										15
									
								
								luarocks/functions.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								luarocks/functions.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| /* | ||||
|  *  functions.hpp | ||||
|  *  Author: Benjamin Sergeant | ||||
|  *  Copyright (c) 2020 Machine Zone, Inc. All rights reserved. | ||||
|  */ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <iostream> | ||||
|  | ||||
| int lua_info(lua_State* /*L*/) | ||||
| { | ||||
|     std::cout << "C++ Lua v0.1" << std::endl << std::endl; | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										709
									
								
								luarocks/luawrapper.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										709
									
								
								luarocks/luawrapper.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,709 @@ | ||||
| /* | ||||
|  * Copyright (c) 2010-2013 Alexander Ames | ||||
|  * Alexander.Ames@gmail.com | ||||
|  * See Copyright Notice at the end of this file | ||||
|  */ | ||||
|  | ||||
| // API Summary: | ||||
| // | ||||
| // LuaWrapper is a library designed to help bridge the gab between Lua and | ||||
| // C++. It is designed to be small (a single header file), simple, fast, | ||||
| // and typesafe. It has no external dependencies, and does not need to be | ||||
| // precompiled; the header can simply be dropped into a project and used | ||||
| // immediately. It even supports class inheritance to a certain degree. Objects | ||||
| // can be created in either Lua or C++, and passed back and forth. | ||||
| // | ||||
| // The main functions of interest are the following: | ||||
| //  luaW_is<T> | ||||
| //  luaW_to<T> | ||||
| //  luaW_check<T> | ||||
| //  luaW_push<T> | ||||
| //  luaW_register<T> | ||||
| //  luaW_setfuncs<T> | ||||
| //  luaW_extend<T, U> | ||||
| //  luaW_hold<T> | ||||
| //  luaW_release<T> | ||||
| // | ||||
| // These functions allow you to manipulate arbitrary classes just like you | ||||
| // would the primitive types (e.g. numbers or strings). If you are familiar | ||||
| // with the normal Lua API the behavior of these functions should be very | ||||
| // intuative. | ||||
| // | ||||
| // For more information see the README and the comments below | ||||
|  | ||||
| #ifndef LUA_WRAPPER_H_ | ||||
| #define LUA_WRAPPER_H_ | ||||
|  | ||||
| // If you are linking against Lua compiled in C++, define LUAW_NO_EXTERN_C | ||||
| #ifndef LUAW_NO_EXTERN_C | ||||
| extern "C" | ||||
| { | ||||
| #endif // LUAW_NO_EXTERN_C | ||||
|  | ||||
| #include "lua.h" | ||||
| #include "lauxlib.h" | ||||
|      | ||||
| #ifndef LUAW_NO_EXTERN_C | ||||
| } | ||||
| #endif // LUAW_NO_EXTERN_C | ||||
|  | ||||
| #define LUAW_POSTCTOR_KEY "__postctor" | ||||
| #define LUAW_EXTENDS_KEY "__extends" | ||||
| #define LUAW_STORAGE_KEY "storage" | ||||
| #define LUAW_CACHE_KEY "cache" | ||||
| #define LUAW_CACHE_METATABLE_KEY "cachemetatable" | ||||
| #define LUAW_HOLDS_KEY "holds" | ||||
| #define LUAW_WRAPPER_KEY "LuaWrapper" | ||||
|  | ||||
| // A simple utility function to adjust a given index | ||||
| // Useful for when a parameter index needs to be adjusted | ||||
| // after pushing or popping things off the stack | ||||
| inline int luaW_correctindex(lua_State* /*L*/, int index, int correction) | ||||
| { | ||||
|     return index < 0 ? index - correction : index; | ||||
| } | ||||
|  | ||||
| // These are the default allocator and deallocator. If you would prefer an | ||||
| // alternative option, you may select a different function when registering | ||||
| // your class. | ||||
| template <typename T> | ||||
| T* luaW_defaultallocator(lua_State*) | ||||
| { | ||||
|     return new T(); | ||||
| } | ||||
| template <typename T> | ||||
| void luaW_defaultdeallocator(lua_State*, T* obj) | ||||
| { | ||||
|     delete obj; | ||||
| } | ||||
|  | ||||
| // The identifier function is responsible for pushing a value unique to each | ||||
| // object on to the stack. Most of the time, this can simply be the address | ||||
| // of the pointer, but sometimes that is not adaquate. For example, if you | ||||
| // are using shared_ptr you would need to push the address of the object the | ||||
| // shared_ptr represents, rather than the address of the shared_ptr itself. | ||||
| template <typename T> | ||||
| void luaW_defaultidentifier(lua_State* L, T* obj) | ||||
| { | ||||
|     lua_pushlightuserdata(L, obj); | ||||
| } | ||||
|  | ||||
| // This class is what is used by LuaWrapper to contain the userdata. data | ||||
| // stores a pointer to the object itself, and cast is used to cast toward the | ||||
| // base class if there is one and it is necessary. Rather than use RTTI and | ||||
| // typid to compare types, I use the clever trick of using the cast to compare | ||||
| // types. Because there is at most one cast per type, I can use it to identify | ||||
| // when and object is the type I want. This is only used internally. | ||||
| struct luaW_Userdata | ||||
| { | ||||
|     luaW_Userdata(void* vptr = NULL, luaW_Userdata (*udcast)(const luaW_Userdata&) = NULL) | ||||
|         : data(vptr), cast(udcast) {} | ||||
|     void* data; | ||||
|     luaW_Userdata (*cast)(const luaW_Userdata&); | ||||
| }; | ||||
|  | ||||
| // This class cannot actually to be instantiated. It is used only hold the | ||||
| // table name and other information. | ||||
| template <typename T> | ||||
| class LuaWrapper | ||||
| { | ||||
| public: | ||||
|     static const char* classname; | ||||
|     static void (*identifier)(lua_State*, T*); | ||||
|     static T* (*allocator)(lua_State*); | ||||
|     static void (*deallocator)(lua_State*, T*); | ||||
|     static luaW_Userdata (*cast)(const luaW_Userdata&); | ||||
| private: | ||||
|     LuaWrapper(); | ||||
| }; | ||||
| template <typename T> const char* LuaWrapper<T>::classname; | ||||
| template <typename T> void (*LuaWrapper<T>::identifier)(lua_State*, T*); | ||||
| template <typename T> T* (*LuaWrapper<T>::allocator)(lua_State*); | ||||
| template <typename T> void (*LuaWrapper<T>::deallocator)(lua_State*, T*); | ||||
| template <typename T> luaW_Userdata (*LuaWrapper<T>::cast)(const luaW_Userdata&); | ||||
|  | ||||
| // Cast from an object of type T to an object of type U. This template | ||||
| // function is instantiated by calling luaW_extend<T, U>(L). This is only used | ||||
| // internally. | ||||
| template <typename T, typename U> | ||||
| luaW_Userdata luaW_cast(const luaW_Userdata& obj) | ||||
| { | ||||
|     return luaW_Userdata(static_cast<U*>(static_cast<T*>(obj.data)), LuaWrapper<U>::cast); | ||||
| } | ||||
|  | ||||
| template <typename T, typename U> | ||||
| void luaW_identify(lua_State* L, T* obj) | ||||
| { | ||||
|     LuaWrapper<U>::identifier(L, static_cast<U*>(obj)); | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| inline void luaW_wrapperfield(lua_State* L, const char* field) | ||||
| { | ||||
|     lua_getfield(L, LUA_REGISTRYINDEX, LUAW_WRAPPER_KEY); // ... LuaWrapper | ||||
|     lua_getfield(L, -1, field); // ... LuaWrapper LuaWrapper.field | ||||
|     lua_getfield(L, -1, LuaWrapper<T>::classname); // ... LuaWrapper LuaWrapper.field LuaWrapper.field.class | ||||
|     lua_replace(L, -3); // ... LuaWrapper.field.class LuaWrapper.field | ||||
|     lua_pop(L, 1); // ... LuaWrapper.field.class | ||||
| } | ||||
|  | ||||
| // Analogous to lua_is(boolean|string|*) | ||||
| // | ||||
| // Returns 1 if the value at the given acceptable index is of type T (or if | ||||
| // strict is false, convertable to type T) and 0 otherwise. | ||||
| template <typename T> | ||||
| bool luaW_is(lua_State *L, int index, bool strict = false) | ||||
| { | ||||
|     bool equal = false;// lua_isnil(L, index); | ||||
|     if (!equal && lua_isuserdata(L, index) && lua_getmetatable(L, index)) | ||||
|     { | ||||
|         // ... ud ... udmt | ||||
|         luaL_getmetatable(L, LuaWrapper<T>::classname); // ... ud ... udmt Tmt | ||||
|         equal = lua_rawequal(L, -1, -2) != 0; | ||||
|         if (!equal && !strict) | ||||
|         { | ||||
|             lua_getfield(L, -2, LUAW_EXTENDS_KEY); // ... ud ... udmt Tmt udmt.extends | ||||
|             for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) | ||||
|             { | ||||
|                 // ... ud ... udmt Tmt udmt.extends k v | ||||
|                 equal = lua_rawequal(L, -1, -4) != 0; | ||||
|                 if (equal) | ||||
|                 { | ||||
|                     lua_pop(L, 2); // ... ud ... udmt Tmt udmt.extends | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|             lua_pop(L, 1); // ... ud ... udmt Tmt | ||||
|         } | ||||
|         lua_pop(L, 2); // ... ud ... | ||||
|     } | ||||
|     return equal; | ||||
| } | ||||
|  | ||||
| // Analogous to lua_to(boolean|string|*) | ||||
| // | ||||
| // Converts the given acceptable index to a T*. That value must be of (or | ||||
| // convertable to) type T; otherwise, returns NULL. | ||||
| template <typename T> | ||||
| T* luaW_to(lua_State* L, int index, bool strict = false) | ||||
| { | ||||
|     if (luaW_is<T>(L, index, strict)) | ||||
|     { | ||||
|         luaW_Userdata* pud = static_cast<luaW_Userdata*>(lua_touserdata(L, index)); | ||||
|         luaW_Userdata ud; | ||||
|         while (!strict && LuaWrapper<T>::cast != pud->cast) | ||||
|         { | ||||
|             ud = pud->cast(*pud); | ||||
|             pud = &ud; | ||||
|         } | ||||
|         return static_cast<T*>(pud->data); | ||||
|     } | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| // Analogous to luaL_check(boolean|string|*) | ||||
| // | ||||
| // Converts the given acceptable index to a T*. That value must be of (or | ||||
| // convertable to) type T; otherwise, an error is raised. | ||||
| template <typename T> | ||||
| T* luaW_check(lua_State* L, int index, bool strict = false) | ||||
| { | ||||
|     T* obj = NULL; | ||||
|     if (luaW_is<T>(L, index, strict)) | ||||
|     { | ||||
|         luaW_Userdata* pud = (luaW_Userdata*)lua_touserdata(L, index); | ||||
|         luaW_Userdata ud; | ||||
|         while (!strict && LuaWrapper<T>::cast != pud->cast) | ||||
|         { | ||||
|             ud = pud->cast(*pud); | ||||
|             pud = &ud; | ||||
|         } | ||||
|         obj = (T*)pud->data; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         const char *msg = lua_pushfstring(L, "%s expected, got %s", LuaWrapper<T>::classname, luaL_typename(L, index)); | ||||
|         luaL_argerror(L, index, msg); | ||||
|     } | ||||
|     return obj; | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| T* luaW_opt(lua_State* L, int index, T* fallback = NULL, bool strict = false) | ||||
| { | ||||
|     if (lua_isnil(L, index)) | ||||
|         return fallback; | ||||
|     else | ||||
|         return luaW_check<T>(L, index, strict); | ||||
| } | ||||
|  | ||||
| // Analogous to lua_push(boolean|string|*) | ||||
| // | ||||
| // Pushes a userdata of type T onto the stack. If this object already exists in | ||||
| // the Lua environment, it will assign the existing storage table to it. | ||||
| // Otherwise, a new storage table will be created for it. | ||||
| template <typename T> | ||||
| void luaW_push(lua_State* L, T* obj) | ||||
| { | ||||
|     if (obj) | ||||
|     { | ||||
|         LuaWrapper<T>::identifier(L, obj); // ... id | ||||
|         luaW_wrapperfield<T>(L, LUAW_CACHE_KEY); // ... id cache | ||||
|         lua_pushvalue(L, -2); // ... id cache id | ||||
|         lua_gettable(L, -2); // ... id cache obj | ||||
|         if (lua_isnil(L, -1)) | ||||
|         { | ||||
|             // Create the new luaW_userdata and place it in the cache | ||||
|             lua_pop(L, 1); // ... id cache | ||||
|             lua_insert(L, -2); // ... cache id | ||||
|             luaW_Userdata* ud = static_cast<luaW_Userdata*>(lua_newuserdata(L, sizeof(luaW_Userdata))); // ... cache id obj | ||||
|             ud->data = obj; | ||||
|             ud->cast = LuaWrapper<T>::cast; | ||||
|             lua_pushvalue(L, -1); // ... cache id obj obj | ||||
|             lua_insert(L, -4); // ... obj cache id obj | ||||
|             lua_settable(L, -3); // ... obj cache | ||||
|  | ||||
|             luaL_getmetatable(L, LuaWrapper<T>::classname); // ... obj cache mt | ||||
|             lua_setmetatable(L, -3); // ... obj cache | ||||
|  | ||||
|             lua_pop(L, 1); // ... obj | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             lua_replace(L, -3); // ... obj cache | ||||
|             lua_pop(L, 1); // ... obj | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         lua_pushnil(L); | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Instructs LuaWrapper that it owns the userdata, and can manage its memory. | ||||
| // When all references to the object are removed, Lua is free to garbage | ||||
| // collect it and delete the object. | ||||
| // | ||||
| // Returns true if luaW_hold took hold of the object, and false if it was | ||||
| // already held | ||||
| template <typename T> | ||||
| bool luaW_hold(lua_State* L, T* obj) | ||||
| { | ||||
|     luaW_wrapperfield<T>(L, LUAW_HOLDS_KEY); // ... holds | ||||
|     LuaWrapper<T>::identifier(L, obj); // ... holds id | ||||
|     lua_pushvalue(L, -1); // ... holds id id | ||||
|     lua_gettable(L, -3); // ... holds id hold | ||||
|     // If it's not held, hold it | ||||
|     if (!lua_toboolean(L, -1)) | ||||
|     { | ||||
|         // Apply hold boolean | ||||
|         lua_pop(L, 1); // ... holds id | ||||
|         lua_pushboolean(L, true); // ... holds id true | ||||
|         lua_settable(L, -3); // ... holds | ||||
|         lua_pop(L, 1); // ... | ||||
|         return true; | ||||
|     } | ||||
|     lua_pop(L, 3); // ... | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| // Releases LuaWrapper's hold on an object. This allows the user to remove | ||||
| // all references to an object in Lua and ensure that Lua will not attempt to | ||||
| // garbage collect it. | ||||
| // | ||||
| // This function takes the index of the identifier for an object rather than | ||||
| // the object itself. This is because needs to be able to run after the object | ||||
| // has already been deallocated. A wrapper is provided for when it is more | ||||
| // convenient to pass in the object directly. | ||||
| template <typename T> | ||||
| void luaW_release(lua_State* L, int index) | ||||
| { | ||||
|     luaW_wrapperfield<T>(L, LUAW_HOLDS_KEY); // ... id ... holds | ||||
|     lua_pushvalue(L, luaW_correctindex(L, index, 1)); // ... id ... holds id | ||||
|     lua_pushnil(L); // ... id ... holds id nil | ||||
|     lua_settable(L, -3); // ... id ... holds | ||||
|     lua_pop(L, 1); // ... id ... | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| void luaW_release(lua_State* L, T* obj) | ||||
| { | ||||
|     LuaWrapper<T>::identifier(L, obj); // ... id | ||||
|     luaW_release<T>(L, -1); // ... id | ||||
|     lua_pop(L, 1); // ... | ||||
| } | ||||
|  | ||||
| // This function is called from Lua, not C++ | ||||
| // | ||||
| // Calls the lua post-constructor (LUAW_POSTCTOR_KEY or "__postctor") on a | ||||
| // userdata. Assumes the userdata is on top of the stack, and numargs arguments | ||||
| // are below it. This runs the LUAW_POSTCTOR_KEY function on T's metatable, | ||||
| // using the object as the first argument and whatever else is below it as | ||||
| // the rest of the arguments This exists to allow types to adjust values in | ||||
| // thier storage table, which can not be created until after the constructor is | ||||
| // called. | ||||
| template <typename T> | ||||
| void luaW_postconstructor(lua_State* L, int numargs) | ||||
| { | ||||
|     // ... args... ud | ||||
|     lua_getfield(L, -1, LUAW_POSTCTOR_KEY); // ... args... ud ud.__postctor | ||||
|     if (lua_type(L, -1) == LUA_TFUNCTION) | ||||
|     { | ||||
|         lua_pushvalue(L, -2); // ... args... ud ud.__postctor ud | ||||
|         lua_insert(L, -3 - numargs); // ... ud args... ud ud.__postctor | ||||
|         lua_insert(L, -3 - numargs); // ... ud.__postctor ud args... ud | ||||
|         lua_insert(L, -3 - numargs); // ... ud ud.__postctor ud args... | ||||
|         lua_call(L, numargs + 1, 0); // ... ud | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         lua_pop(L, 1); // ... ud | ||||
|     } | ||||
| } | ||||
|  | ||||
| // This function is generally called from Lua, not C++ | ||||
| // | ||||
| // Creates an object of type T using the constructor and subsequently calls the | ||||
| // post-constructor on it. | ||||
| template <typename T> | ||||
| inline int luaW_new(lua_State* L, int args) | ||||
| { | ||||
|     T* obj = LuaWrapper<T>::allocator(L); | ||||
|     luaW_push<T>(L, obj); | ||||
|     luaW_hold<T>(L, obj); | ||||
|     luaW_postconstructor<T>(L, args); | ||||
|     return 1; | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| int luaW_new(lua_State* L) | ||||
| { | ||||
|     return luaW_new<T>(L, lua_gettop(L)); | ||||
| } | ||||
|  | ||||
| // This function is called from Lua, not C++ | ||||
| // | ||||
| // The default metamethod to call when indexing into lua userdata representing | ||||
| // an object of type T. This will first check the userdata's environment table | ||||
| // and if it's not found there it will check the metatable. This is done so | ||||
| // individual userdata can be treated as a table, and can hold thier own | ||||
| // values. | ||||
| template <typename T> | ||||
| int luaW_index(lua_State* L) | ||||
| { | ||||
|     // obj key | ||||
|     T* obj = luaW_to<T>(L, 1); | ||||
|     luaW_wrapperfield<T>(L, LUAW_STORAGE_KEY); // obj key storage | ||||
|     LuaWrapper<T>::identifier(L, obj); // obj key storage id | ||||
|     lua_gettable(L, -2); // obj key storage store | ||||
|  | ||||
|     // Check if storage table exists | ||||
|     if (!lua_isnil(L, -1)) | ||||
|     { | ||||
|         lua_pushvalue(L, -3); // obj key storage store key | ||||
|         lua_gettable(L, -2); // obj key storage store store[k] | ||||
|     } | ||||
|  | ||||
|     // If either there is no storage table or the key wasn't found | ||||
|     // then fall back to the metatable | ||||
|     if (lua_isnil(L, -1)) | ||||
|     { | ||||
|         lua_settop(L, 2); // obj key | ||||
|         lua_getmetatable(L, -2); // obj key mt | ||||
|         lua_pushvalue(L, -2); // obj key mt k | ||||
|         lua_gettable(L, -2); // obj key mt mt[k] | ||||
|     } | ||||
|     return 1; | ||||
| } | ||||
|  | ||||
| // This function is called from Lua, not C++ | ||||
| // | ||||
| // The default metamethod to call when creating a new index on lua userdata | ||||
| // representing an object of type T. This will index into the the userdata's | ||||
| // environment table that it keeps for personal storage. This is done so | ||||
| // individual userdata can be treated as a table, and can hold thier own | ||||
| // values. | ||||
| template <typename T> | ||||
| int luaW_newindex(lua_State* L) | ||||
| { | ||||
|     // obj key value | ||||
|     T* obj = luaW_check<T>(L, 1); | ||||
|     luaW_wrapperfield<T>(L, LUAW_STORAGE_KEY); // obj key value storage | ||||
|     LuaWrapper<T>::identifier(L, obj); // obj key value storage id | ||||
|     lua_pushvalue(L, -1); // obj key value storage id id | ||||
|     lua_gettable(L, -3); // obj key value storage id store | ||||
|  | ||||
|     // Add the storage table if there isn't one already | ||||
|     if (lua_isnil(L, -1)) | ||||
|     { | ||||
|         lua_pop(L, 1); // obj key value storage id | ||||
|         lua_newtable(L); // obj key value storage id store | ||||
|         lua_pushvalue(L, -1); // obj key value storage id store store | ||||
|         lua_insert(L, -3); // obj key value storage store id store | ||||
|         lua_settable(L, -4); // obj key value storage store | ||||
|     } | ||||
|  | ||||
|     lua_pushvalue(L, 2); // obj key value ... store key | ||||
|     lua_pushvalue(L, 3); // obj key value ... store key value | ||||
|     lua_settable(L, -3); // obj key value ... store | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| // This function is called from Lua, not C++ | ||||
| // | ||||
| // The __gc metamethod handles cleaning up userdata. The userdata's reference | ||||
| // count is decremented and if this is the final reference to the userdata its | ||||
| // environment table is nil'd and pointer deleted with the destructor callback. | ||||
| template <typename T> | ||||
| int luaW_gc(lua_State* L) | ||||
| { | ||||
|     // obj | ||||
|     T* obj = luaW_to<T>(L, 1); | ||||
|     LuaWrapper<T>::identifier(L, obj); // obj key value storage id | ||||
|     luaW_wrapperfield<T>(L, LUAW_HOLDS_KEY); // obj id counts count holds | ||||
|     lua_pushvalue(L, 2); // obj id counts count holds id | ||||
|     lua_gettable(L, -2); // obj id counts count holds hold | ||||
|     if (lua_toboolean(L, -1) && LuaWrapper<T>::deallocator) | ||||
|     { | ||||
|         LuaWrapper<T>::deallocator(L, obj); | ||||
|     } | ||||
|  | ||||
|     luaW_wrapperfield<T>(L, LUAW_STORAGE_KEY); // obj id counts count holds hold storage | ||||
|     lua_pushvalue(L, 2); // obj id counts count holds hold storage id | ||||
|     lua_pushnil(L); // obj id counts count holds hold storage id nil | ||||
|     lua_settable(L, -3); // obj id counts count holds hold storage | ||||
|  | ||||
|     luaW_release<T>(L, 2); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| // Thakes two tables and registers them with Lua to the table on the top of the | ||||
| // stack.  | ||||
| // | ||||
| // This function is only called from LuaWrapper internally.  | ||||
| inline void luaW_registerfuncs(lua_State* L, const luaL_Reg defaulttable[], const luaL_Reg table[]) | ||||
| { | ||||
|     // ... T | ||||
| #if LUA_VERSION_NUM > 501 | ||||
|     if (defaulttable) | ||||
|         luaL_setfuncs(L, defaulttable, 0); // ... T | ||||
|     if (table) | ||||
|         luaL_setfuncs(L, table, 0); // ... T | ||||
| #else | ||||
|     if (defaulttable) | ||||
|         luaL_register(L, NULL, defaulttable); // ... T | ||||
|     if (table) | ||||
|         luaL_register(L, NULL, table); // ... T | ||||
| #endif | ||||
| } | ||||
|  | ||||
| // Initializes the LuaWrapper tables used to track internal state.  | ||||
| // | ||||
| // This function is only called from LuaWrapper internally.  | ||||
| inline void luaW_initialize(lua_State* L) | ||||
| { | ||||
|     // Ensure that the LuaWrapper table is set up | ||||
|     lua_getfield(L, LUA_REGISTRYINDEX, LUAW_WRAPPER_KEY); // ... LuaWrapper | ||||
|     if (lua_isnil(L, -1)) | ||||
|     { | ||||
|         lua_newtable(L); // ... nil {} | ||||
|         lua_pushvalue(L, -1); // ... nil {} {} | ||||
|         lua_setfield(L, LUA_REGISTRYINDEX, LUAW_WRAPPER_KEY); // ... nil LuaWrapper | ||||
|          | ||||
|         // Create a storage table         | ||||
|         lua_newtable(L); // ... LuaWrapper nil {} | ||||
|         lua_setfield(L, -2, LUAW_STORAGE_KEY); // ... nil LuaWrapper | ||||
|          | ||||
|         // Create a holds table | ||||
|         lua_newtable(L); // ... LuaWrapper {} | ||||
|         lua_setfield(L, -2, LUAW_HOLDS_KEY); // ... nil LuaWrapper | ||||
|  | ||||
|         // Create a cache table, with weak values so that the userdata will not | ||||
|         // be ref counted | ||||
|         lua_newtable(L); // ... nil LuaWrapper {} | ||||
|         lua_setfield(L, -2, LUAW_CACHE_KEY); // ... nil LuaWrapper | ||||
|          | ||||
|         lua_newtable(L); // ... nil LuaWrapper {} | ||||
|         lua_pushstring(L, "v"); // ... nil LuaWrapper {} "v" | ||||
|         lua_setfield(L, -2, "__mode"); // ... nil LuaWrapper {} | ||||
|         lua_setfield(L, -2, LUAW_CACHE_METATABLE_KEY); // ... nil LuaWrapper | ||||
|          | ||||
|         lua_pop(L, 1); // ... nil | ||||
|     } | ||||
|     lua_pop(L, 1); // ... | ||||
| } | ||||
|  | ||||
| // Run luaW_register or luaW_setfuncs to create a table and metatable for your | ||||
| // class.  These functions create a table with filled with the function from | ||||
| // the table argument in addition to the functions new and build (This is | ||||
| // generally for things you think of as static methods in C++). The given | ||||
| // metatable argument becomes a metatable for each object of your class. These | ||||
| // can be thought of as member functions or methods. | ||||
| // | ||||
| // You may also supply constructors and destructors for classes that do not | ||||
| // have a default constructor or that require special set up or tear down. You | ||||
| // may specify NULL as the constructor, which means that you will not be able | ||||
| // to call the new function on your class table. You will need to manually push | ||||
| // objects from C++. By default, the default constructor is used to create | ||||
| // objects and a simple call to delete is used to destroy them. | ||||
| // | ||||
| // By default LuaWrapper uses the address of C++ object to identify unique | ||||
| // objects. In some cases this is not desired, such as in the case of | ||||
| // shared_ptrs. Two shared_ptrs may themselves have unique locations in memory | ||||
| // but still represent the same object. For cases like that, you may specify an | ||||
| // identifier function which is responsible for pushing a key representing your | ||||
| // object on to the stack. | ||||
| // | ||||
| // luaW_register will set table as the new value of the global of the given | ||||
| // name. luaW_setfuncs is identical to luaW_register, but it does not set the | ||||
| // table globally.  As with luaL_register and luaL_setfuncs, both funcstions | ||||
| // leave the new table on the top of the stack. | ||||
| template <typename T> | ||||
| void luaW_setfuncs(lua_State* L, const char* classname, const luaL_Reg* table, const luaL_Reg* metatable, T* (*allocator)(lua_State*) = luaW_defaultallocator<T>, void (*deallocator)(lua_State*, T*) = luaW_defaultdeallocator<T>, void (*identifier)(lua_State*, T*) = luaW_defaultidentifier<T>) | ||||
| { | ||||
|     luaW_initialize(L); | ||||
|  | ||||
|     LuaWrapper<T>::classname = classname; | ||||
|     LuaWrapper<T>::identifier = identifier; | ||||
|     LuaWrapper<T>::allocator = allocator; | ||||
|     LuaWrapper<T>::deallocator = deallocator; | ||||
|  | ||||
|     const luaL_Reg defaulttable[] = | ||||
|     { | ||||
|         { "new", luaW_new<T> }, | ||||
|         { NULL, NULL } | ||||
|     }; | ||||
|     const luaL_Reg defaultmetatable[] =  | ||||
|     {  | ||||
|         { "__index", luaW_index<T> },  | ||||
|         { "__newindex", luaW_newindex<T> },  | ||||
|         { "__gc", luaW_gc<T> },  | ||||
|         { NULL, NULL }  | ||||
|     }; | ||||
|  | ||||
|     // Set up per-type tables | ||||
|     lua_getfield(L, LUA_REGISTRYINDEX, LUAW_WRAPPER_KEY); // ... LuaWrapper | ||||
|      | ||||
|     lua_getfield(L, -1, LUAW_STORAGE_KEY); // ... LuaWrapper LuaWrapper.storage | ||||
|     lua_newtable(L); // ... LuaWrapper LuaWrapper.storage {} | ||||
|     lua_setfield(L, -2, LuaWrapper<T>::classname); // ... LuaWrapper LuaWrapper.storage | ||||
|     lua_pop(L, 1); // ... LuaWrapper | ||||
|  | ||||
|     lua_getfield(L, -1, LUAW_HOLDS_KEY); // ... LuaWrapper LuaWrapper.holds | ||||
|     lua_newtable(L); // ... LuaWrapper LuaWrapper.holds {} | ||||
|     lua_setfield(L, -2, LuaWrapper<T>::classname); // ... LuaWrapper LuaWrapper.holds | ||||
|     lua_pop(L, 1); // ... LuaWrapper | ||||
|  | ||||
|     lua_getfield(L, -1, LUAW_CACHE_KEY); // ... LuaWrapper LuaWrapper.cache | ||||
|     lua_newtable(L); // ... LuaWrapper LuaWrapper.cache {} | ||||
|     luaW_wrapperfield<T>(L, LUAW_CACHE_METATABLE_KEY); // ... LuaWrapper LuaWrapper.cache {} cmt | ||||
|     lua_setmetatable(L, -2); // ... LuaWrapper LuaWrapper.cache {} | ||||
|     lua_setfield(L, -2, LuaWrapper<T>::classname); // ... LuaWrapper LuaWrapper.cache | ||||
|          | ||||
|     lua_pop(L, 2); // ... | ||||
|      | ||||
|     // Open table | ||||
|     lua_newtable(L); // ... T | ||||
|     luaW_registerfuncs(L, allocator ? defaulttable : NULL, table); // ... T | ||||
|  | ||||
|     // Open metatable, set up extends table | ||||
|     luaL_newmetatable(L, classname); // ... T mt | ||||
|     lua_newtable(L); // ... T mt {} | ||||
|     lua_setfield(L, -2, LUAW_EXTENDS_KEY); // ... T mt | ||||
|     luaW_registerfuncs(L, defaultmetatable, metatable); // ... T mt | ||||
|     lua_setfield(L, -2, "metatable"); // ... T | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| void luaW_register(lua_State* L, const char* classname, const luaL_Reg* table, const luaL_Reg* metatable, T* (*allocator)(lua_State*) = luaW_defaultallocator<T>, void (*deallocator)(lua_State*, T*) = luaW_defaultdeallocator<T>, void (*identifier)(lua_State*, T*) = luaW_defaultidentifier<T>) | ||||
| { | ||||
|     luaW_setfuncs(L, classname, table, metatable, allocator, deallocator, identifier); // ... T | ||||
|     lua_pushvalue(L, -1); // ... T T | ||||
|     lua_setglobal(L, classname); // ... T | ||||
| } | ||||
|  | ||||
| // luaW_extend is used to declare that class T inherits from class U. All | ||||
| // functions in the base class will be available to the derived class (except | ||||
| // when they share a function name, in which case the derived class's function | ||||
| // wins). This also allows luaW_to<T> to cast your object apropriately, as | ||||
| // casts straight through a void pointer do not work. | ||||
| template <typename T, typename U> | ||||
| void luaW_extend(lua_State* L) | ||||
| { | ||||
|     if(!LuaWrapper<T>::classname) | ||||
|         luaL_error(L, "attempting to call extend on a type that has not been registered"); | ||||
|  | ||||
|     if(!LuaWrapper<U>::classname) | ||||
|         luaL_error(L, "attempting to extend %s by a type that has not been registered", LuaWrapper<T>::classname); | ||||
|  | ||||
|     LuaWrapper<T>::cast = luaW_cast<T, U>; | ||||
|     LuaWrapper<T>::identifier = luaW_identify<T, U>; | ||||
|  | ||||
|     luaL_getmetatable(L, LuaWrapper<T>::classname); // mt | ||||
|     luaL_getmetatable(L, LuaWrapper<U>::classname); // mt emt | ||||
|  | ||||
|     // Point T's metatable __index at U's metatable for inheritance | ||||
|     lua_newtable(L); // mt emt {} | ||||
|     lua_pushvalue(L, -2); // mt emt {} emt | ||||
|     lua_setfield(L, -2, "__index"); // mt emt {} | ||||
|     lua_setmetatable(L, -3); // mt emt | ||||
|  | ||||
|     // Set up per-type tables to point at parent type | ||||
|     lua_getfield(L, LUA_REGISTRYINDEX, LUAW_WRAPPER_KEY); // ... LuaWrapper | ||||
|      | ||||
|     lua_getfield(L, -1, LUAW_STORAGE_KEY); // ... LuaWrapper LuaWrapper.storage | ||||
|     lua_getfield(L, -1, LuaWrapper<U>::classname); // ... LuaWrapper LuaWrapper.storage U | ||||
|     lua_setfield(L, -2, LuaWrapper<T>::classname); // ... LuaWrapper LuaWrapper.storage | ||||
|     lua_pop(L, 1); // ... LuaWrapper | ||||
|  | ||||
|     lua_getfield(L, -1, LUAW_HOLDS_KEY); // ... LuaWrapper LuaWrapper.holds | ||||
|     lua_getfield(L, -1, LuaWrapper<U>::classname); // ... LuaWrapper LuaWrapper.holds U | ||||
|     lua_setfield(L, -2, LuaWrapper<T>::classname); // ... LuaWrapper LuaWrapper.holds | ||||
|     lua_pop(L, 1); // ... LuaWrapper | ||||
|  | ||||
|     lua_getfield(L, -1, LUAW_CACHE_KEY); // ... LuaWrapper LuaWrapper.cache | ||||
|     lua_getfield(L, -1, LuaWrapper<U>::classname); // ... LuaWrapper LuaWrapper.cache U | ||||
|     lua_setfield(L, -2, LuaWrapper<T>::classname); // ... LuaWrapper LuaWrapper.cache | ||||
|          | ||||
|     lua_pop(L, 2); // ... | ||||
|      | ||||
|     // Make a list of all types that inherit from U, for type checking | ||||
|     lua_getfield(L, -2, LUAW_EXTENDS_KEY); // mt emt mt.extends | ||||
|     lua_pushvalue(L, -2); // mt emt mt.extends emt | ||||
|     lua_setfield(L, -2, LuaWrapper<U>::classname); // mt emt mt.extends | ||||
|     lua_getfield(L, -2, LUAW_EXTENDS_KEY); // mt emt mt.extends emt.extends | ||||
|     for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) | ||||
|     { | ||||
|         // mt emt mt.extends emt.extends k v | ||||
|         lua_pushvalue(L, -2); // mt emt mt.extends emt.extends k v k | ||||
|         lua_pushvalue(L, -2); // mt emt mt.extends emt.extends k v k | ||||
|         lua_rawset(L, -6); // mt emt mt.extends emt.extends k v | ||||
|     } | ||||
|  | ||||
|     lua_pop(L, 4); // mt emt | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Copyright (c) 2010-2013 Alexander Ames | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to | ||||
|  * deal in the Software without restriction, including without limitation the | ||||
|  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
|  * sell copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
|  * FROM OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
|  * IN THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| #endif // LUA_WRAPPER_H_ | ||||
							
								
								
									
										714
									
								
								luarocks/luawrapperutil.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										714
									
								
								luarocks/luawrapperutil.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,714 @@ | ||||
| /* | ||||
|  * Copyright (c) 2010-2013 Alexander Ames | ||||
|  * Alexander.Ames@gmail.com | ||||
|  * See Copyright Notice at the end of this file | ||||
|  */ | ||||
|  | ||||
| // API Summary: | ||||
| // | ||||
| // This is a set of utility functions that add to the functionalit of | ||||
| // LuaWrapper. Over time I found myself repeating a few patterns, such as | ||||
| // writing many trvial getter and setter functions, and wanting pass ownership | ||||
| // of one object to another and have the Lua script properly handle that case. | ||||
| // | ||||
| // This file contains the additional functions that I've added but that do | ||||
| // not really belong in the core API. | ||||
|  | ||||
| #ifndef LUAWRAPPERUTILS_HPP_ | ||||
| #define LUAWRAPPERUTILS_HPP_ | ||||
|  | ||||
| #include "luawrapper.hpp" | ||||
|  | ||||
| #ifndef LUAW_NO_CXX11 | ||||
| #include <type_traits> | ||||
| #endif | ||||
|  | ||||
| #ifndef LUAW_STD | ||||
| #define LUAW_STD std | ||||
| #endif | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // | ||||
| // A set of templated luaL_check and lua_push functions for use in the getters | ||||
| // and setters below | ||||
| // | ||||
| // It is often useful to override luaU_check, luaU_to and/or luaU_push to | ||||
| // operate on your own simple types rather than register your type with | ||||
| // LuaWrapper, especially with small objects. | ||||
| // | ||||
|  | ||||
| template<typename U, typename = void> | ||||
| struct luaU_Impl | ||||
| { | ||||
|     static U    luaU_check(lua_State* L, int      index); | ||||
|     static U    luaU_to   (lua_State* L, int      index); | ||||
|     static void luaU_push (lua_State* L, const U& value); | ||||
|     static void luaU_push (lua_State* L,       U& value); | ||||
| }; | ||||
|  | ||||
| template<typename U> U    luaU_check(lua_State* L, int      index) { return luaU_Impl<U>::luaU_check(L, index); } | ||||
| template<typename U> U    luaU_to   (lua_State* L, int      index) { return luaU_Impl<U>::luaU_to   (L, index); } | ||||
| template<typename U> void luaU_push (lua_State* L, const U& value) {        luaU_Impl<U>::luaU_push (L, value); } | ||||
| template<typename U> void luaU_push (lua_State* L,       U& value) {        luaU_Impl<U>::luaU_push (L, value); } | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // | ||||
| // This is slightly different than the previous three functions in that you | ||||
| // shouldn't need to write your own version of it, since it uses luaU_check | ||||
| // automatically. | ||||
| // | ||||
| template<typename U> | ||||
| U luaU_opt(lua_State* L, int index, const U& fallback = U()) | ||||
| { | ||||
|     if (lua_isnil(L, index)) | ||||
|         return fallback; | ||||
|     else | ||||
|         return luaU_Impl<U>::luaU_check(L, index); | ||||
| } | ||||
|  | ||||
| template<> | ||||
| struct luaU_Impl<bool> | ||||
| { | ||||
|     static bool luaU_check(lua_State* L, int         index) { return lua_toboolean  (L, index) != 0; } | ||||
|     static bool luaU_to   (lua_State* L, int         index) { return lua_toboolean  (L, index) != 0; } | ||||
|     static void luaU_push (lua_State* L, const bool& value) {        lua_pushboolean(L, value); } | ||||
| }; | ||||
|  | ||||
| template<> | ||||
| struct luaU_Impl<const char*> | ||||
| { | ||||
|     static const char* luaU_check(lua_State* L, int                index) { return luaL_checkstring(L, index); } | ||||
|     static const char* luaU_to   (lua_State* L, int                index) { return lua_tostring    (L, index); } | ||||
|     static void        luaU_push (lua_State* L, const char* const& value) {        lua_pushstring  (L, value); } | ||||
| }; | ||||
|  | ||||
| template<> | ||||
| struct luaU_Impl<unsigned int> | ||||
| { | ||||
|     static unsigned int luaU_check(lua_State* L, int                 index) { return static_cast<unsigned int>(luaL_checkinteger(L, index)); } | ||||
|     static unsigned int luaU_to   (lua_State* L, int                 index) { return static_cast<unsigned int>(lua_tointeger    (L, index)); } | ||||
|     static void         luaU_push (lua_State* L, const unsigned int& value) {                                  lua_pushinteger  (L, value); } | ||||
| }; | ||||
|  | ||||
| template<> | ||||
| struct luaU_Impl<int> | ||||
| { | ||||
|     static int  luaU_check(lua_State* L, int        index) { return static_cast<int>(luaL_checkinteger(L, index)); } | ||||
|     static int  luaU_to   (lua_State* L, int        index) { return static_cast<int>(lua_tointeger    (L, index)); } | ||||
|     static void luaU_push (lua_State* L, const int& value) {                         lua_pushinteger  (L, value); } | ||||
| }; | ||||
|  | ||||
| template<> | ||||
| struct luaU_Impl<unsigned char> | ||||
| { | ||||
|     static unsigned char luaU_check(lua_State* L, int                  index) { return static_cast<unsigned char>(luaL_checkinteger(L, index)); } | ||||
|     static unsigned char luaU_to   (lua_State* L, int                  index) { return static_cast<unsigned char>(lua_tointeger    (L, index)); } | ||||
|     static void          luaU_push (lua_State* L, const unsigned char& value) {                                   lua_pushinteger  (L, value); } | ||||
| }; | ||||
|  | ||||
| template<> | ||||
| struct luaU_Impl<char> | ||||
| { | ||||
|     static char luaU_check(lua_State* L, int         index) { return static_cast<char>(luaL_checkinteger(L, index)); } | ||||
|     static char luaU_to   (lua_State* L, int         index) { return static_cast<char>(lua_tointeger    (L, index)); } | ||||
|     static void luaU_push (lua_State* L, const char& value) {                          lua_pushinteger  (L, value); } | ||||
| }; | ||||
|  | ||||
| template<> | ||||
| struct luaU_Impl<float> | ||||
| { | ||||
|     static float luaU_check(lua_State* L, int          index) { return static_cast<float>(luaL_checknumber(L, index)); } | ||||
|     static float luaU_to   (lua_State* L, int          index) { return static_cast<float>(lua_tonumber    (L, index)); } | ||||
|     static void  luaU_push (lua_State* L, const float& value) {                           lua_pushnumber  (L, value); } | ||||
| }; | ||||
|  | ||||
| template<> | ||||
| struct luaU_Impl<double> | ||||
| { | ||||
|     static double luaU_check(lua_State* L, int           index) { return static_cast<double>(luaL_checknumber(L, index)); } | ||||
|     static double luaU_to   (lua_State* L, int           index) { return static_cast<double>(lua_tonumber    (L, index)); } | ||||
|     static void   luaU_push (lua_State* L, const double& value) {                            lua_pushnumber  (L, value); } | ||||
| }; | ||||
|  | ||||
| #ifndef LUAW_NO_CXX11 | ||||
| template<typename T> | ||||
| struct luaU_Impl<T, typename LUAW_STD::enable_if<LUAW_STD::is_enum<T>::value>::type> | ||||
| { | ||||
|     static T    luaU_check(lua_State* L, int      index) { return static_cast<T>(luaL_checkinteger  (L, index)); } | ||||
|     static T    luaU_to   (lua_State* L, int      index) { return static_cast<T>(lua_tointeger      (L, index)); } | ||||
|     static void luaU_push (lua_State* L, const T& value) {        lua_pushnumber(L, static_cast<int>(value   )); } | ||||
| }; | ||||
|  | ||||
| template<typename T> | ||||
| struct luaU_Impl<T*, typename LUAW_STD::enable_if<LUAW_STD::is_class<T>::value>::type> | ||||
| { | ||||
|     static T*   luaU_check( lua_State* L, int index) { return luaW_check<T>(L, index); } | ||||
|     static T*   luaU_to   ( lua_State* L, int index) { return luaW_to   <T>(L, index); } | ||||
|     static void luaU_push ( lua_State* L, T*& value) {        luaW_push <T>(L, value); } | ||||
|     static void luaU_push ( lua_State* L, T*  value) {        luaW_push <T>(L, value); } | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
| // | ||||
| // These are just some functions I've always felt should exist | ||||
| // | ||||
|  | ||||
| template <typename U> | ||||
| inline U luaU_getfield(lua_State* L, int index, const char* field) | ||||
| { | ||||
| #ifndef LUAW_NO_CXX11 | ||||
|     static_assert(!std::is_same<U, const char*>::value,  | ||||
|         "luaU_getfield is not safe to use on const char*'s. (The string will be popped from the stack.)"); | ||||
| #endif | ||||
|     lua_getfield(L, index, field); | ||||
|     U val = luaU_to<U>(L, -1); | ||||
|     lua_pop(L, 1); | ||||
|     return val; | ||||
| } | ||||
|  | ||||
| template <typename U> | ||||
| inline U luaU_checkfield(lua_State* L, int index, const char* field) | ||||
| { | ||||
| #ifndef LUAW_NO_CXX11 | ||||
|     static_assert(!std::is_same<U, const char*>::value,  | ||||
|         "luaU_checkfield is not safe to use on const char*'s. (The string will be popped from the stack.)"); | ||||
| #endif | ||||
|     lua_getfield(L, index, field); | ||||
|     U val = luaU_check<U>(L, -1); | ||||
|     lua_pop(L, 1); | ||||
|     return val; | ||||
| } | ||||
|  | ||||
| template <typename U> | ||||
| inline void luaU_setfield(lua_State* L, int index, const char* field, U val) | ||||
| { | ||||
|     luaU_push<U>(L, val); | ||||
|     lua_setfield(L, luaW_correctindex(L, index, 1), field); | ||||
| } | ||||
|  | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
| // | ||||
| // A set of trivial getter and setter templates. These templates are designed | ||||
| // to call trivial getters or setters. | ||||
| // | ||||
| // There are four forms: | ||||
| //  1. Getting or setting a public member variable that is of a primitive type | ||||
| //  2. Getting or setting a public member variable that is a pointer to an | ||||
| //     object | ||||
| //  3. Getting or setting a private member variable that is of a primitive type | ||||
| //     through a getter or setter | ||||
| //  3. Getting or setting a private member variable that is is a pointer to an | ||||
| //     object through a getter or setter | ||||
| // | ||||
| // The interface to all of them is the same however. In addition to plain | ||||
| // getter and setter functions, there is a getset which does both - if an | ||||
| // argument is supplied it attempts to set the value, and in either case it | ||||
| // returns the value. In your lua table declaration in C++ rather than write | ||||
| // individiual wrappers for each getter and setter you may do the following: | ||||
| // | ||||
| // static luaL_reg Foo_metatable[] = | ||||
| // { | ||||
| //     { "GetBar", luaU_get<Foo, bool, &Widget::GetBar> }, | ||||
| //     { "SetBar", luaU_set<Foo, bool, &Widget::SetBar> }, | ||||
| //     { "Bar", luaU_getset<Foo, bool, &Widget::GetBar, &Widget::SetBar> }, | ||||
| //     { NULL, NULL } | ||||
| // } | ||||
| // | ||||
| // Getters and setters must have one of the following signatures: | ||||
| //    void T::Setter(U value); | ||||
| //    void T::Setter(U* value); | ||||
| //    void T::Setter(const U& value); | ||||
| //    U Getter() const; | ||||
| //    U* Getter() const; | ||||
| // | ||||
| // In this example, the variable Foo::bar is private and so it is accessed | ||||
| // through getter and setter functions. If Foo::bar were public, it could be | ||||
| // accessed directly, like so: | ||||
| // | ||||
| // static luaL_reg Foo_metatable[] = | ||||
| // { | ||||
| //     { "GetBar", luaU_get<Foo, bool, &Widget::bar> }, | ||||
| //     { "SetBar", luaU_set<Foo, bool, &Widget::bar> }, | ||||
| //     { "Bar", luaU_getset<Foo, bool, &Widget::bar> }, | ||||
| // } | ||||
| // | ||||
| // In a Lua script, you can now use foo:GetBar(), foo:SetBar() and foo:Bar() | ||||
| // | ||||
|  | ||||
| template <typename T, typename U, U T::*Member> | ||||
| int luaU_get(lua_State* L) | ||||
| { | ||||
|     T* obj = luaW_check<T>(L, 1); | ||||
|     luaU_push<U>(L, obj->*Member); | ||||
|     return 1; | ||||
| } | ||||
|  | ||||
| template <typename T, typename U, U* T::*Member> | ||||
| int luaU_get(lua_State* L) | ||||
| { | ||||
|     T* obj = luaW_check<T>(L, 1); | ||||
|     luaW_push<U>(L, obj->*Member); | ||||
|     return 1; | ||||
| } | ||||
|  | ||||
| template <typename T, typename U, U (T::*Getter)() const> | ||||
| int luaU_get(lua_State* L) | ||||
| { | ||||
|     T* obj = luaW_check<T>(L, 1); | ||||
|     luaU_push<U>(L, (obj->*Getter)()); | ||||
|     return 1; | ||||
| } | ||||
|  | ||||
| template <typename T, typename U, const U& (T::*Getter)() const> | ||||
| int luaU_get(lua_State* L) | ||||
| { | ||||
|     T* obj = luaW_check<T>(L, 1); | ||||
|     luaU_push<U>(L, (obj->*Getter)()); | ||||
|     return 1; | ||||
| } | ||||
|  | ||||
| template <typename T, typename U, U* (T::*Getter)() const> | ||||
| int luaU_get(lua_State* L) | ||||
| { | ||||
|     T* obj = luaW_check<T>(L, 1); | ||||
|     luaW_push<U>(L, (obj->*Getter)()); | ||||
|     return 1; | ||||
| } | ||||
|  | ||||
| template <typename T, typename U, U T::*Member> | ||||
| int luaU_set(lua_State* L) | ||||
| { | ||||
|     T* obj = luaW_check<T>(L, 1); | ||||
|     if (obj) | ||||
|         obj->*Member = luaU_check<U>(L, 2); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| template <typename T, typename U, U* T::*Member> | ||||
| int luaU_set(lua_State* L) | ||||
| { | ||||
|     T* obj = luaW_check<T>(L, 1); | ||||
|     if (obj) | ||||
|     { | ||||
|         U* member = luaW_opt<U>(L, 2); | ||||
|         obj->*Member = member; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| template <typename T, typename U, const U* T::*Member> | ||||
| int luaU_set(lua_State* L) | ||||
| { | ||||
|     T* obj = luaW_check<T>(L, 1); | ||||
|     if (obj) | ||||
|     { | ||||
|         U* member = luaW_opt<U>(L, 2); | ||||
|         obj->*Member = member; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| template <typename T, typename U, const U* T::*Member> | ||||
| int luaU_setandrelease(lua_State* L) | ||||
| { | ||||
|     T* obj = luaW_check<T>(L, 1); | ||||
|     if (obj) | ||||
|     { | ||||
|         U* member = luaW_opt<U>(L, 2); | ||||
|         obj->*Member = member; | ||||
|         if (member) | ||||
|             luaW_release<U>(L, member); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| template <typename T, typename U, void (T::*Setter)(U)> | ||||
| int luaU_set(lua_State* L) | ||||
| { | ||||
|     T* obj = luaW_check<T>(L, 1); | ||||
|     if (obj) | ||||
|         (obj->*Setter)(luaU_check<U>(L, 2)); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| template <typename T, typename U, void (T::*Setter)(const U&)> | ||||
| int luaU_set(lua_State* L) | ||||
| { | ||||
|     T* obj = luaW_check<T>(L, 1); | ||||
|     if (obj) | ||||
|         (obj->*Setter)(luaU_check<U>(L, 2)); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| template <typename T, typename U, void (T::*Setter)(U*)> | ||||
| int luaU_set(lua_State* L) | ||||
| { | ||||
|     T* obj = luaW_check<T>(L, 1); | ||||
|     if (obj) | ||||
|     { | ||||
|         U* member = luaW_opt<U>(L, 2); | ||||
|         (obj->*Setter)(member); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| template <typename T, typename U, void (T::*Setter)(U*)> | ||||
| int luaU_setandrelease(lua_State* L) | ||||
| { | ||||
|     T* obj = luaW_check<T>(L, 1); | ||||
|     if (obj) | ||||
|     { | ||||
|         U* member = luaW_opt<U>(L, 2); | ||||
|         (obj->*Setter)(member); | ||||
|         if (member) | ||||
|             luaW_release<U>(L, member); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| template <typename T, typename U, U T::*Member> | ||||
| int luaU_getset(lua_State* L) | ||||
| { | ||||
|     T* obj = luaW_check<T>(L, 1); | ||||
|     if (obj && lua_gettop(L) >= 2) | ||||
|     { | ||||
|         obj->*Member = luaU_check<U>(L, 2); | ||||
|         return 0; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         luaU_push<U>(L, obj->*Member); | ||||
|         return 1; | ||||
|     } | ||||
| } | ||||
|  | ||||
| template <typename T, typename U, U* T::*Member> | ||||
| int luaU_getset(lua_State* L) | ||||
| { | ||||
|     T* obj = luaW_check<T>(L, 1); | ||||
|     if (obj && lua_gettop(L) >= 2) | ||||
|     { | ||||
|         U* member = luaW_opt<U>(L, 2); | ||||
|         obj->*Member = member; | ||||
|         return 0; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         luaW_push<U>(L, obj->*Member); | ||||
|         return 1; | ||||
|     } | ||||
| } | ||||
|  | ||||
| template <typename T, typename U, U* T::*Member> | ||||
| int luaU_getsetandrelease(lua_State* L) | ||||
| { | ||||
|     T* obj = luaW_check<T>(L, 1); | ||||
|     if (obj && lua_gettop(L) >= 2) | ||||
|     { | ||||
|         U* member = luaW_opt<U>(L, 2); | ||||
|         obj->*Member = member; | ||||
|         if (member) | ||||
|             luaW_release<U>(L, member); | ||||
|         return 0; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         luaW_push<U>(L, obj->*Member); | ||||
|         return 1; | ||||
|     } | ||||
| } | ||||
|  | ||||
| template <typename T, typename U, U (T::*Getter)() const, void (T::*Setter)(U)> | ||||
| int luaU_getset(lua_State* L) | ||||
| { | ||||
|     T* obj = luaW_check<T>(L, 1); | ||||
|     if (obj && lua_gettop(L) >= 2) | ||||
|     { | ||||
|         (obj->*Setter)(luaU_check<U>(L, 2)); | ||||
|         return 0; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         luaU_push<U>(L, (obj->*Getter)()); | ||||
|         return 1; | ||||
|     } | ||||
| } | ||||
|  | ||||
| template <typename T, typename U, U (T::*Getter)() const, void (T::*Setter)(const U&)> | ||||
| int luaU_getset(lua_State* L) | ||||
| { | ||||
|     T* obj = luaW_check<T>(L, 1); | ||||
|     if (obj && lua_gettop(L) >= 2) | ||||
|     { | ||||
|         (obj->*Setter)(luaU_check<U>(L, 2)); | ||||
|         return 0; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         luaU_push<U>(L, (obj->*Getter)()); | ||||
|         return 1; | ||||
|     } | ||||
| } | ||||
|  | ||||
| template <typename T, typename U, const U& (T::*Getter)() const, void (T::*Setter)(const U&)> | ||||
| int luaU_getset(lua_State* L) | ||||
| { | ||||
|     T* obj = luaW_check<T>(L, 1); | ||||
|     if (obj && lua_gettop(L) >= 2) | ||||
|     { | ||||
|         (obj->*Setter)(luaU_check<U>(L, 2)); | ||||
|         return 0; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         luaU_push<U>(L, (obj->*Getter)()); | ||||
|         return 1; | ||||
|     } | ||||
| } | ||||
|  | ||||
| template <typename T, typename U, U* (T::*Getter)() const, void (T::*Setter)(U*)> | ||||
| int luaU_getset(lua_State* L) | ||||
| { | ||||
|     T* obj = luaW_check<T>(L, 1); | ||||
|     if (obj && lua_gettop(L) >= 2) | ||||
|     { | ||||
|         U* member = luaW_opt<U>(L, 2); | ||||
|         (obj->*Setter)(member); | ||||
|         return 0; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         luaW_push<U>(L, (obj->*Getter)()); | ||||
|         return 1; | ||||
|     } | ||||
| } | ||||
|  | ||||
| template <typename T, typename U, U* (T::*Getter)() const, void (T::*Setter)(U*)> | ||||
| int luaU_getsetandrelease(lua_State* L) | ||||
| { | ||||
|     T* obj = luaW_check<T>(L, 1); | ||||
|     if (obj && lua_gettop(L) >= 2) | ||||
|     { | ||||
|         U* member = luaW_opt<U>(L, 2); | ||||
|         (obj->*Setter)(member); | ||||
|         if (member) | ||||
|             luaW_release<U>(L, member); | ||||
|         return 0; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         luaW_push<U>(L, (obj->*Getter)()); | ||||
|         return 1; | ||||
|     } | ||||
| } | ||||
|  | ||||
| #if !defined(_WIN32) && !defined(LUAW_NO_CXX11) | ||||
|  | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
| // | ||||
| // luaU_func is a special macro that expands into a simple function wrapper. | ||||
| // Unlike the getter setters above, you merely need to name the function you | ||||
| // would like to wrap. | ||||
| // | ||||
| // For example, | ||||
| // | ||||
| // struct Foo | ||||
| // { | ||||
| //     int DoSomething(int, const char*); | ||||
| // }; | ||||
| // | ||||
| // static luaL_reg Foo_metatable[] = | ||||
| // { | ||||
| //     { "DoSomething", luaU_func(&Foo::DoSomething) }, | ||||
| //     { NULL, NULL } | ||||
| // } | ||||
| // | ||||
| // This macro will expand based on the function signature of Foo::DoSomething | ||||
| // In this example, it would expand into the following wrapper: | ||||
| // | ||||
| //     luaU_push(luaW_check<T>(L, 1)->DoSomething(luaU_check<int>(L, 2), luaU_check<const char*>(L, 3))); | ||||
| //     return 1; | ||||
| // | ||||
| // In this example there is only one member function called DoSomething. In some  | ||||
| // cases there may be multiple overrides for a function. For those cases, an  | ||||
| // additional macro has been provided, luaU_funcsig, which takes the entire | ||||
| // function signature. The arguments to the macro reflect the order they would | ||||
| // appear in the function signature: return type, type name, function name, and | ||||
| // finally a list of all the argument types. For example: | ||||
| // | ||||
| // struct Foo | ||||
| // { | ||||
| //     int DoSomething (const char*); | ||||
| //     int DoSomething (const char*, int); | ||||
| // }; | ||||
| // | ||||
| // const struct luaL_Reg Foo_metatable[] = | ||||
| // { | ||||
| //     {"DoSomething1", luaU_funcsig(int, Foo, DoSomething, const char*)) }, | ||||
| //     {"DoSomething1", luaU_funcsig(int, Foo, DoSomething, const char*, int)) }, | ||||
| //     { NULL, NULL } | ||||
| // }; | ||||
| // | ||||
| // These macros and it's underlying templates are somewhat experimental and some | ||||
| // refinements are probably needed.  There are cases where it does not | ||||
| // currently work and I expect some changes can be made to refine its behavior. | ||||
| // | ||||
|  | ||||
| #define luaU_func(memberfunc) &luaU_FuncWrapper<decltype(memberfunc),memberfunc>::call | ||||
| #define luaU_funcsig(returntype, type, funcname, ...) luaU_func(static_cast<returntype (type::*)(__VA_ARGS__)>(&type::funcname)) | ||||
|  | ||||
| template<int... ints> struct luaU_IntPack { }; | ||||
| template<int start, int count, int... tail> struct luaU_MakeIntRangeType { typedef typename luaU_MakeIntRangeType<start, count-1, start+count-1, tail...>::type type; }; | ||||
| template<int start, int... tail> struct luaU_MakeIntRangeType<start, 0, tail...> { typedef luaU_IntPack<tail...> type; }; | ||||
| template<int start, int count> inline typename luaU_MakeIntRangeType<start, count>::type luaU_makeIntRange() { return typename luaU_MakeIntRangeType<start, count>::type(); } | ||||
| template<class MemFunPtrType, MemFunPtrType MemberFunc> struct luaU_FuncWrapper; | ||||
|  | ||||
| template<class T, class ReturnType, class... Args, ReturnType(T::*MemberFunc)(Args...)> | ||||
| struct luaU_FuncWrapper<ReturnType (T::*)(Args...), MemberFunc> | ||||
| { | ||||
| public: | ||||
|     static int call(lua_State* L) | ||||
|     { | ||||
|         return callImpl(L, luaU_makeIntRange<2,sizeof...(Args)>()); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     template<int... indices> | ||||
|     static int callImpl(lua_State* L, luaU_IntPack<indices...>) | ||||
|     { | ||||
|         luaU_push<ReturnType>(L, (luaW_check<T>(L, 1)->*MemberFunc)(luaU_check<Args>(L, indices)...)); | ||||
|         return 1; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| #endif | ||||
|  | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
| // | ||||
| // Calls the copy constructor for an object of type T. | ||||
| // Arguments may be passed in, in case they're needed for the postconstructor | ||||
| // | ||||
| // e.g. | ||||
| // | ||||
| // C++: | ||||
| // luaL_reg Foo_Metatable[] = | ||||
| // { | ||||
| //     { "clone", luaU_clone<Foo> }, | ||||
| //     { NULL, NULL } | ||||
| // }; | ||||
| // | ||||
| // Lua: | ||||
| // foo = Foo.new() | ||||
| // foo2 = foo:clone() | ||||
| // | ||||
| template <typename T> | ||||
| int luaU_clone(lua_State* L) | ||||
| { | ||||
|     // obj ... | ||||
|     T* obj = new T(*luaW_check<T>(L, 1)); | ||||
|     lua_remove(L, 1); // ... | ||||
|     int numargs = lua_gettop(L); | ||||
|     luaW_push<T>(L, obj); // ... clone | ||||
|     luaW_hold<T>(L, obj); | ||||
|     luaW_postconstructor<T>(L, numargs); | ||||
|     return 1; | ||||
| } | ||||
|  | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
| // | ||||
| // luaU_build is intended to be used to initialize many values by passing in a | ||||
| // table. They keys of the table are used as function names, and values are | ||||
| // used as arguments to the function. This is intended to be used on functions | ||||
| // that are simple setters. | ||||
| // | ||||
| // For example, if luaU_build is set as the post constructor, you can | ||||
| // initialize an object as so: | ||||
| // | ||||
| // f = Foo.new | ||||
| // { | ||||
| //     X = 10; | ||||
| //     Y = 20; | ||||
| // } | ||||
| // | ||||
| // After the object is constructed, luaU_build will do the equivalent of | ||||
| // calling f:X(10) and f:Y(20). | ||||
| // | ||||
| template <typename T> | ||||
| int luaU_build(lua_State* L) | ||||
| { | ||||
|     // obj {} | ||||
|     lua_insert(L, -2); // {} obj | ||||
|     if (lua_type(L, 1) == LUA_TTABLE) | ||||
|     { | ||||
|         for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) | ||||
|         { | ||||
|             // {} obj k v | ||||
|             lua_pushvalue(L, -2); // {} obj k v k | ||||
|             lua_gettable(L, -4); // {} obj k v ud[k] | ||||
|             lua_pushvalue(L, -4); // {} obj k v ud[k] ud | ||||
|             lua_pushvalue(L, -3); // {} obj k v ud[k] ud v | ||||
|             lua_call(L, 2, 0); // {} obj k v | ||||
|         } | ||||
|         // {} ud | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
| // | ||||
| // Takes the object of type T at the top of the stack and stores it in on a | ||||
| // table with the name storagetable, on the table at the specified index. | ||||
| // | ||||
| // You may manually call luaW_hold and luaW_release to handle pointer | ||||
| // ownership, but it is often easier to simply store a Lua userdata on a table | ||||
| // that is owned by its parent. This ensures that your object will not be | ||||
| // prematurely freed, and that it can only be destoryed after its parent. | ||||
| // | ||||
| // e.g. | ||||
| // | ||||
| // Foo* parent = luaW_check<Foo>(L, 1); | ||||
| // Bar* child = luaW_check<Bar>(L, 2); | ||||
| // if (parent && child) | ||||
| // { | ||||
| //     luaU_store<Bar>(L, 1, "Children"); | ||||
| //     parent->AddChild(child); | ||||
| // } | ||||
| // | ||||
| template <typename T> | ||||
| void luaU_store(lua_State* L, int index, const char* storagetable, const char* key = NULL) | ||||
| { | ||||
|     // ... store ... obj | ||||
|     lua_getfield(L, index, storagetable); // ... store ... obj store.storagetable | ||||
|     if (key) | ||||
|         lua_pushstring(L, key); // ... store ... obj store.storagetable key | ||||
|     else | ||||
|         LuaWrapper<T>::identifier(L, luaW_to<T>(L, -2)); // ... store ... obj store.storagetable key | ||||
|     lua_pushvalue(L, -3); // ... store ... obj store.storagetable key obj | ||||
|     lua_settable(L, -3); // ... store ... obj store.storagetable | ||||
|     lua_pop(L, 1); // ... store ... obj | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Copyright (c) 2010-2011 Alexander Ames | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to | ||||
|  * deal in the Software without restriction, including without limitation the | ||||
|  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
|  * sell copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
|  * FROM OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
|  * IN THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| #endif // LUAWRAPPERUTILS_HPP_ | ||||
							
								
								
									
										64
									
								
								luarocks/main.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								luarocks/main.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| /* | ||||
|  *  main.cpp | ||||
|  *  Author: Benjamin Sergeant | ||||
|  *  Copyright (c) 2020 Machine Zone, Inc. All rights reserved. | ||||
|  */ | ||||
|  | ||||
| #include <iostream> | ||||
|  | ||||
| extern "C" | ||||
| { | ||||
|     #include "lua.h" | ||||
|     #include "lualib.h" | ||||
|     #include "lauxlib.h" | ||||
| } | ||||
|  | ||||
| #include "functions.hpp" | ||||
| #include "LuaWebSocket.h" | ||||
| #include <iostream> | ||||
|  | ||||
| int main() | ||||
| { | ||||
|     lua_State* L = luaL_newstate(); | ||||
|     luaL_openlibs(L); | ||||
|  | ||||
|     // Functions | ||||
|     lua_register(L, "info", lua_info); | ||||
|  | ||||
|     // Objets | ||||
|     ix::luaopen_WebSocket(L); | ||||
|  | ||||
|     // | ||||
|     // Simple version does little error handling | ||||
|     // luaL_dofile(L, "echo_client.lua"); | ||||
|     // | ||||
|     std::string luaFile("echo_client.lua"); | ||||
|     int loadStatus = luaL_loadfile(L, luaFile.c_str()); | ||||
|     if (loadStatus) | ||||
|     { | ||||
|         std::cerr << "Error loading " << luaFile << std::endl; | ||||
|         std::cerr << lua_tostring(L, -1) << std::endl; | ||||
|         return 1; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         std::cout << "loaded " << luaFile << std::endl; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // Capture lua errors | ||||
|     // | ||||
|     try | ||||
|     { | ||||
|         lua_call(L, 0, 0); | ||||
|         lua_close(L); | ||||
|     } | ||||
|     catch (const std::runtime_error& ex) | ||||
|     { | ||||
|         lua_close(L); | ||||
|         std::cerr << ex.what() << std::endl; | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										4
									
								
								makefile
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								makefile
									
									
									
									
									
								
							| @@ -159,6 +159,9 @@ test_no_ssl: | ||||
| 	mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_TEST=1 .. ; make -j 4) | ||||
| 	(cd test ; python2.7 run.py -r) | ||||
|  | ||||
| luarocks: | ||||
| 	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DUSE_LUAROCKS=1 .. ; ninja) | ||||
|  | ||||
| ws_test: ws | ||||
| 	(cd ws ; env DEBUG=1 PATH=../ws/build:$$PATH bash test_ws.sh) | ||||
|  | ||||
| @@ -185,3 +188,4 @@ doc: | ||||
| .PHONY: test | ||||
| .PHONY: build | ||||
| .PHONY: ws | ||||
| .PHONY: luarocks | ||||
|   | ||||
		Reference in New Issue
	
	Block a user