Compare commits
8 Commits
master
...
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
|
||||
|
Loading…
Reference in New Issue
Block a user