2013-12-20 02:02:12 +02:00
|
|
|
#ifndef _library__lua_base__hpp__included__
|
|
|
|
#define _library__lua_base__hpp__included__
|
2012-10-16 17:39:55 +03:00
|
|
|
|
|
|
|
#include <string>
|
|
|
|
#include <stdexcept>
|
2013-12-19 23:24:08 +02:00
|
|
|
#include <typeinfo>
|
|
|
|
#include <typeindex>
|
2012-10-16 17:39:55 +03:00
|
|
|
#include <map>
|
2013-12-19 23:24:08 +02:00
|
|
|
#include <unordered_map>
|
2013-08-07 17:31:09 +03:00
|
|
|
#include <set>
|
2013-08-06 16:17:01 +03:00
|
|
|
#include <list>
|
2012-10-16 17:39:55 +03:00
|
|
|
#include <cassert>
|
2012-11-13 22:01:12 +02:00
|
|
|
#include "string.hpp"
|
2013-05-01 18:06:24 +03:00
|
|
|
#include "utf8.hpp"
|
2012-10-16 17:39:55 +03:00
|
|
|
extern "C"
|
|
|
|
{
|
|
|
|
#include <lua.h>
|
|
|
|
}
|
|
|
|
|
2013-12-20 02:02:12 +02:00
|
|
|
namespace lua
|
|
|
|
{
|
|
|
|
class state;
|
2013-09-27 04:43:44 +03:00
|
|
|
|
2013-12-20 02:02:12 +02:00
|
|
|
struct class_ops
|
2013-09-27 10:47:19 +03:00
|
|
|
{
|
2013-12-20 02:02:12 +02:00
|
|
|
bool (*is)(state& _state, int index);
|
2013-09-27 10:47:19 +03:00
|
|
|
const std::string& (*name)();
|
2013-12-20 02:02:12 +02:00
|
|
|
std::string (*print)(state& _state, int index);
|
2013-09-27 10:47:19 +03:00
|
|
|
};
|
|
|
|
|
2013-12-20 02:02:12 +02:00
|
|
|
std::list<class_ops>& userdata_recogn_fns();
|
|
|
|
std::string try_recognize_userdata(state& _state, int index);
|
|
|
|
std::string try_print_userdata(state& _state, int index);
|
2013-09-27 04:43:44 +03:00
|
|
|
|
2013-12-20 02:02:12 +02:00
|
|
|
struct function;
|
2012-10-16 17:39:55 +03:00
|
|
|
|
2013-12-20 02:02:12 +02:00
|
|
|
std::unordered_map<std::type_index, void*>& class_types();
|
2013-12-19 23:24:08 +02:00
|
|
|
|
2013-08-07 17:31:09 +03:00
|
|
|
/**
|
|
|
|
* Group of functions.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
class function_group
|
2013-08-07 17:31:09 +03:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Create a group.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
function_group();
|
2013-08-07 17:31:09 +03:00
|
|
|
/**
|
|
|
|
* Destroy a group.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
~function_group();
|
2013-08-07 17:31:09 +03:00
|
|
|
/**
|
|
|
|
* Add a function to group.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
void do_register(const std::string& name, function& fun);
|
2013-08-07 17:31:09 +03:00
|
|
|
/**
|
|
|
|
* Drop a function from group.
|
|
|
|
*/
|
|
|
|
void do_unregister(const std::string& name);
|
|
|
|
/**
|
|
|
|
* Request callbacks on all currently registered functions.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
void request_callback(std::function<void(std::string, function*)> cb);
|
2013-08-07 17:31:09 +03:00
|
|
|
/**
|
|
|
|
* Bind a callback.
|
|
|
|
*
|
|
|
|
* Callbacks for all registered functions are immediately called.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
int add_callback(std::function<void(std::string, function*)> cb,
|
|
|
|
std::function<void(function_group*)> dcb);
|
2013-08-07 17:31:09 +03:00
|
|
|
/**
|
|
|
|
* Unbind a calback.
|
|
|
|
*/
|
|
|
|
void drop_callback(int handle);
|
|
|
|
private:
|
|
|
|
int next_handle;
|
2013-12-20 02:02:12 +02:00
|
|
|
std::map<std::string, function*> functions;
|
|
|
|
std::map<int, std::function<void(std::string, function*)>> callbacks;
|
|
|
|
std::map<int, std::function<void(function_group*)>> dcallbacks;
|
2013-08-07 17:31:09 +03:00
|
|
|
};
|
|
|
|
|
2012-10-16 17:39:55 +03:00
|
|
|
/**
|
|
|
|
* Lua state object.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
class state
|
2012-10-16 17:39:55 +03:00
|
|
|
{
|
2012-10-20 10:45:56 +03:00
|
|
|
public:
|
2013-05-12 11:18:16 +03:00
|
|
|
//Auxillary type for store-tag.
|
2012-10-20 10:45:56 +03:00
|
|
|
template<typename T> struct _store_tag
|
|
|
|
{
|
|
|
|
T& addr;
|
|
|
|
T val;
|
|
|
|
_store_tag(T& a, T v) : addr(a), val(v) {}
|
|
|
|
};
|
2013-10-27 14:41:28 +02:00
|
|
|
//Auxillary type for vararg-tag.
|
|
|
|
struct vararg_tag
|
|
|
|
{
|
|
|
|
std::list<std::string> args;
|
|
|
|
vararg_tag(std::list<std::string>& _args) : args(_args) {}
|
2013-12-20 02:02:12 +02:00
|
|
|
int pushargs(state& L);
|
2013-10-27 14:41:28 +02:00
|
|
|
};
|
2013-05-12 11:18:16 +03:00
|
|
|
|
|
|
|
//Auxillary type for numeric-tag.
|
2012-10-20 10:45:56 +03:00
|
|
|
template<typename T> struct _numeric_tag
|
|
|
|
{
|
|
|
|
T val;
|
|
|
|
_numeric_tag(T v) : val(v) {}
|
|
|
|
};
|
2013-05-12 11:18:16 +03:00
|
|
|
|
|
|
|
//Auxillary type for fnptr-tag.
|
2012-10-20 10:45:56 +03:00
|
|
|
template<typename T> struct _fnptr_tag
|
|
|
|
{
|
2013-12-20 02:02:12 +02:00
|
|
|
int(*fn)(state& L, T v);
|
2012-10-20 10:45:56 +03:00
|
|
|
T val;
|
2013-12-20 02:02:12 +02:00
|
|
|
_fnptr_tag(int (*f)(state& L, T v), T v) : fn(f), val(v) {}
|
2012-10-20 10:45:56 +03:00
|
|
|
};
|
2013-05-12 11:18:16 +03:00
|
|
|
|
|
|
|
//Auxillary type for fn-tag.
|
2012-10-20 10:45:56 +03:00
|
|
|
template<typename T> struct _fn_tag
|
|
|
|
{
|
|
|
|
T fn;
|
|
|
|
_fn_tag(T f) : fn(f) {}
|
|
|
|
};
|
2013-05-12 11:18:16 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Callback parameter: Don't pass any real parameter, but instead store specified value in specified
|
|
|
|
* location.
|
|
|
|
*
|
|
|
|
* Parameter a: The location to store value to.
|
|
|
|
* Parameter v: The value to store.
|
|
|
|
* Returns: The parameter structure.
|
|
|
|
*/
|
|
|
|
template<typename T> static struct _store_tag<T> store_tag(T& a, T v) { return _store_tag<T>(a, v); }
|
|
|
|
/**
|
|
|
|
* Callback parameter: Pass numeric value.
|
|
|
|
*
|
|
|
|
* Parameter v: The value to pass.
|
|
|
|
* Returns: The parameter structure.
|
|
|
|
*/
|
|
|
|
template<typename T> static struct _numeric_tag<T> numeric_tag(T v) { return _numeric_tag<T>(v); }
|
2013-07-06 23:21:11 +03:00
|
|
|
|
2013-05-12 11:18:16 +03:00
|
|
|
/**
|
|
|
|
* Callback parameter: Execute function to push more parameters.
|
|
|
|
*
|
|
|
|
* Parameter f: The function to execute. The return value is number of additional parameters pushed.
|
|
|
|
* Parameter v: The value to pass to function.
|
|
|
|
* Returns: The parameter structure.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
template<typename T> static struct _fnptr_tag<T> fnptr_tag(int (*f)(state& L, T v), T v)
|
2013-05-12 11:18:16 +03:00
|
|
|
{
|
|
|
|
return _fnptr_tag<T>(f, v);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Callback parameter: Execute function to push more parameters.
|
|
|
|
*
|
|
|
|
* Parameter v: The functor to execute. Passed reference to the Lua state. The return value is number of
|
|
|
|
* additional parameters pushed.
|
|
|
|
* Returns: The parameter structure.
|
|
|
|
*/
|
2012-10-20 10:45:56 +03:00
|
|
|
template<typename T> static struct _fn_tag<T> fn_tag(T v) { return _fn_tag<T>(v); }
|
2013-05-12 11:18:16 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Callback parameter: Pass boolean argument.
|
|
|
|
*
|
|
|
|
* Parameter v: The boolean value to pass.
|
|
|
|
*/
|
2012-10-20 10:45:56 +03:00
|
|
|
struct boolean_tag { bool val; boolean_tag(bool v) : val(v) {}};
|
2013-05-12 11:18:16 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Callback parameter: Pass string argument.
|
|
|
|
*
|
|
|
|
* Parameter v: The string value to pass.
|
|
|
|
*/
|
2012-10-20 10:45:56 +03:00
|
|
|
struct string_tag { std::string val; string_tag(const std::string& v) : val(v) {}};
|
2013-05-12 11:18:16 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Callback parameter: Pass nil argument.
|
|
|
|
*/
|
|
|
|
struct nil_tag { nil_tag() {}};
|
2012-10-20 10:45:56 +03:00
|
|
|
private:
|
|
|
|
template<typename U, typename... T> void _callback(int argc, _store_tag<U> tag, T... args)
|
|
|
|
{
|
|
|
|
tag.addr = tag.val;
|
|
|
|
_callback(argc, args...);
|
|
|
|
tag.addr = NULL;
|
|
|
|
}
|
|
|
|
|
2013-10-27 14:41:28 +02:00
|
|
|
template<typename... T> void _callback(int argc, vararg_tag tag, T... args)
|
|
|
|
{
|
|
|
|
int e = tag.pushargs(*this);
|
|
|
|
_callback(argc + e, args...);
|
|
|
|
}
|
|
|
|
|
2013-05-12 11:18:16 +03:00
|
|
|
template<typename... T> void _callback(int argc, nil_tag tag, T... args)
|
|
|
|
{
|
|
|
|
pushnil();
|
|
|
|
_callback(argc + 1, args...);
|
|
|
|
}
|
|
|
|
|
2012-10-20 10:45:56 +03:00
|
|
|
template<typename... T> void _callback(int argc, boolean_tag tag, T... args)
|
|
|
|
{
|
|
|
|
pushboolean(tag.val);
|
|
|
|
_callback(argc + 1, args...);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename... T> void _callback(int argc, string_tag tag, T... args)
|
|
|
|
{
|
|
|
|
pushlstring(tag.val.c_str(), tag.val.length());
|
|
|
|
_callback(argc + 1, args...);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename U, typename... T> void _callback(int argc, _numeric_tag<U> tag, T... args)
|
|
|
|
{
|
|
|
|
pushnumber(tag.val);
|
|
|
|
_callback(argc + 1, args...);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename U, typename... T> void _callback(int argc, _fnptr_tag<U> tag, T... args)
|
|
|
|
{
|
|
|
|
int extra = tag.fn(*this, tag.val);
|
|
|
|
_callback(argc + extra, args...);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename U, typename... T> void _callback(int argc, _fn_tag<U> tag, T... args)
|
|
|
|
{
|
|
|
|
int extra = tag.fn(*this);
|
|
|
|
_callback(argc + extra, args...);
|
|
|
|
}
|
|
|
|
|
|
|
|
void _callback(int argc)
|
|
|
|
{
|
|
|
|
int r = pcall(argc, 0, 0);
|
|
|
|
if(r == LUA_ERRRUN) {
|
|
|
|
(stringfmt() << "Error running Lua callback: " << tostring(-1)).throwex();
|
|
|
|
pop(1);
|
|
|
|
}
|
|
|
|
if(r == LUA_ERRMEM) {
|
|
|
|
(stringfmt() << "Error running Lua callback: Out of memory").throwex();
|
|
|
|
pop(1);
|
|
|
|
}
|
|
|
|
if(r == LUA_ERRERR) {
|
|
|
|
(stringfmt() << "Error running Lua callback: Double Fault???").throwex();
|
|
|
|
pop(1);
|
|
|
|
}
|
|
|
|
}
|
2012-10-16 17:39:55 +03:00
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Create a new state.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
state() throw(std::bad_alloc);
|
2013-06-21 00:25:04 +03:00
|
|
|
/**
|
|
|
|
* Create a new state with specified master state.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
state(state& _master, lua_State* L);
|
2012-10-16 17:39:55 +03:00
|
|
|
/**
|
|
|
|
* Destroy a state.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
~state() throw();
|
2012-10-16 17:39:55 +03:00
|
|
|
/**
|
|
|
|
* Get the internal state object.
|
|
|
|
*
|
|
|
|
* Return value: Internal state.
|
|
|
|
*/
|
|
|
|
lua_State* handle() { return lua_handle; }
|
2013-06-21 00:25:04 +03:00
|
|
|
/**
|
|
|
|
* Get the master state.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
state& get_master() { return master ? master->get_master() : *this; }
|
2013-06-21 00:25:04 +03:00
|
|
|
/**
|
|
|
|
* Set the internal state object.
|
|
|
|
*/
|
|
|
|
void handle(lua_State* l) { lua_handle = l; }
|
2012-10-16 17:39:55 +03:00
|
|
|
/**
|
|
|
|
* Set OOM handler.
|
|
|
|
*/
|
|
|
|
void set_oom_handler(void (*oom)()) { oom_handler = oom ? oom : builtin_oom; }
|
|
|
|
/**
|
|
|
|
* Reset the state.
|
|
|
|
*/
|
|
|
|
void reset() throw(std::runtime_error, std::bad_alloc);
|
|
|
|
/**
|
|
|
|
* Deinit the state.
|
|
|
|
*/
|
|
|
|
void deinit() throw();
|
|
|
|
/**
|
|
|
|
* Get a string argument.
|
|
|
|
*
|
|
|
|
* Parameter argindex: The stack index.
|
|
|
|
* Parameter fname: The name of function to use in error messages.
|
|
|
|
* Returns: The string.
|
|
|
|
* Throws std::runtime_error: The specified argument is not a string.
|
|
|
|
*/
|
|
|
|
std::string get_string(int argindex, const std::string& fname) throw(std::runtime_error, std::bad_alloc)
|
|
|
|
{
|
|
|
|
if(lua_isnone(lua_handle, argindex))
|
|
|
|
(stringfmt() << "argument #" << argindex << " to " << fname << " must be string").throwex();
|
|
|
|
size_t len;
|
|
|
|
const char* f = lua_tolstring(lua_handle, argindex, &len);
|
|
|
|
if(!f)
|
|
|
|
(stringfmt() << "argument #" << argindex << " to " << fname << " must be string").throwex();
|
|
|
|
return std::string(f, f + len);
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Get a boolean argument.
|
|
|
|
*
|
|
|
|
* Parameter argindex: The stack index.
|
|
|
|
* Parameter fname: The name of function to use in error messages.
|
|
|
|
* Returns: The string.
|
|
|
|
* Throws std::runtime_error: The specified argument is not a boolean.
|
|
|
|
*/
|
|
|
|
bool get_bool(int argindex, const std::string& fname) throw(std::runtime_error, std::bad_alloc)
|
|
|
|
{
|
|
|
|
if(lua_isnone(lua_handle, argindex) || !lua_isboolean(lua_handle, argindex))
|
|
|
|
(stringfmt() << "argument #" << argindex << " to " << fname << " must be boolean").throwex();
|
|
|
|
return (lua_toboolean(lua_handle, argindex) != 0);
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Get a mandatory numeric argument.
|
|
|
|
*
|
|
|
|
* Parameter argindex: The stack index.
|
|
|
|
* Parameter fname: The name of function to use in error messages.
|
|
|
|
* Returns: The parsed number.
|
|
|
|
* Throws std::runtime_error: Bad type.
|
|
|
|
*/
|
|
|
|
template<typename T>
|
|
|
|
T get_numeric_argument(int argindex, const std::string& fname)
|
|
|
|
{
|
|
|
|
if(lua_isnone(lua_handle, argindex) || !lua_isnumber(lua_handle, argindex))
|
2013-11-24 04:41:46 +02:00
|
|
|
(stringfmt() << "Argument #" << argindex << " to " << fname << " must be numeric").throwex();
|
2012-10-16 17:39:55 +03:00
|
|
|
return static_cast<T>(lua_tonumber(lua_handle, argindex));
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Get a optional numeric argument.
|
|
|
|
*
|
|
|
|
* Parameter argindex: The stack index.
|
|
|
|
* Parameter value: The place to store the value.
|
|
|
|
* Parameter fname: The name of function to use in error messages.
|
|
|
|
* Throws std::runtime_error: Bad type.
|
|
|
|
*/
|
|
|
|
template<typename T>
|
|
|
|
void get_numeric_argument(unsigned argindex, T& value, const std::string& fname)
|
|
|
|
{
|
|
|
|
if(lua_isnoneornil(lua_handle, argindex))
|
|
|
|
return;
|
|
|
|
if(lua_isnone(lua_handle, argindex) || !lua_isnumber(lua_handle, argindex))
|
2013-11-24 04:41:46 +02:00
|
|
|
(stringfmt() << "Argument #" << argindex << " to " << fname << " must be numeric if "
|
2012-10-16 17:39:55 +03:00
|
|
|
"present").throwex();
|
|
|
|
value = static_cast<T>(lua_tonumber(lua_handle, argindex));
|
|
|
|
}
|
2012-10-20 10:45:56 +03:00
|
|
|
/**
|
|
|
|
* Do a callback.
|
|
|
|
*
|
|
|
|
* Parameter name: The name of the callback.
|
|
|
|
* Parameter args: Arguments to pass to the callback.
|
|
|
|
*/
|
|
|
|
template<typename... T>
|
2013-03-03 09:37:52 +02:00
|
|
|
bool callback(const std::string& name, T... args)
|
2012-10-20 10:45:56 +03:00
|
|
|
{
|
|
|
|
getglobal(name.c_str());
|
|
|
|
int t = type(-1);
|
|
|
|
if(t != LUA_TFUNCTION) {
|
|
|
|
pop(1);
|
2013-03-03 09:37:52 +02:00
|
|
|
return false;
|
2012-10-20 10:45:56 +03:00
|
|
|
}
|
|
|
|
_callback(0, args...);
|
2013-03-03 09:37:52 +02:00
|
|
|
return true;
|
2012-10-20 10:45:56 +03:00
|
|
|
}
|
2013-08-06 16:17:01 +03:00
|
|
|
/**
|
|
|
|
* Do a callback.
|
|
|
|
*
|
|
|
|
* Parameter cblist: List of environment keys to do callbacks.
|
|
|
|
* Parameter args: Arguments to pass to the callback.
|
|
|
|
*/
|
|
|
|
template<typename... T>
|
|
|
|
bool callback(const std::list<char>& cblist, T... args)
|
|
|
|
{
|
|
|
|
bool any = false;
|
|
|
|
for(auto& i : cblist) {
|
|
|
|
pushlightuserdata(const_cast<char*>(&i));
|
|
|
|
rawget(LUA_REGISTRYINDEX);
|
|
|
|
int t = type(-1);
|
|
|
|
if(t != LUA_TFUNCTION) {
|
|
|
|
pop(1);
|
|
|
|
} else {
|
|
|
|
_callback(0, args...);
|
|
|
|
any = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return any;
|
|
|
|
}
|
2013-08-07 17:31:09 +03:00
|
|
|
/**
|
|
|
|
* Add a group of functions.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
void add_function_group(function_group& group);
|
2013-08-07 17:31:09 +03:00
|
|
|
/**
|
|
|
|
* Function callback.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
void function_callback(const std::string& name, function* func);
|
2013-02-01 22:26:22 +02:00
|
|
|
/**
|
|
|
|
* Do something just once per VM.
|
2013-05-12 11:18:16 +03:00
|
|
|
*
|
|
|
|
* Parameter key: The do-once key value.
|
2013-05-12 13:48:52 +03:00
|
|
|
* Returns: True if called the first time for given key on given VM, false otherwise.
|
2013-02-01 22:26:22 +02:00
|
|
|
*/
|
|
|
|
bool do_once(void* key);
|
2013-08-06 16:17:01 +03:00
|
|
|
/**
|
|
|
|
* Callback list.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
class callback_list
|
2013-08-06 16:17:01 +03:00
|
|
|
{
|
|
|
|
public:
|
2013-12-20 02:02:12 +02:00
|
|
|
callback_list(state& L, const std::string& name, const std::string& fn_cbname = "");
|
|
|
|
~callback_list();
|
|
|
|
void _register(state& L); //Reads callback from top of lua stack.
|
|
|
|
void _unregister(state& L); //Reads callback from top of lua stack.
|
2013-08-06 16:17:01 +03:00
|
|
|
template<typename... T> bool callback(T... args) {
|
|
|
|
bool any = L.callback(callbacks, args...);
|
|
|
|
if(fn_cbname != "" && L.callback(fn_cbname, args...))
|
|
|
|
any = true;
|
|
|
|
return any;
|
|
|
|
}
|
|
|
|
const std::string& get_name() { return name; }
|
|
|
|
void clear() { callbacks.clear(); }
|
|
|
|
private:
|
2013-12-20 02:02:12 +02:00
|
|
|
callback_list(const callback_list&);
|
|
|
|
callback_list& operator=(const callback_list&);
|
2013-08-06 16:17:01 +03:00
|
|
|
std::list<char> callbacks;
|
2013-12-20 02:02:12 +02:00
|
|
|
state& L;
|
2013-08-06 16:17:01 +03:00
|
|
|
std::string name;
|
|
|
|
std::string fn_cbname;
|
|
|
|
};
|
|
|
|
/**
|
|
|
|
* Enumerate all callbacks.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
std::list<callback_list*> get_callbacks()
|
2013-08-06 16:17:01 +03:00
|
|
|
{
|
|
|
|
if(master)
|
|
|
|
return master->get_callbacks();
|
2013-12-20 02:02:12 +02:00
|
|
|
std::list<callback_list*> r;
|
2013-08-06 16:17:01 +03:00
|
|
|
for(auto i : callbacks)
|
|
|
|
r.push_back(i.second);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Register a callback.
|
|
|
|
*/
|
|
|
|
class callback_proxy
|
|
|
|
{
|
|
|
|
public:
|
2013-12-20 02:02:12 +02:00
|
|
|
callback_proxy(state& _L) : parent(_L) {}
|
|
|
|
void do_register(const std::string& name, callback_list& callback)
|
2013-08-06 16:17:01 +03:00
|
|
|
{
|
|
|
|
parent.do_register_cb(name, callback);
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Unregister a callback.
|
|
|
|
*/
|
|
|
|
void do_unregister(const std::string& name)
|
|
|
|
{
|
|
|
|
parent.do_unregister_cb(name);
|
|
|
|
}
|
|
|
|
private:
|
2013-12-20 02:02:12 +02:00
|
|
|
state& parent;
|
2013-08-06 16:17:01 +03:00
|
|
|
};
|
|
|
|
|
2013-12-20 02:02:12 +02:00
|
|
|
void do_register_cb(const std::string& name, callback_list& callback)
|
2013-08-06 16:17:01 +03:00
|
|
|
{
|
|
|
|
callbacks[name] = &callback;
|
|
|
|
}
|
|
|
|
|
|
|
|
void do_unregister_cb(const std::string& name)
|
|
|
|
{
|
|
|
|
callbacks.erase(name);
|
|
|
|
}
|
2012-10-16 17:39:55 +03:00
|
|
|
|
2013-05-12 11:18:16 +03:00
|
|
|
//All kinds of Lua API functions.
|
2012-10-16 17:39:55 +03:00
|
|
|
void pop(int n) { lua_pop(lua_handle, n); }
|
|
|
|
void* newuserdata(size_t size) { return lua_newuserdata(lua_handle, size); }
|
|
|
|
int setmetatable(int index) { return lua_setmetatable(lua_handle, index); }
|
|
|
|
int type(int index) { return lua_type(lua_handle, index); }
|
|
|
|
int getmetatable(int index) { return lua_getmetatable(lua_handle, index); }
|
|
|
|
int rawequal(int index1, int index2) { return lua_rawequal(lua_handle, index1, index2); }
|
|
|
|
void* touserdata(int index) { return lua_touserdata(lua_handle, index); }
|
2013-09-27 04:43:44 +03:00
|
|
|
const void* topointer(int index) { return lua_topointer(lua_handle, index); }
|
|
|
|
int gettop() { return lua_gettop(lua_handle); }
|
2012-10-16 17:39:55 +03:00
|
|
|
void pushvalue(int index) { lua_pushvalue(lua_handle, index); }
|
|
|
|
void pushlightuserdata(void* p) { lua_pushlightuserdata(lua_handle, p); }
|
|
|
|
void rawset(int index) { lua_rawset(lua_handle, index); }
|
|
|
|
void pushnil() { lua_pushnil(lua_handle); }
|
|
|
|
void pushstring(const char* s) { lua_pushstring(lua_handle, s); }
|
|
|
|
void rawget(int index) { lua_rawget(lua_handle, index); }
|
|
|
|
int isnil(int index) { return lua_isnil(lua_handle, index); }
|
|
|
|
void newtable() { lua_newtable(lua_handle); }
|
|
|
|
void pushcclosure(lua_CFunction fn, int n) { lua_pushcclosure(lua_handle, fn, n); }
|
|
|
|
void pushcfunction(lua_CFunction fn) { lua_pushcfunction(lua_handle, fn); }
|
|
|
|
void setfield(int index, const char* k) { lua_setfield(lua_handle, index, k); }
|
|
|
|
void getfield(int index, const char* k) { lua_getfield(lua_handle, index, k); }
|
|
|
|
void getglobal(const char* name) { lua_getglobal(lua_handle, name); }
|
|
|
|
void setglobal(const char* name) { lua_setglobal(lua_handle, name); }
|
|
|
|
void insert(int index) { lua_insert(lua_handle, index); }
|
|
|
|
void settable(int index) { lua_settable(lua_handle, index); }
|
|
|
|
int isnone(int index) { return lua_isnone(lua_handle, index); }
|
|
|
|
void pushnumber(lua_Number n) { return lua_pushnumber(lua_handle, n); }
|
|
|
|
int isnumber(int index) { return lua_isnumber(lua_handle, index); }
|
|
|
|
int isboolean(int index) { return lua_isboolean(lua_handle, index); }
|
|
|
|
int toboolean(int index) { return lua_toboolean(lua_handle, index); }
|
|
|
|
const char* tolstring(int index, size_t *len) { return lua_tolstring(lua_handle, index, len); }
|
|
|
|
void pushboolean(int b) { lua_pushboolean(lua_handle, b); }
|
|
|
|
lua_Number tonumber(int index) { return lua_tonumber(lua_handle, index); }
|
|
|
|
void gettable(int index) { lua_gettable(lua_handle, index); }
|
|
|
|
#if LUA_VERSION_NUM == 501
|
|
|
|
int load(lua_Reader reader, void* data, const char* chunkname) { return lua_load(lua_handle, reader, data,
|
|
|
|
chunkname); }
|
|
|
|
#endif
|
|
|
|
#if LUA_VERSION_NUM == 502
|
|
|
|
int load(lua_Reader reader, void* data, const char* chunkname, const char* mode) { return lua_load(lua_handle,
|
|
|
|
reader, data, chunkname, mode); }
|
|
|
|
#endif
|
|
|
|
const char* tostring(int index) { return lua_tostring(lua_handle, index); }
|
|
|
|
const char* tolstring(int index, size_t& len) { return lua_tolstring(lua_handle, index, &len); }
|
|
|
|
void pushlstring(const char* s, size_t len) { lua_pushlstring(lua_handle, s, len); }
|
2013-05-01 18:06:24 +03:00
|
|
|
void pushlstring(const std::string& s) { lua_pushlstring(lua_handle, s.c_str(), s.length()); }
|
|
|
|
void pushlstring(const char32_t* s, size_t len) { pushlstring(to_u8string(std::u32string(s, len))); }
|
2012-10-16 17:39:55 +03:00
|
|
|
int pcall(int nargs, int nresults, int errfunc) { return lua_pcall(lua_handle, nargs, nresults, errfunc); }
|
|
|
|
int next(int index) { return lua_next(lua_handle, index); }
|
|
|
|
int isnoneornil(int index) { return lua_isnoneornil(lua_handle, index); }
|
|
|
|
lua_Integer tointeger(int index) { return lua_tointeger(lua_handle, index); }
|
|
|
|
void rawgeti(int index, int n) { lua_rawgeti(lua_handle, index, n); }
|
2013-08-06 16:17:01 +03:00
|
|
|
callback_proxy cbproxy;
|
2012-10-16 17:39:55 +03:00
|
|
|
private:
|
|
|
|
static void builtin_oom();
|
|
|
|
static void* builtin_alloc(void* user, void* old, size_t olds, size_t news);
|
|
|
|
void (*oom_handler)();
|
2013-12-20 02:02:12 +02:00
|
|
|
state* master;
|
2012-10-16 17:39:55 +03:00
|
|
|
lua_State* lua_handle;
|
2013-12-20 02:02:12 +02:00
|
|
|
std::set<std::pair<function_group*, int>> function_groups;
|
|
|
|
std::map<std::string, callback_list*> callbacks;
|
|
|
|
state(state&);
|
|
|
|
state& operator=(state&);
|
2012-10-16 17:39:55 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Pin of an object against Lua GC.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
template<typename T> struct objpin
|
2012-10-16 17:39:55 +03:00
|
|
|
{
|
2013-08-21 19:24:00 +03:00
|
|
|
/**
|
|
|
|
* Create a null pin.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
objpin()
|
2013-08-21 19:24:00 +03:00
|
|
|
{
|
2013-12-20 02:02:12 +02:00
|
|
|
_state = NULL;
|
2013-08-21 19:24:00 +03:00
|
|
|
obj = NULL;
|
|
|
|
}
|
2012-10-16 17:39:55 +03:00
|
|
|
/**
|
|
|
|
* Create a new pin.
|
|
|
|
*
|
|
|
|
* Parameter _state: The state to pin the object in.
|
|
|
|
* Parameter _object: The object to pin.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
objpin(state& lstate, T* _object)
|
|
|
|
: _state(&lstate.get_master())
|
2012-10-16 17:39:55 +03:00
|
|
|
{
|
2013-12-20 02:02:12 +02:00
|
|
|
_state->pushlightuserdata(this);
|
|
|
|
_state->pushvalue(-2);
|
|
|
|
_state->rawset(LUA_REGISTRYINDEX);
|
2012-10-16 17:39:55 +03:00
|
|
|
obj = _object;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Delete a pin.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
~objpin() throw()
|
2012-10-16 17:39:55 +03:00
|
|
|
{
|
2013-08-21 19:24:00 +03:00
|
|
|
if(obj) {
|
2013-12-20 02:02:12 +02:00
|
|
|
_state->pushlightuserdata(this);
|
|
|
|
_state->pushnil();
|
|
|
|
_state->rawset(LUA_REGISTRYINDEX);
|
2013-08-21 19:24:00 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Copy ctor.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
objpin(const objpin& p)
|
2013-08-21 19:24:00 +03:00
|
|
|
{
|
2013-12-20 02:02:12 +02:00
|
|
|
_state = p._state;
|
2013-08-21 19:24:00 +03:00
|
|
|
obj = p.obj;
|
|
|
|
if(obj) {
|
2013-12-20 02:02:12 +02:00
|
|
|
_state->pushlightuserdata(this);
|
|
|
|
_state->pushlightuserdata(const_cast<objpin*>(&p));
|
|
|
|
_state->rawget(LUA_REGISTRYINDEX);
|
|
|
|
_state->rawset(LUA_REGISTRYINDEX);
|
2013-08-21 19:24:00 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Assignment operator.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
objpin& operator=(const objpin& p)
|
2013-08-21 19:24:00 +03:00
|
|
|
{
|
2013-12-20 02:02:12 +02:00
|
|
|
if(_state == p._state && obj == p.obj)
|
2013-08-21 19:24:00 +03:00
|
|
|
return *this;
|
|
|
|
if(obj == p.obj)
|
|
|
|
throw std::logic_error("A Lua object can't be in two lua states at once");
|
|
|
|
if(obj) {
|
2013-12-20 02:02:12 +02:00
|
|
|
_state->pushlightuserdata(this);
|
|
|
|
_state->pushnil();
|
|
|
|
_state->rawset(LUA_REGISTRYINDEX);
|
2013-08-21 19:24:00 +03:00
|
|
|
}
|
2013-12-20 02:02:12 +02:00
|
|
|
_state = p._state;
|
2013-08-21 19:24:00 +03:00
|
|
|
if(p.obj) {
|
2013-12-20 02:02:12 +02:00
|
|
|
_state->pushlightuserdata(this);
|
|
|
|
_state->pushlightuserdata(const_cast<objpin*>(&p));
|
|
|
|
_state->rawget(LUA_REGISTRYINDEX);
|
|
|
|
_state->rawset(LUA_REGISTRYINDEX);
|
2013-08-21 19:24:00 +03:00
|
|
|
}
|
|
|
|
obj = p.obj;
|
|
|
|
return *this;
|
2012-10-16 17:39:55 +03:00
|
|
|
}
|
2013-09-27 20:54:54 +03:00
|
|
|
/**
|
|
|
|
* Clear a pinned object.
|
|
|
|
*/
|
|
|
|
void clear()
|
|
|
|
{
|
|
|
|
if(obj) {
|
2013-12-20 02:02:12 +02:00
|
|
|
_state->pushlightuserdata(this);
|
|
|
|
_state->pushnil();
|
|
|
|
_state->rawset(LUA_REGISTRYINDEX);
|
2013-09-27 20:54:54 +03:00
|
|
|
}
|
2013-12-20 02:02:12 +02:00
|
|
|
_state = NULL;
|
2013-09-27 20:54:54 +03:00
|
|
|
obj = NULL;
|
|
|
|
}
|
2012-10-16 17:39:55 +03:00
|
|
|
/**
|
|
|
|
* Get pointer to pinned object.
|
|
|
|
*
|
|
|
|
* Returns: The pinned object.
|
|
|
|
*/
|
|
|
|
T* object() { return obj; }
|
2013-08-21 19:24:00 +03:00
|
|
|
/**
|
|
|
|
* Is non-null?
|
|
|
|
*/
|
|
|
|
operator bool() { return obj != NULL; }
|
|
|
|
/**
|
|
|
|
* Smart pointer.
|
|
|
|
*/
|
|
|
|
T& operator*() { if(obj) return *obj; throw std::runtime_error("Attempted to reference NULL Lua pin"); }
|
|
|
|
T* operator->() { if(obj) return obj; throw std::runtime_error("Attempted to reference NULL Lua pin"); }
|
2013-09-27 20:54:54 +03:00
|
|
|
/**
|
|
|
|
* Push Lua value.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
void luapush(state& lstate)
|
2013-09-27 20:54:54 +03:00
|
|
|
{
|
2013-12-20 02:02:12 +02:00
|
|
|
lstate.pushlightuserdata(this);
|
|
|
|
lstate.rawget(LUA_REGISTRYINDEX);
|
2013-09-27 20:54:54 +03:00
|
|
|
}
|
2012-10-16 17:39:55 +03:00
|
|
|
private:
|
|
|
|
T* obj;
|
2013-12-20 02:02:12 +02:00
|
|
|
state* _state;
|
2012-10-16 17:39:55 +03:00
|
|
|
};
|
|
|
|
|
2013-12-20 02:02:12 +02:00
|
|
|
template<typename T> void* unbox_any_pin(struct objpin<T>* pin)
|
2013-02-28 10:40:40 +02:00
|
|
|
{
|
|
|
|
return pin ? pin->object() : NULL;
|
|
|
|
}
|
|
|
|
|
2012-10-16 17:39:55 +03:00
|
|
|
/**
|
|
|
|
* Helper class containing binding data for Lua class call.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
template<class T> struct class_binding
|
2012-10-16 17:39:55 +03:00
|
|
|
{
|
|
|
|
/**
|
|
|
|
* The pointer to call.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
int (T::*fn)(state& lstate, const std::string& _fname);
|
2012-10-16 17:39:55 +03:00
|
|
|
/**
|
|
|
|
* The state to call it in.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
state* _state;
|
2012-10-16 17:39:55 +03:00
|
|
|
/**
|
|
|
|
* The name of the method to pass.
|
|
|
|
*/
|
2013-08-21 23:32:48 +03:00
|
|
|
char fname[];
|
2012-10-16 17:39:55 +03:00
|
|
|
};
|
|
|
|
|
2013-12-20 02:02:12 +02:00
|
|
|
template<class T> class _class;
|
2012-10-16 17:39:55 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Function to obtain class object for given Lua class.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
template<class T> _class<T>& objclass()
|
2013-12-19 23:24:08 +02:00
|
|
|
{
|
2013-12-20 02:02:12 +02:00
|
|
|
auto& type = typeid(T);
|
|
|
|
if(!class_types().count(type))
|
2013-12-19 23:34:02 +02:00
|
|
|
throw std::runtime_error("Internal error: Lua class not found!");
|
2013-12-20 02:02:12 +02:00
|
|
|
return *reinterpret_cast<_class<T>*>(class_types()[type]);
|
2013-12-19 23:24:08 +02:00
|
|
|
}
|
2012-10-16 17:39:55 +03:00
|
|
|
|
2013-12-20 02:02:12 +02:00
|
|
|
template<class T> struct class_method
|
2013-08-22 00:11:34 +03:00
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Name.
|
|
|
|
*/
|
|
|
|
const char* name;
|
|
|
|
/**
|
|
|
|
* Function.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
int (T::*fn)(state& LS, const std::string& fname);
|
2013-08-22 00:11:34 +03:00
|
|
|
};
|
|
|
|
|
2012-10-16 17:39:55 +03:00
|
|
|
/**
|
|
|
|
* The type of Lua classes.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
template<class T> class _class
|
2012-10-16 17:39:55 +03:00
|
|
|
{
|
2013-12-20 02:02:12 +02:00
|
|
|
template<typename... U> T* _create(state& _state, U... args)
|
2012-10-16 17:39:55 +03:00
|
|
|
{
|
2013-12-20 02:02:12 +02:00
|
|
|
void* obj = _state.newuserdata(sizeof(T));
|
|
|
|
load_metatable(_state);
|
|
|
|
_state.setmetatable(-2);
|
2012-10-16 17:39:55 +03:00
|
|
|
T* _obj = reinterpret_cast<T*>(obj);
|
2013-12-20 02:02:12 +02:00
|
|
|
new(_obj) T(_state, args...);
|
2012-10-16 17:39:55 +03:00
|
|
|
return _obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int class_bind_trampoline(lua_State* LS)
|
|
|
|
{
|
2013-05-12 15:02:38 +03:00
|
|
|
try {
|
2013-12-20 02:02:12 +02:00
|
|
|
class_binding<T>* b = (class_binding<T>*)lua_touserdata(LS, lua_upvalueindex(1));
|
|
|
|
state L(*b->_state, LS);
|
|
|
|
T* p = _class<T>::get(L, 1, b->fname);
|
2013-08-22 22:34:17 +03:00
|
|
|
return (p->*(b->fn))(L, b->fname);
|
2013-05-12 15:02:38 +03:00
|
|
|
} catch(std::exception& e) {
|
|
|
|
std::string err = e.what();
|
|
|
|
lua_pushlstring(LS, err.c_str(), err.length());
|
|
|
|
lua_error(LS);
|
|
|
|
}
|
2012-10-16 17:39:55 +03:00
|
|
|
}
|
|
|
|
|
2013-12-20 02:02:12 +02:00
|
|
|
T* _get(state& _state, int arg, const std::string& fname, bool optional = false)
|
2012-10-16 17:39:55 +03:00
|
|
|
{
|
2013-12-20 02:02:12 +02:00
|
|
|
if(_state.type(arg) == LUA_TNONE || _state.type(arg) == LUA_TNIL) {
|
2012-10-16 17:39:55 +03:00
|
|
|
if(optional)
|
|
|
|
return NULL;
|
|
|
|
else
|
|
|
|
goto badtype;
|
|
|
|
}
|
2013-12-20 02:02:12 +02:00
|
|
|
load_metatable(_state);
|
|
|
|
if(!_state.getmetatable(arg))
|
2012-10-16 17:39:55 +03:00
|
|
|
goto badtype;
|
2013-12-20 02:02:12 +02:00
|
|
|
if(!_state.rawequal(-1, -2))
|
2012-10-16 17:39:55 +03:00
|
|
|
goto badtype;
|
2013-12-20 02:02:12 +02:00
|
|
|
_state.pop(2);
|
|
|
|
return reinterpret_cast<T*>(_state.touserdata(arg));
|
2012-10-16 17:39:55 +03:00
|
|
|
badtype:
|
|
|
|
(stringfmt() << "argument #" << arg << " to " << fname << " must be " << name).throwex();
|
2013-02-10 15:00:12 +02:00
|
|
|
return NULL; //Never reached.
|
2012-10-16 17:39:55 +03:00
|
|
|
}
|
|
|
|
|
2013-12-20 02:02:12 +02:00
|
|
|
bool _is(state& _state, int arg)
|
2012-10-16 17:39:55 +03:00
|
|
|
{
|
2013-12-20 02:02:12 +02:00
|
|
|
if(_state.type(arg) != LUA_TUSERDATA)
|
2012-10-16 17:39:55 +03:00
|
|
|
return false;
|
2013-12-20 02:02:12 +02:00
|
|
|
load_metatable(_state);
|
|
|
|
if(!_state.getmetatable(arg)) {
|
|
|
|
_state.pop(1);
|
2012-10-16 17:39:55 +03:00
|
|
|
return false;
|
|
|
|
}
|
2013-12-20 02:02:12 +02:00
|
|
|
bool ret = _state.rawequal(-1, -2);
|
|
|
|
_state.pop(2);
|
2012-10-16 17:39:55 +03:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-12-20 02:02:12 +02:00
|
|
|
objpin<T> _pin(state& _state, int arg, const std::string& fname)
|
2012-10-16 17:39:55 +03:00
|
|
|
{
|
2013-12-20 02:02:12 +02:00
|
|
|
T* obj = get(_state, arg, fname);
|
|
|
|
_state.pushvalue(arg);
|
|
|
|
return objpin<T>(_state, obj);
|
2012-10-16 17:39:55 +03:00
|
|
|
}
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Create a new Lua class.
|
|
|
|
*
|
|
|
|
* Parameter _name: The name of the class.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
_class(const std::string& _name)
|
2012-10-16 17:39:55 +03:00
|
|
|
{
|
|
|
|
name = _name;
|
2013-12-20 02:02:12 +02:00
|
|
|
class_ops m;
|
|
|
|
m.is = _class<T>::is;
|
|
|
|
m.name = _class<T>::get_name;
|
|
|
|
m.print = _class<T>::print;
|
2013-09-27 10:47:19 +03:00
|
|
|
userdata_recogn_fns().push_back(m);
|
2013-12-20 02:02:12 +02:00
|
|
|
auto& type = typeid(T);
|
|
|
|
class_types()[type] = this;
|
2012-10-16 17:39:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a new instance of object.
|
|
|
|
*
|
2013-12-20 02:02:12 +02:00
|
|
|
* Parameter _state: The Lua state to create the object in.
|
2012-10-16 17:39:55 +03:00
|
|
|
* Parameter args: The arguments to pass to class constructor.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
template<typename... U> static T* create(state& _state, U... args)
|
2012-10-16 17:39:55 +03:00
|
|
|
{
|
2013-12-20 02:02:12 +02:00
|
|
|
return objclass<T>()._create(_state, args...);
|
2012-10-16 17:39:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Bind a method to class.
|
|
|
|
*
|
2013-12-20 02:02:12 +02:00
|
|
|
* Parameter _state: The state to do the binding in.
|
2012-10-16 17:39:55 +03:00
|
|
|
* Parameter keyname: The name of the method.
|
|
|
|
* Parameter fn: The method to call.
|
|
|
|
* Parameter force: If true, overwrite existing method.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
void bind(state& _state, const char* keyname, int (T::*fn)(state& LS, const std::string& fname))
|
2012-10-16 17:39:55 +03:00
|
|
|
{
|
2013-12-20 02:02:12 +02:00
|
|
|
load_metatable(_state);
|
|
|
|
_state.pushstring(keyname);
|
2013-08-22 22:34:17 +03:00
|
|
|
std::string fname = name + std::string("::") + keyname;
|
2013-12-20 02:02:12 +02:00
|
|
|
void* ptr = _state.newuserdata(sizeof(class_binding<T>) + fname.length() + 1);
|
|
|
|
class_binding<T>* bdata = reinterpret_cast<class_binding<T>*>(ptr);
|
2012-10-16 17:39:55 +03:00
|
|
|
bdata->fn = fn;
|
2013-12-20 02:02:12 +02:00
|
|
|
bdata->_state = &_state.get_master();
|
2013-08-21 23:32:48 +03:00
|
|
|
std::copy(fname.begin(), fname.end(), bdata->fname);
|
2013-08-22 22:34:17 +03:00
|
|
|
bdata->fname[fname.length()] = 0;
|
2013-12-20 02:02:12 +02:00
|
|
|
_state.pushcclosure(class_bind_trampoline, 1);
|
|
|
|
_state.rawset(-3);
|
|
|
|
_state.pop(1);
|
2012-10-16 17:39:55 +03:00
|
|
|
}
|
2013-08-22 00:11:34 +03:00
|
|
|
/**
|
|
|
|
* Bind multiple at once.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
void bind_multi(state& _state, std::initializer_list<class_method<T>> list, void* doonce_key = NULL)
|
2013-08-22 00:11:34 +03:00
|
|
|
{
|
|
|
|
static char once_key;
|
2013-12-20 02:02:12 +02:00
|
|
|
if(_state.do_once(doonce_key ? doonce_key : &once_key))
|
2013-08-22 00:11:34 +03:00
|
|
|
for(auto i : list)
|
2013-12-20 02:02:12 +02:00
|
|
|
bind(_state, i.name, i.fn);
|
2013-08-22 00:11:34 +03:00
|
|
|
}
|
2012-10-16 17:39:55 +03:00
|
|
|
/**
|
|
|
|
* Get a pointer to the object.
|
|
|
|
*
|
2013-12-20 02:02:12 +02:00
|
|
|
* Parameter _state: The Lua state.
|
2012-10-16 17:39:55 +03:00
|
|
|
* Parameter arg: Argument index.
|
|
|
|
* Parameter fname: The name of function for error messages.
|
|
|
|
* Parameter optional: If true and argument is NIL or none, return NULL.
|
|
|
|
* Throws std::runtime_error: Wrong type.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
static T* get(state& _state, int arg, const std::string& fname, bool optional = false)
|
2012-10-16 17:39:55 +03:00
|
|
|
throw(std::bad_alloc, std::runtime_error)
|
|
|
|
{
|
2013-12-20 02:02:12 +02:00
|
|
|
return objclass<T>()._get(_state, arg, fname, optional);
|
2012-10-16 17:39:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Identify if object is of this type.
|
|
|
|
*
|
2013-12-20 02:02:12 +02:00
|
|
|
* Parameter _state: The Lua state.
|
2012-10-16 17:39:55 +03:00
|
|
|
* Parameter arg: Argument index.
|
|
|
|
* Returns: True if object is of specified type, false if not.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
static bool is(state& _state, int arg) throw()
|
2012-10-16 17:39:55 +03:00
|
|
|
{
|
2013-12-19 23:34:02 +02:00
|
|
|
try {
|
2013-12-20 02:02:12 +02:00
|
|
|
return objclass<T>()._is(_state, arg);
|
2013-12-19 23:34:02 +02:00
|
|
|
} catch(...) {
|
|
|
|
return false;
|
|
|
|
}
|
2012-10-16 17:39:55 +03:00
|
|
|
}
|
2013-09-27 04:43:44 +03:00
|
|
|
/**
|
2013-09-27 10:47:19 +03:00
|
|
|
* Get name of class.
|
2013-09-27 04:43:44 +03:00
|
|
|
*/
|
2013-09-27 10:47:19 +03:00
|
|
|
static const std::string& get_name()
|
2013-09-27 04:43:44 +03:00
|
|
|
{
|
2013-12-19 23:34:02 +02:00
|
|
|
try {
|
|
|
|
return objclass<T>().name;
|
|
|
|
} catch(...) {
|
|
|
|
static std::string foo = "???";
|
|
|
|
return foo;
|
|
|
|
}
|
2013-09-27 10:47:19 +03:00
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Format instance of this class as string.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
static std::string print(state& _state, int index)
|
2013-09-27 10:47:19 +03:00
|
|
|
{
|
2013-12-20 02:02:12 +02:00
|
|
|
T* obj = get(_state, index, "__internal_print");
|
2013-09-27 10:47:19 +03:00
|
|
|
return obj->print();
|
2013-09-27 04:43:44 +03:00
|
|
|
}
|
2012-10-16 17:39:55 +03:00
|
|
|
/**
|
|
|
|
* Get a pin of object against Lua GC.
|
|
|
|
*
|
2013-12-20 02:02:12 +02:00
|
|
|
* Parameter _state: The Lua state.
|
2012-10-16 17:39:55 +03:00
|
|
|
* Parameter arg: Argument index.
|
|
|
|
* Parameter fname: Name of function for error message purposes.
|
|
|
|
* Throws std::runtime_error: Wrong type.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
static objpin<T> pin(state& _state, int arg, const std::string& fname) throw(std::bad_alloc,
|
2012-10-16 17:39:55 +03:00
|
|
|
std::runtime_error)
|
|
|
|
{
|
2013-12-20 02:02:12 +02:00
|
|
|
return objclass<T>()._pin(_state, arg, fname);
|
2012-10-16 17:39:55 +03:00
|
|
|
}
|
|
|
|
private:
|
|
|
|
static int dogc(lua_State* LS)
|
|
|
|
{
|
|
|
|
T* obj = reinterpret_cast<T*>(lua_touserdata(LS, 1));
|
|
|
|
obj->~T();
|
2013-02-10 15:00:12 +02:00
|
|
|
return 0;
|
2012-10-16 17:39:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static int newindex(lua_State* LS)
|
|
|
|
{
|
|
|
|
lua_pushstring(LS, "Writing metatables of classes is not allowed");
|
|
|
|
lua_error(LS);
|
2013-02-10 15:00:12 +02:00
|
|
|
return 0;
|
2012-10-16 17:39:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static int index(lua_State* LS)
|
|
|
|
{
|
|
|
|
lua_getmetatable(LS, 1);
|
|
|
|
lua_pushvalue(LS, 2);
|
|
|
|
lua_rawget(LS, -2);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-12-20 02:02:12 +02:00
|
|
|
void load_metatable(state& _state)
|
2012-10-16 17:39:55 +03:00
|
|
|
{
|
|
|
|
again:
|
2013-12-20 02:02:12 +02:00
|
|
|
_state.pushlightuserdata(this);
|
|
|
|
_state.rawget(LUA_REGISTRYINDEX);
|
|
|
|
if(_state.type(-1) == LUA_TNIL) {
|
|
|
|
_state.pop(1);
|
|
|
|
_state.pushlightuserdata(this);
|
|
|
|
_state.newtable();
|
|
|
|
_state.pushvalue(-1);
|
|
|
|
_state.setmetatable(-2);
|
|
|
|
_state.pushstring("__gc");
|
|
|
|
_state.pushcfunction(&_class<T>::dogc);
|
|
|
|
_state.rawset(-3);
|
|
|
|
_state.pushstring("__newindex");
|
|
|
|
_state.pushcfunction(&_class<T>::newindex);
|
|
|
|
_state.rawset(-3);
|
|
|
|
_state.pushstring("__index");
|
|
|
|
_state.pushcfunction(&_class<T>::index);
|
|
|
|
_state.rawset(-3);
|
|
|
|
_state.rawset(LUA_REGISTRYINDEX);
|
2012-10-16 17:39:55 +03:00
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::string name;
|
2013-12-20 02:02:12 +02:00
|
|
|
_class(const _class<T>&);
|
|
|
|
_class& operator=(const _class<T>&);
|
2012-10-16 17:39:55 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function implemented in C++ exported to Lua.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
class function
|
2012-10-16 17:39:55 +03:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Register function.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
function(function_group& group, const std::string& name) throw(std::bad_alloc);
|
2012-10-16 17:39:55 +03:00
|
|
|
/**
|
|
|
|
* Unregister function.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
virtual ~function() throw();
|
2012-10-16 17:39:55 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Invoke function.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
virtual int invoke(state& L) = 0;
|
2012-10-16 17:39:55 +03:00
|
|
|
protected:
|
|
|
|
std::string fname;
|
2013-12-20 02:02:12 +02:00
|
|
|
function_group& group;
|
2012-10-16 17:39:55 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Register function pointer as lua function.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
class fnptr : public function
|
2012-10-16 17:39:55 +03:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Register.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
fnptr(function_group& group, const std::string& name,
|
|
|
|
int (*_fn)(state& L, const std::string& fname))
|
|
|
|
: function(group, name)
|
2012-10-16 17:39:55 +03:00
|
|
|
{
|
|
|
|
fn = _fn;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Invoke function.
|
|
|
|
*/
|
2013-12-20 02:02:12 +02:00
|
|
|
int invoke(state& L)
|
2012-10-16 17:39:55 +03:00
|
|
|
{
|
|
|
|
return fn(L, fname);
|
|
|
|
}
|
|
|
|
private:
|
2013-12-20 02:02:12 +02:00
|
|
|
int (*fn)(state& L, const std::string& fname);
|
2012-10-16 17:39:55 +03:00
|
|
|
};
|
2013-12-20 02:02:12 +02:00
|
|
|
}
|
2013-08-06 16:17:01 +03:00
|
|
|
|
2012-10-16 17:39:55 +03:00
|
|
|
#endif
|