add lua user types + bytearray
This commit is contained in:
parent
0338fe542b
commit
490727fdc0
86
src/logic/scripting/lua/lua_custom_types.cpp
Normal file
86
src/logic/scripting/lua/lua_custom_types.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
#include "lua_custom_types.hpp"
|
||||
|
||||
#include "lua_util.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using namespace lua;
|
||||
|
||||
|
||||
Bytearray::Bytearray(size_t capacity)
|
||||
: buffer(std::make_unique<ubyte[]>(capacity)), capacity(capacity) {
|
||||
}
|
||||
|
||||
Bytearray::~Bytearray() {
|
||||
}
|
||||
|
||||
static int l_bytearray_meta_meta_call(lua::State* L) {
|
||||
auto size = tointeger(L, 2);
|
||||
if (size < 0) {
|
||||
throw std::runtime_error("size can not be less than 0");
|
||||
}
|
||||
return newuserdata<Bytearray>(L, static_cast<size_t>(size));
|
||||
}
|
||||
|
||||
static int l_bytearray_meta_index(lua::State* L) {
|
||||
auto buffer = touserdata<Bytearray>(L, 1);
|
||||
auto index = tointeger(L, 2)-1;
|
||||
if (buffer == nullptr || static_cast<size_t>(index) > buffer->size()) {
|
||||
return 0;
|
||||
}
|
||||
return pushinteger(L, (*buffer)[index]);
|
||||
}
|
||||
|
||||
static int l_bytearray_meta_newindex(lua::State* L) {
|
||||
auto buffer = touserdata<Bytearray>(L, 1);
|
||||
auto index = tointeger(L, 2)-1;
|
||||
if (buffer == nullptr || static_cast<size_t>(index) > buffer->size()) {
|
||||
return 0;
|
||||
}
|
||||
auto value = tointeger(L, 3);
|
||||
(*buffer)[index] = static_cast<ubyte>(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_bytearray_meta_len(lua::State* L) {
|
||||
if (auto buffer = touserdata<Bytearray>(L, 1)) {
|
||||
return pushinteger(L, buffer->size());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_bytearray_meta_tostring(lua::State* L) {
|
||||
auto& buffer = *touserdata<Bytearray>(L, 1);
|
||||
if (buffer.size() > 128) {
|
||||
return pushstring(L, "bytearray["+std::to_string(buffer.size())+"]{...}");
|
||||
} else {
|
||||
std::stringstream ss;
|
||||
ss << "bytearray[" << std::to_string(buffer.size()) << "]{";
|
||||
for (size_t i = 0; i < buffer.size(); i++) {
|
||||
if (i > 0) {
|
||||
ss << " ";
|
||||
}
|
||||
ss << static_cast<uint>(buffer[i]);
|
||||
}
|
||||
ss << "}";
|
||||
return pushstring(L, ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
int Bytearray::createMetatable(lua::State* L) {
|
||||
createtable(L, 0, 5);
|
||||
pushcfunction(L, lua::wrap<l_bytearray_meta_index>);
|
||||
setfield(L, "__index");
|
||||
pushcfunction(L, lua::wrap<l_bytearray_meta_newindex>);
|
||||
setfield(L, "__newindex");
|
||||
pushcfunction(L, lua::wrap<l_bytearray_meta_len>);
|
||||
setfield(L, "__len");
|
||||
pushcfunction(L, lua::wrap<l_bytearray_meta_tostring>);
|
||||
setfield(L, "__tostring");
|
||||
|
||||
createtable(L, 0, 1);
|
||||
pushcfunction(L, lua::wrap<l_bytearray_meta_meta_call>);
|
||||
setfield(L, "__call");
|
||||
setmetatable(L);
|
||||
return 1;
|
||||
}
|
||||
39
src/logic/scripting/lua/lua_custom_types.hpp
Normal file
39
src/logic/scripting/lua/lua_custom_types.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef LOGIC_SCRIPTING_LUA_LUA_CUSTOM_TYPES_HPP_
|
||||
#define LOGIC_SCRIPTING_LUA_LUA_CUSTOM_TYPES_HPP_
|
||||
|
||||
#include "lua_commons.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace lua {
|
||||
class Userdata {
|
||||
public:
|
||||
virtual ~Userdata() {};
|
||||
virtual const std::string& getTypeName() const = 0;
|
||||
};
|
||||
|
||||
class Bytearray : public Userdata {
|
||||
std::unique_ptr<ubyte[]> buffer;
|
||||
size_t capacity;
|
||||
public:
|
||||
Bytearray(size_t capacity);
|
||||
virtual ~Bytearray();
|
||||
|
||||
inline ubyte& operator[](size_t index) {
|
||||
return buffer[index];
|
||||
}
|
||||
|
||||
const std::string& getTypeName() const override {
|
||||
return TYPENAME;
|
||||
}
|
||||
|
||||
inline size_t size() const {
|
||||
return capacity;
|
||||
}
|
||||
static int createMetatable(lua::State*);
|
||||
inline static std::string TYPENAME = "bytearray";
|
||||
};
|
||||
}
|
||||
|
||||
#endif // LOGIC_SCRIPTING_LUA_LUA_CUSTOM_TYPES_HPP_
|
||||
@ -1,6 +1,7 @@
|
||||
#include "lua_engine.hpp"
|
||||
|
||||
#include "api_lua.hpp"
|
||||
#include "lua_custom_types.hpp"
|
||||
#include "../../../debug/Logger.hpp"
|
||||
#include "../../../util/stringutil.hpp"
|
||||
|
||||
@ -45,7 +46,6 @@ static void create_libs(lua::State* L) {
|
||||
addfunc(L, "print", lua::wrap<l_print>);
|
||||
}
|
||||
|
||||
#include <iostream>
|
||||
void lua::initialize() {
|
||||
logger.info() << LUA_VERSION;
|
||||
logger.info() << LUAJIT_VERSION;
|
||||
@ -81,6 +81,8 @@ void lua::initialize() {
|
||||
|
||||
createtable(L, 0, 0);
|
||||
setglobal(L, LAMBDAS_TABLE);
|
||||
|
||||
newusertype<Bytearray, Bytearray::createMetatable>(L, "bytearray");
|
||||
}
|
||||
|
||||
void lua::finalize() {
|
||||
|
||||
@ -9,6 +9,15 @@ using namespace lua;
|
||||
|
||||
static int nextEnvironment = 1;
|
||||
|
||||
std::unordered_map<std::type_index, std::string> lua::usertypeNames;
|
||||
|
||||
int lua::userdata_destructor(lua::State* L) {
|
||||
if (auto obj = touserdata<Userdata>(L, 1)) {
|
||||
obj->~Userdata();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string lua::env_name(int env) {
|
||||
return "_ENV"+util::mangleid(env);
|
||||
}
|
||||
|
||||
@ -2,9 +2,16 @@
|
||||
#define LOGIC_SCRIPTING_LUA_UTIL_HPP_
|
||||
|
||||
#include "lua_commons.hpp"
|
||||
#include "lua_custom_types.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <typeindex>
|
||||
#include <typeinfo>
|
||||
|
||||
namespace lua {
|
||||
inline std::string LAMBDAS_TABLE = "$L";
|
||||
extern std::unordered_map<std::type_index, std::string> usertypeNames;
|
||||
int userdata_destructor(lua::State* L);
|
||||
|
||||
std::string env_name(int env);
|
||||
|
||||
@ -230,6 +237,12 @@ namespace lua {
|
||||
inline bool isfunction(lua::State* L, int idx) {
|
||||
return lua_isfunction(L, idx);
|
||||
}
|
||||
inline bool isuserdata(lua::State* L, int idx) {
|
||||
return lua_isuserdata(L, idx);
|
||||
}
|
||||
inline void setfield(lua::State* L, const std::string& name, int idx=-2) {
|
||||
lua_setfield(L, idx, name.c_str());
|
||||
}
|
||||
inline bool toboolean(lua::State* L, int idx) {
|
||||
return lua_toboolean(L, idx);
|
||||
}
|
||||
@ -245,7 +258,42 @@ namespace lua {
|
||||
inline const void* topointer(lua::State* L, int idx) {
|
||||
return lua_topointer(L, idx);
|
||||
}
|
||||
inline glm::vec2 tovec2(lua::State* L, int idx) {
|
||||
inline void setglobal(lua::State* L, const std::string& name) {
|
||||
lua_setglobal(L, name.c_str());
|
||||
}
|
||||
template<class T>
|
||||
inline T* touserdata(lua::State* L, int idx) {
|
||||
if (void* rawptr = lua_touserdata(L, idx)) {
|
||||
return static_cast<T*>(rawptr);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
template<class T, typename... Args>
|
||||
inline int newuserdata(lua::State* L, Args&&... args) {
|
||||
const auto& found = usertypeNames.find(typeid(T));
|
||||
void* ptr = lua_newuserdata(L, sizeof(T));
|
||||
new (ptr) T(args...);
|
||||
|
||||
if (found == usertypeNames.end()) {
|
||||
log_error("usertype is not registred: "+std::string(typeid(T).name()));
|
||||
} else if (getglobal(L, found->second)) {
|
||||
setmetatable(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<class T, lua_CFunction func>
|
||||
inline void newusertype(lua::State* L, const std::string& name) {
|
||||
usertypeNames[typeid(T)] = name;
|
||||
func(L);
|
||||
|
||||
pushcfunction(L, userdata_destructor);
|
||||
setfield(L, "__gc");
|
||||
|
||||
setglobal(L, name);
|
||||
}
|
||||
|
||||
inline glm::vec2 tovec2(lua::State* L, int idx) {
|
||||
pushvalue(L, idx);
|
||||
if (!istable(L, idx) || objlen(L, idx) < 2) {
|
||||
throw std::runtime_error("value must be an array of two numbers");
|
||||
@ -287,14 +335,6 @@ namespace lua {
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void setfield(lua::State* L, const std::string& name, int idx=-2) {
|
||||
lua_setfield(L, idx, name.c_str());
|
||||
}
|
||||
|
||||
inline void setglobal(lua::State* L, const std::string& name) {
|
||||
lua_setglobal(L, name.c_str());
|
||||
}
|
||||
|
||||
inline const char* require_string(lua::State* L, int idx) {
|
||||
if (!isstring(L, idx)) {
|
||||
throw luaerror("string expected at "+std::to_string(idx));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user