Adrian Hedqvist
ec131d8bda
* Implemented lua using kaguya, only for config files for now * Moved color struct to its own header * statically link glew instead of including the source in the project * Other stuff that I don't remember
585 lines
18 KiB
C++
585 lines
18 KiB
C++
// Copyright satoren
|
|
// Distributed under the Boost Software License, Version 1.0. (See
|
|
// accompanying file LICENSE_1_0.txt or copy at
|
|
// http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
#pragma once
|
|
|
|
#include <vector>
|
|
#include <map>
|
|
#include <cassert>
|
|
#include <algorithm>
|
|
#include <ostream>
|
|
#include <istream>
|
|
|
|
#include "kaguya/config.hpp"
|
|
#include "kaguya/error_handler.hpp"
|
|
#include "kaguya/type.hpp"
|
|
#include "kaguya/utility.hpp"
|
|
#include "kaguya/detail/lua_ref_impl.hpp"
|
|
#include "kaguya/detail/lua_variant_def.hpp"
|
|
|
|
namespace kaguya {
|
|
namespace util {
|
|
template <class Result>
|
|
inline Result get_result_impl(lua_State *l, int startindex,
|
|
types::typetag<Result>) {
|
|
return lua_type_traits<Result>::get(l, startindex);
|
|
}
|
|
#if KAGUYA_USE_CPP11
|
|
inline standard::tuple<>
|
|
get_result_tuple_impl(lua_State *, int, types::typetag<standard::tuple<> >) {
|
|
return standard::tuple<>();
|
|
}
|
|
template <typename T, typename... TYPES>
|
|
inline standard::tuple<T, TYPES...>
|
|
get_result_tuple_impl(lua_State *l, int index,
|
|
types::typetag<standard::tuple<T, TYPES...> >) {
|
|
return standard::tuple_cat(
|
|
standard::tuple<T>(lua_type_traits<T>::get(l, index)),
|
|
get_result_tuple_impl(l, index + 1,
|
|
types::typetag<standard::tuple<TYPES...> >()));
|
|
}
|
|
template <typename... TYPES>
|
|
inline standard::tuple<TYPES...>
|
|
get_result_impl(lua_State *l, int startindex,
|
|
types::typetag<standard::tuple<TYPES...> > tag) {
|
|
return get_result_tuple_impl<TYPES...>(l, startindex, tag);
|
|
}
|
|
#else
|
|
|
|
inline standard::tuple<> get_result_impl(lua_State *l, int startindex,
|
|
types::typetag<standard::tuple<> >) {
|
|
KAGUYA_UNUSED(l);
|
|
KAGUYA_UNUSED(startindex);
|
|
return standard::tuple<>();
|
|
}
|
|
|
|
#define KAGUYA_GET_DEF(N) \
|
|
lua_type_traits<KAGUYA_PP_CAT(A, N)>::get(l, N + startindex - 1)
|
|
#define KAGUYA_GET_TUPLE_DEF(N) \
|
|
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
|
|
inline standard::tuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)> get_result_impl( \
|
|
lua_State *l, int startindex, \
|
|
types::typetag<standard::tuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)> >) { \
|
|
return standard::tuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)>( \
|
|
KAGUYA_PP_REPEAT_ARG(N, KAGUYA_GET_DEF)); \
|
|
}
|
|
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_TUPLE_SIZE, KAGUYA_GET_TUPLE_DEF)
|
|
#undef KAGUYA_GET_DEF
|
|
#undef KAGUYA_GET_TUPLE_DEF
|
|
#endif
|
|
|
|
template <class Result> inline Result get_result(lua_State *l, int startindex) {
|
|
return get_result_impl(l, startindex, types::typetag<Result>());
|
|
}
|
|
template <> inline void get_result<void>(lua_State *, int) {}
|
|
}
|
|
|
|
/// @addtogroup Lua_reference_types
|
|
|
|
/// @ingroup Lua_reference_types
|
|
/// @brief Reference to any Lua data.
|
|
class LuaRef : public Ref::RegistoryRef, public detail::LuaVariantImpl<LuaRef> {
|
|
private:
|
|
static lua_State *toMainThread(lua_State *state) {
|
|
#if LUA_VERSION_NUM >= 502
|
|
if (state) {
|
|
lua_rawgeti(state, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD);
|
|
lua_State *mainthread = lua_tothread(state, -1);
|
|
lua_pop(state, 1);
|
|
if (mainthread) {
|
|
return mainthread;
|
|
}
|
|
}
|
|
#endif
|
|
return state;
|
|
}
|
|
|
|
public:
|
|
LuaRef(const Ref::RegistoryRef &src) : Ref::RegistoryRef(src) {}
|
|
LuaRef(const LuaRef &src) : Ref::RegistoryRef(src) {}
|
|
LuaRef &operator=(const LuaRef &src) {
|
|
static_cast<RegistoryRef &>(*this) = src;
|
|
return *this;
|
|
}
|
|
|
|
#if KAGUYA_USE_CPP11
|
|
|
|
LuaRef(LuaRef &&src) : Ref::RegistoryRef(std::move(src)) {}
|
|
|
|
LuaRef &operator=(LuaRef &&src) throw() {
|
|
swap(src);
|
|
return *this;
|
|
}
|
|
|
|
LuaRef(RegistoryRef &&src) throw() : Ref::RegistoryRef(std::move(src)) {}
|
|
template <typename T>
|
|
LuaRef(lua_State *state, T &&v, Ref::NoMainCheck)
|
|
: Ref::RegistoryRef(state, std::move(v), Ref::NoMainCheck()) {}
|
|
template <typename T>
|
|
LuaRef(lua_State *state, T &&v) : Ref::RegistoryRef(state, std::move(v)) {}
|
|
#endif
|
|
|
|
LuaRef() {}
|
|
LuaRef(lua_State *state) : Ref::RegistoryRef(state) {}
|
|
|
|
LuaRef(lua_State *state, StackTop, Ref::NoMainCheck)
|
|
: Ref::RegistoryRef(state, StackTop(), Ref::NoMainCheck()) {}
|
|
|
|
LuaRef(lua_State *state, StackTop) : Ref::RegistoryRef(state, StackTop()) {}
|
|
|
|
template <typename T>
|
|
LuaRef(lua_State *state, const T &v, Ref::NoMainCheck)
|
|
: Ref::RegistoryRef(state, v, Ref::NoMainCheck()) {}
|
|
template <typename T>
|
|
LuaRef(lua_State *state, const T &v) : Ref::RegistoryRef(state, v) {}
|
|
|
|
const void *native_pointer() const {
|
|
util::ScopedSavedStack save(state());
|
|
push(state());
|
|
return lua_topointer(state(), -1);
|
|
}
|
|
static void putindent(std::ostream &os, int indent) {
|
|
while (indent-- > 0) {
|
|
os << " ";
|
|
}
|
|
}
|
|
};
|
|
|
|
/// @ingroup lua_type_traits
|
|
/// @brief lua_type_traits for LuaRef
|
|
template <> struct lua_type_traits<LuaRef> {
|
|
typedef LuaRef get_type;
|
|
typedef const LuaRef &push_type;
|
|
|
|
static bool checkType(lua_State *l, int index) {
|
|
KAGUYA_UNUSED(l);
|
|
KAGUYA_UNUSED(index);
|
|
return true;
|
|
}
|
|
static bool strictCheckType(lua_State *l, int index) {
|
|
KAGUYA_UNUSED(l);
|
|
KAGUYA_UNUSED(index);
|
|
return false;
|
|
}
|
|
|
|
static get_type get(lua_State *l, int index) {
|
|
lua_pushvalue(l, index);
|
|
return LuaRef(l, StackTop());
|
|
}
|
|
static int push(lua_State *l, push_type v) { return v.push(l); }
|
|
};
|
|
/// @ingroup lua_type_traits
|
|
/// @brief lua_type_traits for LuaRef
|
|
template <> struct lua_type_traits<const LuaRef &> : lua_type_traits<LuaRef> {};
|
|
|
|
class LuaStackRef : public Ref::StackRef,
|
|
public detail::LuaVariantImpl<LuaStackRef> {
|
|
public:
|
|
LuaStackRef() : Ref::StackRef() {}
|
|
LuaStackRef(lua_State *s, int index) : Ref::StackRef(s, index, false) {}
|
|
LuaStackRef(lua_State *s, int index, bool popAtDestruct)
|
|
: Ref::StackRef(s, index, popAtDestruct) {}
|
|
#if KAGUYA_USE_CPP11
|
|
LuaStackRef(LuaStackRef &&src) : Ref::StackRef(std::move(src)) {
|
|
src.pop_ = false;
|
|
}
|
|
LuaStackRef &operator=(LuaStackRef &&src) {
|
|
if (this != &src) {
|
|
Ref::StackRef::operator=(std::move(src));
|
|
src.pop_ = false;
|
|
}
|
|
return *this;
|
|
}
|
|
LuaStackRef(const LuaStackRef &src) = delete;
|
|
#else
|
|
LuaStackRef(const LuaStackRef &src) : Ref::StackRef(src) { src.pop_ = false; }
|
|
LuaStackRef &operator=(const LuaStackRef &src) {
|
|
if (this != &src) {
|
|
Ref::StackRef::operator=(src);
|
|
src.pop_ = false;
|
|
}
|
|
return *this;
|
|
}
|
|
#endif
|
|
};
|
|
|
|
/// @ingroup lua_type_traits
|
|
/// @brief lua_type_traits for LuaStackRef
|
|
template <> struct lua_type_traits<LuaStackRef> {
|
|
typedef LuaStackRef get_type;
|
|
typedef const LuaStackRef &push_type;
|
|
|
|
static bool checkType(lua_State *l, int index) {
|
|
KAGUYA_UNUSED(l);
|
|
KAGUYA_UNUSED(index);
|
|
return true;
|
|
}
|
|
static bool strictCheckType(lua_State *l, int index) {
|
|
KAGUYA_UNUSED(l);
|
|
KAGUYA_UNUSED(index);
|
|
return false;
|
|
}
|
|
|
|
static get_type get(lua_State *l, int index) { return LuaStackRef(l, index); }
|
|
static int push(lua_State *l, push_type v) { return v.push(l); }
|
|
};
|
|
/// @ingroup lua_type_traits
|
|
/// @brief lua_type_traits for LuaStackRef
|
|
template <>
|
|
struct lua_type_traits<const LuaStackRef &> : lua_type_traits<LuaStackRef> {};
|
|
|
|
/// @ingroup Lua_reference_types
|
|
/// @brief Reference to Lua userdata.
|
|
class LuaUserData : public Ref::RegistoryRef,
|
|
public detail::LuaUserDataImpl<LuaUserData>,
|
|
public detail::LuaTableOrUserDataImpl<LuaUserData>,
|
|
public detail::LuaBasicTypeFunctions<LuaUserData> {
|
|
|
|
void typecheck() {
|
|
int t = type();
|
|
if (t != TYPE_USERDATA && t != TYPE_LIGHTUSERDATA && t != TYPE_NIL &&
|
|
t != TYPE_NONE) {
|
|
except::typeMismatchError(state(), "not user data");
|
|
unref();
|
|
}
|
|
}
|
|
|
|
public:
|
|
operator LuaRef() {
|
|
push(state());
|
|
return LuaRef(state(), StackTop());
|
|
}
|
|
LuaUserData(lua_State *state, StackTop)
|
|
: Ref::RegistoryRef(state, StackTop()) {
|
|
typecheck();
|
|
}
|
|
template <typename TYPE>
|
|
LuaUserData(lua_State *state, const TYPE &table)
|
|
: Ref::RegistoryRef(state, table) {
|
|
typecheck();
|
|
}
|
|
explicit LuaUserData(lua_State *state)
|
|
: Ref::RegistoryRef(state, NilValue()) {
|
|
typecheck();
|
|
}
|
|
LuaUserData() { typecheck(); }
|
|
};
|
|
|
|
/// @ingroup lua_type_traits
|
|
/// @brief lua_type_traits for LuaUserData
|
|
template <> struct lua_type_traits<LuaUserData> {
|
|
typedef LuaUserData get_type;
|
|
typedef LuaUserData push_type;
|
|
|
|
static bool strictCheckType(lua_State *l, int index) {
|
|
return lua_type(l, index) == LUA_TUSERDATA;
|
|
}
|
|
static bool checkType(lua_State *l, int index) {
|
|
return lua_type(l, index) == LUA_TUSERDATA || lua_isnil(l, index);
|
|
}
|
|
static LuaUserData get(lua_State *l, int index) {
|
|
lua_pushvalue(l, index);
|
|
return LuaUserData(l, StackTop());
|
|
}
|
|
static int push(lua_State *l, const LuaUserData &ref) { return ref.push(l); }
|
|
};
|
|
/// @ingroup lua_type_traits
|
|
/// @brief lua_type_traits for LuaUserData
|
|
template <>
|
|
struct lua_type_traits<const LuaUserData &> : lua_type_traits<LuaUserData> {};
|
|
|
|
/// @ingroup Lua_reference_types
|
|
/// @brief Reference to Lua table.
|
|
class LuaTable : public Ref::RegistoryRef,
|
|
public detail::LuaTableImpl<LuaTable>,
|
|
public detail::LuaTableOrUserDataImpl<LuaTable>,
|
|
public detail::LuaBasicTypeFunctions<LuaTable> {
|
|
|
|
void typecheck() {
|
|
int t = type();
|
|
if (t != TYPE_TABLE && t != TYPE_NIL && t != TYPE_NONE) {
|
|
except::typeMismatchError(state(), "not table");
|
|
unref();
|
|
}
|
|
}
|
|
|
|
public:
|
|
operator LuaRef() {
|
|
push(state());
|
|
return LuaRef(state(), StackTop());
|
|
}
|
|
LuaTable(lua_State *state, StackTop) : Ref::RegistoryRef(state, StackTop()) {
|
|
typecheck();
|
|
}
|
|
LuaTable(lua_State *state, const NewTable &table)
|
|
: Ref::RegistoryRef(state, table) {
|
|
typecheck();
|
|
}
|
|
explicit LuaTable(lua_State *state) : Ref::RegistoryRef(state, NewTable()) {
|
|
typecheck();
|
|
}
|
|
LuaTable() { typecheck(); }
|
|
};
|
|
|
|
/// @ingroup lua_type_traits
|
|
/// @brief lua_type_traits for LuaTable
|
|
template <> struct lua_type_traits<LuaTable> {
|
|
typedef LuaTable get_type;
|
|
typedef LuaTable push_type;
|
|
|
|
static bool strictCheckType(lua_State *l, int index) {
|
|
return lua_istable(l, index);
|
|
}
|
|
static bool checkType(lua_State *l, int index) {
|
|
return lua_istable(l, index) || lua_isnil(l, index);
|
|
}
|
|
static LuaTable get(lua_State *l, int index) {
|
|
lua_pushvalue(l, index);
|
|
return LuaTable(l, StackTop());
|
|
}
|
|
static int push(lua_State *l, const LuaTable &ref) { return ref.push(l); }
|
|
};
|
|
/// @ingroup lua_type_traits
|
|
/// @brief lua_type_traits for LuaTable
|
|
template <>
|
|
struct lua_type_traits<const LuaTable &> : lua_type_traits<LuaTable> {};
|
|
|
|
/// @ingroup Lua_reference_types
|
|
/// @brief Reference to Lua function.
|
|
class LuaFunction : public Ref::RegistoryRef,
|
|
public detail::LuaFunctionImpl<LuaFunction>,
|
|
public detail::LuaBasicTypeFunctions<LuaFunction> {
|
|
void typecheck() {
|
|
int t = type();
|
|
if (t != TYPE_FUNCTION && t != TYPE_NIL && t != TYPE_NONE) {
|
|
except::typeMismatchError(state(), "not function");
|
|
RegistoryRef::unref();
|
|
}
|
|
}
|
|
|
|
struct LuaLoadStreamWrapper {
|
|
LuaLoadStreamWrapper(std::istream &stream)
|
|
: preloaded_(false), stream_(stream) {
|
|
buffer_.reserve(512);
|
|
skipComment();
|
|
preloaded_ = !buffer_.empty();
|
|
}
|
|
|
|
void skipComment() {
|
|
// skip bom
|
|
const char *bom = "\xEF\xBB\xBF";
|
|
const char *bomseq = bom;
|
|
char c;
|
|
while (stream_.get(c)) {
|
|
if (c != *bomseq) // not bom sequence
|
|
{
|
|
buffer_.assign(bom, bomseq);
|
|
buffer_.push_back(c);
|
|
break;
|
|
}
|
|
bomseq++;
|
|
if ('\0' == *bomseq) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// skip comment
|
|
if (!buffer_.empty() && buffer_.front() == '#') {
|
|
buffer_.clear();
|
|
std::string comment;
|
|
std::getline(stream_, comment);
|
|
}
|
|
}
|
|
|
|
static const char *getdata(lua_State *, void *ud, size_t *size) {
|
|
LuaLoadStreamWrapper *loader = static_cast<LuaLoadStreamWrapper *>(ud);
|
|
|
|
if (loader->preloaded_) {
|
|
loader->preloaded_ = false;
|
|
} else {
|
|
loader->buffer_.clear();
|
|
}
|
|
|
|
char c = 0;
|
|
while (loader->buffer_.size() < loader->buffer_.capacity() &&
|
|
loader->stream_.get(c)) {
|
|
loader->buffer_.push_back(c);
|
|
}
|
|
*size = loader->buffer_.size();
|
|
return loader->buffer_.empty() ? 0 : &loader->buffer_[0];
|
|
}
|
|
|
|
private:
|
|
bool preloaded_;
|
|
std::vector<char> buffer_;
|
|
std::istream &stream_;
|
|
};
|
|
|
|
public:
|
|
/// @brief construct with state and function .
|
|
/// @param state pointer to lua_State
|
|
/// @param f execute function for lua thread. e.g.
|
|
/// kaguya::function(function_ptr),kaguya::overload(function_ptr)
|
|
template <typename F>
|
|
LuaFunction(lua_State *state, F f) : Ref::RegistoryRef(state, f) {
|
|
typecheck();
|
|
}
|
|
|
|
/// @brief construct with stack top value.
|
|
/// @param state pointer to lua_State
|
|
LuaFunction(lua_State *state, StackTop)
|
|
: Ref::RegistoryRef(state, StackTop()) {
|
|
typecheck();
|
|
}
|
|
|
|
/// @brief construct with nil reference.
|
|
LuaFunction() {}
|
|
|
|
/// @brief load lua code .
|
|
/// @param state pointer to lua_State
|
|
/// @param luacode string
|
|
static LuaFunction loadstring(lua_State *state, const std::string &luacode) {
|
|
return loadstring(state, luacode.c_str());
|
|
}
|
|
/// @brief load lua code .
|
|
/// @param state pointer to lua_State
|
|
/// @param luacode string
|
|
static LuaFunction loadstring(lua_State *state, const char *luacode) {
|
|
util::ScopedSavedStack save(state);
|
|
int status = luaL_loadstring(state, luacode);
|
|
|
|
if (status) {
|
|
ErrorHandler::handle(status, state);
|
|
lua_pushnil(state);
|
|
}
|
|
return LuaFunction(state, StackTop());
|
|
}
|
|
|
|
/// @brief If there are no errors,compiled file as a Lua function and return.
|
|
/// Otherwise send error message to error handler and return nil reference
|
|
/// @param state pointer to lua_State
|
|
/// @param file file path of lua script
|
|
/// @return reference of lua function
|
|
static LuaFunction loadfile(lua_State *state, const std::string &file) {
|
|
return loadfile(state, file.c_str());
|
|
}
|
|
|
|
/// @brief If there are no errors,compiled file as a Lua function and return.
|
|
/// Otherwise send error message to error handler and return nil reference
|
|
/// @param state pointer to lua_State
|
|
/// @param file file path of lua script
|
|
/// @return reference of lua function
|
|
static LuaFunction loadfile(lua_State *state, const char *file) {
|
|
util::ScopedSavedStack save(state);
|
|
|
|
int status = luaL_loadfile(state, file);
|
|
|
|
if (status) {
|
|
ErrorHandler::handle(status, state);
|
|
lua_pushnil(state);
|
|
}
|
|
return LuaFunction(state, StackTop());
|
|
}
|
|
|
|
/// @brief If there are no errors,compiled stream as a Lua function and
|
|
/// return.
|
|
/// Otherwise send error message to error handler and return nil reference
|
|
/// @param state pointer to lua_State
|
|
/// @param stream stream of lua script data
|
|
/// @param chunkname use for error message.
|
|
/// @return reference of lua function
|
|
static LuaStackRef loadstreamtostack(lua_State *state, std::istream &stream,
|
|
const char *chunkname = 0) {
|
|
LuaLoadStreamWrapper wrapper(stream);
|
|
#if LUA_VERSION_NUM >= 502
|
|
int status =
|
|
lua_load(state, &LuaLoadStreamWrapper::getdata, &wrapper, chunkname, 0);
|
|
#else
|
|
int status =
|
|
lua_load(state, &LuaLoadStreamWrapper::getdata, &wrapper, chunkname);
|
|
#endif
|
|
if (status) {
|
|
ErrorHandler::handle(status, state);
|
|
lua_pushnil(state);
|
|
}
|
|
return LuaStackRef(state, -1, true);
|
|
}
|
|
|
|
/// @brief If there are no errors,compiled stream as a Lua function and
|
|
/// return.
|
|
/// Otherwise send error message to error handler and return nil reference
|
|
/// @param state pointer to lua_State
|
|
/// @param stream stream of lua script data
|
|
/// @param chunkname use for error message.
|
|
/// @return reference of lua function
|
|
static LuaFunction loadstream(lua_State *state, std::istream &stream,
|
|
const char *chunkname = 0) {
|
|
util::ScopedSavedStack save(state);
|
|
LuaLoadStreamWrapper wrapper(stream);
|
|
#if LUA_VERSION_NUM >= 502
|
|
int status =
|
|
lua_load(state, &LuaLoadStreamWrapper::getdata, &wrapper, chunkname, 0);
|
|
#else
|
|
int status =
|
|
lua_load(state, &LuaLoadStreamWrapper::getdata, &wrapper, chunkname);
|
|
#endif
|
|
if (status) {
|
|
ErrorHandler::handle(status, state);
|
|
lua_pushnil(state);
|
|
}
|
|
return LuaFunction(state, StackTop());
|
|
}
|
|
};
|
|
|
|
/// @ingroup Lua_reference_types
|
|
/// @brief Reference to Lua thread(coroutine).
|
|
class LuaThread : public Ref::RegistoryRef,
|
|
public detail::LuaThreadImpl<LuaThread>,
|
|
public detail::LuaBasicTypeFunctions<LuaThread> {
|
|
void typecheck() {
|
|
int t = type();
|
|
if (t != TYPE_THREAD && t != TYPE_NIL && t != TYPE_NONE) {
|
|
except::typeMismatchError(state(), "not lua thread");
|
|
RegistoryRef::unref();
|
|
}
|
|
}
|
|
|
|
public:
|
|
/// @brief construct with stack top value.
|
|
LuaThread(lua_State *state, StackTop) : Ref::RegistoryRef(state, StackTop()) {
|
|
typecheck();
|
|
}
|
|
/// @brief construct with new thread.
|
|
LuaThread(lua_State *state, const NewThread &t)
|
|
: Ref::RegistoryRef(state, t) {}
|
|
/// @brief construct with nil reference.
|
|
LuaThread(lua_State *state) : Ref::RegistoryRef(state, NewThread()) {}
|
|
/// @brief construct with nil reference.
|
|
LuaThread() {}
|
|
/// @brief get lua thread
|
|
operator lua_State *() { return getthread(); }
|
|
};
|
|
}
|
|
|
|
#if KAGUYA_USE_CPP11
|
|
#else
|
|
namespace std {
|
|
template <> inline void swap(kaguya::LuaUserData &a, kaguya::LuaUserData &b) {
|
|
a.swap(b);
|
|
}
|
|
template <> inline void swap(kaguya::LuaTable &a, kaguya::LuaTable &b) {
|
|
a.swap(b);
|
|
}
|
|
template <> inline void swap(kaguya::LuaFunction &a, kaguya::LuaFunction &b) {
|
|
a.swap(b);
|
|
}
|
|
template <> inline void swap(kaguya::LuaThread &a, kaguya::LuaThread &b) {
|
|
a.swap(b);
|
|
}
|
|
template <> inline void swap(kaguya::LuaRef &a, kaguya::LuaRef &b) {
|
|
a.swap(b);
|
|
}
|
|
}
|
|
#endif
|