diff options
Diffstat (limited to 'state.cpp')
| -rw-r--r-- | state.cpp | 904 |
1 files changed, 904 insertions, 0 deletions
diff --git a/state.cpp b/state.cpp new file mode 100644 index 000000000000..3c140388e0cb --- /dev/null +++ b/state.cpp @@ -0,0 +1,904 @@ +// Copyright 2011 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +extern "C" { +#include <unistd.h> +} + +#include <cassert> +#include <cstring> + +#include "c_gate.hpp" +#include "exceptions.hpp" +#include "state.ipp" + + +namespace { + + +/// Wrapper around lua_getglobal to run in a protected environment. +/// +/// \pre stack(-1) is the name of the global to get. +/// \post stack(-1) is the value of the global. +/// +/// \param state The Lua C API state. +/// +/// \return The number of return values pushed onto the stack. +static int +protected_getglobal(lua_State* state) +{ + lua_getglobal(state, lua_tostring(state, -1)); + return 1; +} + + +/// Wrapper around lua_gettable to run in a protected environment. +/// +/// \pre stack(-2) is the table to get the element from. +/// \pre stack(-1) is the table index. +/// \post stack(-1) is the value of stack(-2)[stack(-1)]. +/// +/// \param state The Lua C API state. +/// +/// \return The number of return values pushed onto the stack. +static int +protected_gettable(lua_State* state) +{ + lua_gettable(state, -2); + return 1; +} + + +/// Wrapper around lua_next to run in a protected environment. +/// +/// \pre stack(-2) is the table to get the next element from. +/// \pre stack(-1) is the last processed key. +/// \post stack(-1) is the value of next(stack(-2), stack(-1)). +/// +/// \param state The Lua C API state. +/// +/// \return The number of return values pushed onto the stack. +static int +protected_next(lua_State* state) +{ + const int more = lua_next(state, -2) != 0; + lua_pushboolean(state, more); + return more ? 3 : 1; +} + + +/// Wrapper around lua_setglobal to run in a protected environment. +/// +/// \pre stack(-2) is the name of the global to set. +/// \pre stack(-1) is the value to set the global to. +/// +/// \param state The Lua C API state. +/// +/// \return The number of return values pushed onto the stack. +static int +protected_setglobal(lua_State* state) +{ + lua_setglobal(state, lua_tostring(state, -2)); + return 0; +} + + +/// Wrapper around lua_settable to run in a protected environment. +/// +/// \pre stack(-3) is the table to set the element into. +/// \pre stack(-2) is the table index. +/// \pre stack(-1) is the value to set. +/// +/// \param state The Lua C API state. +/// +/// \return The number of return values pushed onto the stack. +static int +protected_settable(lua_State* state) +{ + lua_settable(state, -3); + return 0; +} + + +/// Calls a C++ Lua function from a C calling environment. +/// +/// Any errors reported by the C++ function are caught and reported to the +/// caller as Lua errors. +/// +/// \param function The C++ function to call. +/// \param raw_state The raw Lua state. +/// +/// \return The number of return values pushed onto the Lua stack by the +/// function. +static int +call_cxx_function_from_c(lutok::cxx_function function, + lua_State* raw_state) throw() +{ + char error_buf[1024]; + + try { + lutok::state state = lutok::state_c_gate::connect(raw_state); + return function(state); + } catch (const std::exception& e) { + std::strncpy(error_buf, e.what(), sizeof(error_buf)); + } catch (...) { + std::strncpy(error_buf, "Unhandled exception in Lua C++ hook", + sizeof(error_buf)); + } + error_buf[sizeof(error_buf) - 1] = '\0'; + // We raise the Lua error from outside the try/catch context and we use + // a stack-based buffer to hold the message to ensure that we do not leak + // any C++ objects (and, as a likely result, memory) when Lua performs its + // longjmp. + return luaL_error(raw_state, "%s", error_buf); +} + + +/// Lua glue to call a C++ closure. +/// +/// This Lua binding is actually a closure that we have constructed from the +/// state.push_cxx_closure() method. The closure contains the same upvalues +/// provided by the user plus an extra upvalue that contains the address of the +/// C++ function we have to call. All we do here is safely delegate the +/// execution to the wrapped C++ closure. +/// +/// \param raw_state The Lua C API state. +/// +/// \return The number of return values of the called closure. +static int +cxx_closure_trampoline(lua_State* raw_state) +{ + lutok::state state = lutok::state_c_gate::connect(raw_state); + + int nupvalues; + { + lua_Debug debug; + lua_getstack(raw_state, 0, &debug); + lua_getinfo(raw_state, "u", &debug); + nupvalues = debug.nups; + } + + lutok::cxx_function* function = state.to_userdata< lutok::cxx_function >( + state.upvalue_index(nupvalues)); + return call_cxx_function_from_c(*function, raw_state); +} + + +/// Lua glue to call a C++ function. +/// +/// This Lua binding is actually a closure that we have constructed from the +/// state.push_cxx_function() method. The closure has a single upvalue that +/// contains the address of the C++ function we have to call. All we do here is +/// safely delegate the execution to the wrapped C++ function. +/// +/// \param raw_state The Lua C API state. +/// +/// \return The number of return values of the called function. +static int +cxx_function_trampoline(lua_State* raw_state) +{ + lutok::state state = lutok::state_c_gate::connect(raw_state); + lutok::cxx_function* function = state.to_userdata< lutok::cxx_function >( + state.upvalue_index(1)); + return call_cxx_function_from_c(*function, raw_state); +} + + +} // anonymous namespace + + +const int lutok::registry_index = LUA_REGISTRYINDEX; + + +/// Internal implementation for lutok::state. +struct lutok::state::impl { + /// The Lua internal state. + lua_State* lua_state; + + /// Whether we own the state or not (to decide if we close it). + bool owned; + + /// Constructor. + /// + /// \param lua_ The Lua internal state. + /// \param owned_ Whether we own the state or not. + impl(lua_State* lua_, bool owned_) : + lua_state(lua_), + owned(owned_) + { + } +}; + + +/// Initializes the Lua state. +/// +/// You must share the same state object alongside the lifetime of your Lua +/// session. As soon as the object is destroyed, the session is terminated. +lutok::state::state(void) +{ + lua_State* lua = luaL_newstate(); + if (lua == NULL) + throw lutok::error("lua open failed"); + _pimpl.reset(new impl(lua, true)); +} + + +/// Initializes the Lua state from an existing raw state. +/// +/// Instances constructed using this method do NOT own the raw state. This +/// means that, on exit, the state will not be destroyed. +/// +/// \param raw_state_ The raw Lua state to wrap. +lutok::state::state(void* raw_state_) : + _pimpl(new impl(reinterpret_cast< lua_State* >(raw_state_), false)) +{ +} + + +/// Destructor for the Lua state. +/// +/// Closes the session unless it has already been closed by calling the +/// close() method. It is recommended to explicitly close the session in the +/// code. +lutok::state::~state(void) +{ + if (_pimpl->owned && _pimpl->lua_state != NULL) + close(); +} + + +/// Terminates this Lua session. +/// +/// It is recommended to call this instead of relying on the destructor to do +/// the cleanup, but it is not a requirement to use close(). +/// +/// \pre close() has not yet been called. +/// \pre The Lua stack is empty. This is not truly necessary but ensures that +/// our code is consistent and clears the stack explicitly. +void +lutok::state::close(void) +{ + assert(_pimpl->lua_state != NULL); + assert(lua_gettop(_pimpl->lua_state) == 0); + lua_close(_pimpl->lua_state); + _pimpl->lua_state = NULL; +} + + +/// Wrapper around lua_getglobal. +/// +/// \param name The second parameter to lua_getglobal. +/// +/// \throw api_error If lua_getglobal fails. +/// +/// \warning Terminates execution if there is not enough memory to manipulate +/// the Lua stack. +void +lutok::state::get_global(const std::string& name) +{ + lua_pushcfunction(_pimpl->lua_state, protected_getglobal); + lua_pushstring(_pimpl->lua_state, name.c_str()); + if (lua_pcall(_pimpl->lua_state, 1, 1, 0) != 0) + throw lutok::api_error::from_stack(*this, "lua_getglobal"); +} + + +/// Pushes a reference to the global table onto the stack. +/// +/// This is a wrapper around the incompatible differences between Lua 5.1 and +/// 5.2 to access to the globals table. +/// +/// \post state(-1) Contains the reference to the globals table. +void +lutok::state::get_global_table(void) +{ +#if LUA_VERSION_NUM >= 502 + lua_pushvalue(_pimpl->lua_state, registry_index); + lua_pushinteger(_pimpl->lua_state, LUA_RIDX_GLOBALS); + lua_gettable(_pimpl->lua_state, -2); + lua_remove(_pimpl->lua_state, -2); +#else + lua_pushvalue(_pimpl->lua_state, LUA_GLOBALSINDEX); +#endif +} + + +/// Wrapper around luaL_getmetafield. +/// +/// \param index The second parameter to luaL_getmetafield. +/// \param name The third parameter to luaL_getmetafield. +/// +/// \return The return value of luaL_getmetafield. +/// +/// \warning Terminates execution if there is not enough memory to manipulate +/// the Lua stack. +bool +lutok::state::get_metafield(const int index, const std::string& name) +{ + return luaL_getmetafield(_pimpl->lua_state, index, name.c_str()) != 0; +} + + +/// Wrapper around lua_getmetatable. +/// +/// \param index The second parameter to lua_getmetatable. +/// +/// \return The return value of lua_getmetatable. +bool +lutok::state::get_metatable(const int index) +{ + return lua_getmetatable(_pimpl->lua_state, index) != 0; +} + + +/// Wrapper around lua_gettable. +/// +/// \param index The second parameter to lua_gettable. +/// +/// \throw api_error If lua_gettable fails. +/// +/// \warning Terminates execution if there is not enough memory to manipulate +/// the Lua stack. +void +lutok::state::get_table(const int index) +{ + assert(lua_gettop(_pimpl->lua_state) >= 2); + lua_pushcfunction(_pimpl->lua_state, protected_gettable); + lua_pushvalue(_pimpl->lua_state, index < 0 ? index - 1 : index); + lua_pushvalue(_pimpl->lua_state, -3); + if (lua_pcall(_pimpl->lua_state, 2, 1, 0) != 0) + throw lutok::api_error::from_stack(*this, "lua_gettable"); + lua_remove(_pimpl->lua_state, -2); +} + + +/// Wrapper around lua_gettop. +/// +/// \return The return value of lua_gettop. +int +lutok::state::get_top(void) +{ + return lua_gettop(_pimpl->lua_state); +} + + +/// Wrapper around lua_insert. +/// +/// \param index The second parameter to lua_insert. +void +lutok::state::insert(const int index) +{ + lua_insert(_pimpl->lua_state, index); +} + + +/// Wrapper around lua_isboolean. +/// +/// \param index The second parameter to lua_isboolean. +/// +/// \return The return value of lua_isboolean. +bool +lutok::state::is_boolean(const int index) +{ + return lua_isboolean(_pimpl->lua_state, index); +} + + +/// Wrapper around lua_isfunction. +/// +/// \param index The second parameter to lua_isfunction. +/// +/// \return The return value of lua_isfunction. +bool +lutok::state::is_function(const int index) +{ + return lua_isfunction(_pimpl->lua_state, index); +} + + +/// Wrapper around lua_isnil. +/// +/// \param index The second parameter to lua_isnil. +/// +/// \return The return value of lua_isnil. +bool +lutok::state::is_nil(const int index) +{ + return lua_isnil(_pimpl->lua_state, index); +} + + +/// Wrapper around lua_isnumber. +/// +/// \param index The second parameter to lua_isnumber. +/// +/// \return The return value of lua_isnumber. +bool +lutok::state::is_number(const int index) +{ + return lua_isnumber(_pimpl->lua_state, index); +} + + +/// Wrapper around lua_isstring. +/// +/// \param index The second parameter to lua_isstring. +/// +/// \return The return value of lua_isstring. +bool +lutok::state::is_string(const int index) +{ + return lua_isstring(_pimpl->lua_state, index); +} + + +/// Wrapper around lua_istable. +/// +/// \param index The second parameter to lua_istable. +/// +/// \return The return value of lua_istable. +bool +lutok::state::is_table(const int index) +{ + return lua_istable(_pimpl->lua_state, index); +} + + +/// Wrapper around lua_isuserdata. +/// +/// \param index The second parameter to lua_isuserdata. +/// +/// \return The return value of lua_isuserdata. +bool +lutok::state::is_userdata(const int index) +{ + return lua_isuserdata(_pimpl->lua_state, index); +} + + +/// Wrapper around luaL_loadfile. +/// +/// \param file The second parameter to luaL_loadfile. +/// +/// \throw api_error If luaL_loadfile returns an error. +/// \throw file_not_found_error If the file cannot be accessed. +/// +/// \warning Terminates execution if there is not enough memory. +void +lutok::state::load_file(const std::string& file) +{ + if (::access(file.c_str(), R_OK) == -1) + throw lutok::file_not_found_error(file); + if (luaL_loadfile(_pimpl->lua_state, file.c_str()) != 0) + throw lutok::api_error::from_stack(*this, "luaL_loadfile"); +} + + +/// Wrapper around luaL_loadstring. +/// +/// \param str The second parameter to luaL_loadstring. +/// +/// \throw api_error If luaL_loadstring returns an error. +/// +/// \warning Terminates execution if there is not enough memory. +void +lutok::state::load_string(const std::string& str) +{ + if (luaL_loadstring(_pimpl->lua_state, str.c_str()) != 0) + throw lutok::api_error::from_stack(*this, "luaL_loadstring"); +} + + +/// Wrapper around lua_newtable. +/// +/// \warning Terminates execution if there is not enough memory. +void +lutok::state::new_table(void) +{ + lua_newtable(_pimpl->lua_state); +} + + +/// Wrapper around lua_newuserdata. +/// +/// This is internal. The public type-safe interface of this method should be +/// used instead. +/// +/// \param size The second parameter to lua_newuserdata. +/// +/// \return The return value of lua_newuserdata. +/// +/// \warning Terminates execution if there is not enough memory. +void* +lutok::state::new_userdata_voidp(const size_t size) +{ + return lua_newuserdata(_pimpl->lua_state, size); +} + + +/// Wrapper around lua_next. +/// +/// \param index The second parameter to lua_next. +/// +/// \return True if there are more elements to process; false otherwise. +/// +/// \warning Terminates execution if there is not enough memory. +bool +lutok::state::next(const int index) +{ + assert(lua_istable(_pimpl->lua_state, index)); + assert(lua_gettop(_pimpl->lua_state) >= 1); + lua_pushcfunction(_pimpl->lua_state, protected_next); + lua_pushvalue(_pimpl->lua_state, index < 0 ? index - 1 : index); + lua_pushvalue(_pimpl->lua_state, -3); + if (lua_pcall(_pimpl->lua_state, 2, LUA_MULTRET, 0) != 0) + throw lutok::api_error::from_stack(*this, "lua_next"); + const bool more = lua_toboolean(_pimpl->lua_state, -1); + lua_pop(_pimpl->lua_state, 1); + if (more) + lua_remove(_pimpl->lua_state, -3); + else + lua_pop(_pimpl->lua_state, 1); + return more; +} + + +/// Wrapper around luaL_openlibs. +/// +/// \throw api_error If luaL_openlibs fails. +/// +/// \warning Terminates execution if there is not enough memory. +void +lutok::state::open_all(void) +{ + luaL_openlibs(_pimpl->lua_state); +} + + +/// Wrapper around luaopen_base. +/// +/// \throw api_error If luaopen_base fails. +/// +/// \warning Terminates execution if there is not enough memory. +void +lutok::state::open_base(void) +{ + lua_pushcfunction(_pimpl->lua_state, luaopen_base); + if (lua_pcall(_pimpl->lua_state, 0, 0, 0) != 0) + throw lutok::api_error::from_stack(*this, "luaopen_base"); +} + + +/// Wrapper around luaopen_string. +/// +/// \throw api_error If luaopen_string fails. +/// +/// \warning Terminates execution if there is not enough memory. +void +lutok::state::open_string(void) +{ +#if LUA_VERSION_NUM >= 502 + luaL_requiref(_pimpl->lua_state, LUA_STRLIBNAME, luaopen_string, 1); + lua_pop(_pimpl->lua_state, 1); +#else + lua_pushcfunction(_pimpl->lua_state, luaopen_string); + if (lua_pcall(_pimpl->lua_state, 0, 0, 0) != 0) + throw lutok::api_error::from_stack(*this, "luaopen_string"); +#endif +} + + +/// Wrapper around luaopen_table. +/// +/// \throw api_error If luaopen_table fails. +/// +/// \warning Terminates execution if there is not enough memory. +void +lutok::state::open_table(void) +{ +#if LUA_VERSION_NUM >= 502 + luaL_requiref(_pimpl->lua_state, LUA_TABLIBNAME, luaopen_table, 1); + lua_pop(_pimpl->lua_state, 1); +#else + lua_pushcfunction(_pimpl->lua_state, luaopen_table); + if (lua_pcall(_pimpl->lua_state, 0, 0, 0) != 0) + throw lutok::api_error::from_stack(*this, "luaopen_table"); +#endif +} + + +/// Wrapper around lua_pcall. +/// +/// \param nargs The second parameter to lua_pcall. +/// \param nresults The third parameter to lua_pcall. +/// \param errfunc The fourth parameter to lua_pcall. +/// +/// \throw api_error If lua_pcall returns an error. +void +lutok::state::pcall(const int nargs, const int nresults, const int errfunc) +{ + if (lua_pcall(_pimpl->lua_state, nargs, nresults, errfunc) != 0) + throw lutok::api_error::from_stack(*this, "lua_pcall"); +} + + +/// Wrapper around lua_pop. +/// +/// \param count The second parameter to lua_pop. +void +lutok::state::pop(const int count) +{ + assert(count <= lua_gettop(_pimpl->lua_state)); + lua_pop(_pimpl->lua_state, count); + assert(lua_gettop(_pimpl->lua_state) >= 0); +} + + +/// Wrapper around lua_pushboolean. +/// +/// \param value The second parameter to lua_pushboolean. +void +lutok::state::push_boolean(const bool value) +{ + lua_pushboolean(_pimpl->lua_state, value ? 1 : 0); +} + + +/// Wrapper around lua_pushcclosure. +/// +/// This is not a pure wrapper around lua_pushcclosure because this has to do +/// extra magic to allow passing C++ functions instead of plain C functions. +/// +/// \param function The C++ function to be pushed as a closure. +/// \param nvalues The number of upvalues that the function receives. +void +lutok::state::push_cxx_closure(cxx_function function, const int nvalues) +{ + cxx_function *data = static_cast< cxx_function* >( + lua_newuserdata(_pimpl->lua_state, sizeof(cxx_function))); + *data = function; + lua_pushcclosure(_pimpl->lua_state, cxx_closure_trampoline, nvalues + 1); +} + + +/// Wrapper around lua_pushcfunction. +/// +/// This is not a pure wrapper around lua_pushcfunction because this has to do +/// extra magic to allow passing C++ functions instead of plain C functions. +/// +/// \param function The C++ function to be pushed. +void +lutok::state::push_cxx_function(cxx_function function) +{ + cxx_function *data = static_cast< cxx_function* >( + lua_newuserdata(_pimpl->lua_state, sizeof(cxx_function))); + *data = function; + lua_pushcclosure(_pimpl->lua_state, cxx_function_trampoline, 1); +} + + +/// Wrapper around lua_pushinteger. +/// +/// \param value The second parameter to lua_pushinteger. +void +lutok::state::push_integer(const int value) +{ + lua_pushinteger(_pimpl->lua_state, value); +} + + +/// Wrapper around lua_pushnil. +void +lutok::state::push_nil(void) +{ + lua_pushnil(_pimpl->lua_state); +} + + +/// Wrapper around lua_pushstring. +/// +/// \param str The second parameter to lua_pushstring. +/// +/// \warning Terminates execution if there is not enough memory. +void +lutok::state::push_string(const std::string& str) +{ + lua_pushstring(_pimpl->lua_state, str.c_str()); +} + + +/// Wrapper around lua_pushvalue. +/// +/// \param index The second parameter to lua_pushvalue. +void +lutok::state::push_value(const int index) +{ + lua_pushvalue(_pimpl->lua_state, index); +} + + +/// Wrapper around lua_rawget. +/// +/// \param index The second parameter to lua_rawget. +void +lutok::state::raw_get(const int index) +{ + lua_rawget(_pimpl->lua_state, index); +} + + +/// Wrapper around lua_rawset. +/// +/// \param index The second parameter to lua_rawset. +/// +/// \warning Terminates execution if there is not enough memory to manipulate +/// the Lua stack. +void +lutok::state::raw_set(const int index) +{ + lua_rawset(_pimpl->lua_state, index); +} + + +/// Wrapper around lua_setglobal. +/// +/// \param name The second parameter to lua_setglobal. +/// +/// \throw api_error If lua_setglobal fails. +/// +/// \warning Terminates execution if there is not enough memory to manipulate +/// the Lua stack. +void +lutok::state::set_global(const std::string& name) +{ + lua_pushcfunction(_pimpl->lua_state, protected_setglobal); + lua_pushstring(_pimpl->lua_state, name.c_str()); + lua_pushvalue(_pimpl->lua_state, -3); + if (lua_pcall(_pimpl->lua_state, 2, 0, 0) != 0) + throw lutok::api_error::from_stack(*this, "lua_setglobal"); + lua_pop(_pimpl->lua_state, 1); +} + + +/// Wrapper around lua_setmetatable. +/// +/// \param index The second parameter to lua_setmetatable. +void +lutok::state::set_metatable(const int index) +{ + lua_setmetatable(_pimpl->lua_state, index); +} + + +/// Wrapper around lua_settable. +/// +/// \param index The second parameter to lua_settable. +/// +/// \throw api_error If lua_settable fails. +/// +/// \warning Terminates execution if there is not enough memory to manipulate +/// the Lua stack. +void +lutok::state::set_table(const int index) +{ + lua_pushcfunction(_pimpl->lua_state, protected_settable); + lua_pushvalue(_pimpl->lua_state, index < 0 ? index - 1 : index); + lua_pushvalue(_pimpl->lua_state, -4); + lua_pushvalue(_pimpl->lua_state, -4); + if (lua_pcall(_pimpl->lua_state, 3, 0, 0) != 0) + throw lutok::api_error::from_stack(*this, "lua_settable"); + lua_pop(_pimpl->lua_state, 2); +} + + +/// Wrapper around lua_toboolean. +/// +/// \param index The second parameter to lua_toboolean. +/// +/// \return The return value of lua_toboolean. +bool +lutok::state::to_boolean(const int index) +{ + assert(is_boolean(index)); + return lua_toboolean(_pimpl->lua_state, index); +} + + +/// Wrapper around lua_tointeger. +/// +/// \param index The second parameter to lua_tointeger. +/// +/// \return The return value of lua_tointeger. +long +lutok::state::to_integer(const int index) +{ + assert(is_number(index)); + return lua_tointeger(_pimpl->lua_state, index); +} + + +/// Wrapper around lua_touserdata. +/// +/// This is internal. The public type-safe interface of this method should be +/// used instead. +/// +/// \param index The second parameter to lua_touserdata. +/// +/// \return The return value of lua_touserdata. +/// +/// \warning Terminates execution if there is not enough memory. +void* +lutok::state::to_userdata_voidp(const int index) +{ + return lua_touserdata(_pimpl->lua_state, index); +} + + + +/// Wrapper around lua_tostring. +/// +/// \param index The second parameter to lua_tostring. +/// +/// \return The return value of lua_tostring. +/// +/// \warning Terminates execution if there is not enough memory. +std::string +lutok::state::to_string(const int index) +{ + assert(is_string(index)); + const char *raw_string = lua_tostring(_pimpl->lua_state, index); + // Note that the creation of a string object below (explicit for clarity) + // implies that the raw string is duplicated and, henceforth, the string is + // safe even if the corresponding element is popped from the Lua stack. + return std::string(raw_string); +} + + +/// Wrapper around lua_upvalueindex. +/// +/// \param index The first parameter to lua_upvalueindex. +/// +/// \return The return value of lua_upvalueindex. +int +lutok::state::upvalue_index(const int index) +{ + return lua_upvalueindex(index); +} + + +/// Gets the internal lua_State object. +/// +/// \return The raw Lua state. This is returned as a void pointer to prevent +/// including the lua.hpp header file from our public interface. The only way +/// to call this method is by using the c_gate module, and c_gate takes care of +/// casting this object to the appropriate type. +void* +lutok::state::raw_state(void) +{ + return _pimpl->lua_state; +} |
