Compare commits
	
		
			8 Commits
		
	
	
		
			v9.6.4
			...
			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