Mercurial > code
view C++/Luae.h @ 242:a9883eeb9757
Add tests for Base64
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 11 Sep 2014 21:09:58 +0200 |
parents | 420b1710355f |
children |
line wrap: on
line source
/* * Luae.h -- Lua helpers and such * * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _LUAE_H_ #define _LUAE_H_ /** * @file Luae.h * @brief Lua C++ extended API */ #include <memory> #include <stdexcept> #include <string> #include <type_traits> #include <unordered_map> #include <lua.hpp> /** * @class Luae * @brief Add lot of convenience for Lua * * This class adds lot of functions for Lua and C++. */ class Luae { public: /* * These fields are stored in the Lua registry. * * FieldRefs - this one is used to reference shared_ptr to reuse * objects and avoid new creation. * FieldTop - this field store the current stack size and is used * with assertBegin and assertEnd. * FieldClasses - this field store the table of created classes. It is used * to verify type cast of LuaeClass'es. */ static constexpr const char *FieldRefs = "__luae_refs"; static constexpr const char *FieldTop = "__luae_topcheck"; static constexpr const char *FieldClasses = "__luae_classes"; /* * These fields are stored in the metatable of the object. * * FieldName - this is the field stored in the metatable to get the real * userdata type. */ static constexpr const char *FieldName = "__luea_name"; private: /* * Wrapper for dofile and dostring. */ static void doexecute(lua_State *L, int status); public: /** * Map from string to function. */ using Reg = std::unordered_map<const char *, lua_CFunction>; /** * ## Userdata object * * Test if the object can be pushed as a userdata. If the object can * be pushed as a userdata, it must match the following requirements: * * - Copy constructible * - Move constructible (at least) * - TypeInfo overload must have const char *name and inherit TypeUserdata * * The following example code allows the class Object to be pushed * and get as Lua userdata. * * @code * struct Object { }; * * template <> * struct Luae::TypeInfo<Object> : Luae::TypeUserdata { * static constexpr const char *name = "Object"; * }; * * int l_push(lua_State *L) * { * Luae::push(L, Object()); * } * * int l_get(lua_State *L) * { * Object *o = Luae::get<Object>(L, 1); * } * @endcode * * @note You don't need to add the pointer type to the get template parameter * * ## Custom object * * This other example can be used to push custom objects but not as * userdata. You can use this to push and read tables for instance. * * For this you must overload TypeInfo to the object and inherit to TypeCustom. * * @code * struct Point { * int x, y; * }; * * template <> * struct Luae::TypeInfo<Point> : Luae::TypeCustom { * static void push(lua_State *L, const Point &p) * { * lua_createtable(L, 0, 0); * lua_pushinteger(L, p.x); * lua_setfield(L, -2, "x"); * lua_pushinteger(L, p.y); * lua_setfield(L, -2, "y"); * } * * static Point get(lua_State *L, int index) * { * Point p; * * if (lua_type(L, index) == LUA_TTABLE) { * lua_getfield(L, index, "x"); * p.x = lua_tonumber(L, -1); * lua_pop(L, 1); * lua_getfield(L, index, "y"); * p.y = lua_tonumber(L, -1); * lua_pop(L, 1); * } * * return p; * } * * static Point check(lua_State *L, int index) * { * // Do your check * * return get(L, index); * } * * static Point optional(lua_State *L, int index, const Point &def) * { * // Do your check or return def * } * }; * * int l_push(lua_State *L) * { * Luae::push<Point>(L, Point {1, 2}); * } * * int l_get(lua_State *L) * { * Point p = Luae::get<Point>(L, 1); * } * @endcode * * @note Here you get a T and not a T * */ template <typename T> struct TypeInfo { static const bool isCustom = false; static const bool isUserdata = false; }; /** * Helpers for custom types. It is already overloaded for all standard * types : * - int * - bool * - double * - std::string * - std::32string */ struct TypeCustom { static const bool canGet = true; static const bool canPush = true; static const bool canCheck = true; static const bool canOptional = true; static const bool isCustom = true; static const bool isUserdata = false; }; /** * Helper for userdata. It only require to set the name field * as the metatable name. */ struct TypeUserdata { static const bool isUserdata = true; static const bool isCustom = false; }; private: /* Tests */ template <typename T> struct IsCustom { static const bool value = TypeInfo<T>::isCustom; }; template <typename T> struct IsUserdata { static const bool value = TypeInfo<T>::isUserdata; }; template <typename T> struct IsSharedUserdata : std::false_type { }; template <typename T> struct IsSharedUserdata<std::shared_ptr<T>> { static const bool value = TypeInfo<T>::isUserdata; }; /* Helpers */ template <bool Cond, typename Type = void> using EnableIf = typename std::enable_if<Cond, Type>::type; template <typename T> using SharedType = typename T::element_type; public: /* ------------------------------------------------- * Standard Lua API wrappers * ------------------------------------------------- */ /** * Calls a Lua function in non-protected mode. * * @param L the Lua state * @param np the number of parameters * @param nr the number of return values */ static inline void call(lua_State *L, int np = 0, int nr = 0) { lua_call(L, np, nr); } /** * Ensure that there are at least extra free stack slots in the stack. * * @param L the Lua state * @param extra the extra data * @return true if possible */ static inline int checkstack(lua_State *L, int extra) { return lua_checkstack(L, extra); } /** * Check the type at the given index. Calls luaL_error on bad * type. * * @param L the Lua state * @param index the the index * @param type the type to check */ static inline void checktype(lua_State *L, int index, int type) { luaL_checktype(L, index, type); } /** * Compares two Lua values. * * Operation is one of: * * * LUA_OPEQ, * * LUA_OPLT, * * LUA_OPLE * * @param L the Lua state * @param index1 the first value * @param index2 the second value * @param op the operation * @return true if index1 statisfies op compared to index2 */ static inline bool compare(lua_State *L, int index1, int index2, int op) { return lua_compare(L, index1, index2, op) == 1; } /** * Concatenate the n values at the top of the stack and pops them. * Leaves the result at the top of the stack. * * @param L the Lua state * @param n the number to concat */ static inline void concat(lua_State *L, int n) { lua_concat(L, n); } /** * Moves the element at the index from into the valid index to. * * @param L the Lua state * @param from the from index * @param to the destination index */ static inline void copy(lua_State *L, int from, int to) { lua_copy(L, from, to); } /** * Create a table. * * @param L the Lua state * @param nr the number of array record * @param ns the number of sequence */ static inline void createtable(lua_State *L, int nr = 0, int ns = 0) { lua_createtable(L, nr, ns); } /** * Load and execute a file. * * @param L the Lua state * @param path the the path * @throw std::runtime_error on error */ static inline void dofile(lua_State *L, const std::string &path) { doexecute(L, luaL_dofile(L, path.c_str())); } /** * Load and execute a string. * * @param L the Lua state * @param data the data * @throw std::runtime_error on error */ static inline void dostring(lua_State *L, const std::string &data) { doexecute(L, luaL_dostring(L, data.c_str())); } /** * Generate an error with the string at the top of the stack. * * @param L the Lua state * @return nothing */ static inline int error(lua_State *L) { return lua_error(L); } /** * Raises a Lua error, thus calling longjmp. * * @param L the Lua state * @param fmt the format * @param args the arguments * @return nothing */ template <typename... Args> static inline int error(lua_State *L, const char *fmt, Args&&... args) { return luaL_error(L, fmt, std::forward<Args>(args)...); } /** * Controls the garbage collector. * * @param L the Lua state * @param what the action * @param data optional GC data */ static inline int gc(lua_State *L, int what, int data = 0) { return lua_gc(L, what, data); } /** * Get a field at the given index. * * @param L the Lua state * @param idx the table index * @param name the field name */ static inline void getfield(lua_State *L, int idx, const std::string &name) { lua_getfield(L, idx, name.c_str()); } /** * Get a global value from Lua. * * @param L the Lua state * @param name the value name */ static inline void getglobal(lua_State *L, const std::string &name) { lua_getglobal(L, name.c_str()); } /** * Check if the object at index idx has a field in its metatable. * * @param L the Lua state * @param idx the object index * @param name the name * @return true if has the field */ static inline bool getmetafield(lua_State *L, int idx, const std::string &name) { return luaL_getmetafield(L, idx, name.c_str()); } /** * Get the metatable of the value at the given index. Returns false * if does not have a metatable and pushes nothing. * * @param L the Lua state * @param index the value index */ static inline bool getmetatable(lua_State *L, int index) { return lua_getmetatable(L, index) == 1; } /** * Set the value at the given index. Top value is the value to assign * key is just below the value. * * @param L the Lua state * @param index the value index */ static inline void gettable(lua_State *L, int index) { lua_gettable(L, index); } /** * Get the current stack size. * * @param L the Lua state * @return the stack size */ static inline int gettop(lua_State *L) { return lua_gettop(L); } /** * Pushes the Lua value associated with the userdata. * * @param L the Lua state * @param index the value index */ static inline void getuservalue(lua_State *L, int index) { lua_getuservalue(L, index); } /** * Move the top element at the given index. * * @param L the Lua state * @param index the new index */ static inline void insert(lua_State *L, int index) { lua_insert(L, index); } /** * Push the result of the operator '#' from the value at the given * index. * * @param L the Lua state * @param index the value index */ static inline void len(lua_State *L, int index) { lua_len(L, index); } /** * Create or get a metatable in the registry. * * @param L the Lua state * @param name the metatable name */ static inline void newmetatable(lua_State *L, const std::string &name) { luaL_newmetatable(L, name.c_str()); } /** * Create a new table and fill it with functions. * * @param L the Lua state * @param functions the functions */ static inline void newlib(lua_State *L, const luaL_Reg *functions) { lua_createtable(L, 0, 0); luaL_setfuncs(L, functions, 0); } /** * Create a new table and fill it with functions. * * @param L the Lua state * @param functions the functions */ static inline void newlib(lua_State *L, const Reg &functions) { lua_createtable(L, 0, 0); for (auto &p : functions) { lua_pushcfunction(L, p.second); lua_setfield(L, -2, p.first); } } /** * Create a new table on the stack. * * @param L the Lua state */ static inline void newtable(lua_State *L) { lua_newtable(L); } /** * Pops a key from the stack and pushes a key-value pair from the table * at the given index. * * @param L the Lua state * @param index the table index * @return true if there are still elements */ static inline bool next(lua_State *L, int index) { return lua_next(L, index) == 1; } /** * Load all Lua libraries. * * @param L the Lua state */ static inline void openlibs(lua_State *L) { luaL_openlibs(L); } /** * Wrapper around pcall, throw instead of returning an error code. * * @param L the Lua state * @param np the number of parameters * @param nr the number of return value * @param error the message handler */ static inline void pcall(lua_State *L, int np, int nr, int error = 0) { if (lua_pcall(L, np, nr, error) != LUA_OK) { auto error = lua_tostring(L, -1); lua_pop(L, 1); throw std::runtime_error(error); } } /** * Pop arguments from the stack. * * @param L the Lua state * @param count the number of values to pop */ static inline void pop(lua_State *L, int count = 1) { lua_pop(L, count); } /** * Pushes a copy of the value at the given index. * * @param L the Lua state * @param index the value to copy */ static inline void pushvalue(lua_State *L, int index) { lua_pushvalue(L, index); } /** * Returns true if the values are primitively equal. * * @param L the Lua state * @param index1 the first value * @param index2 the second value * @return true if they equals */ static inline bool rawequal(lua_State *L, int index1, int index2) { return lua_rawequal(L, index1, index2) == 1; } /** * Like gettable but with raw access. * * @param L the Lua state * @param index the value index */ static inline void rawget(lua_State *L, int index) { lua_rawget(L, index); } /** * Like gettable but with raw access. * * @param L the Lua state * @param index the value index * @param n the nt */ static inline void rawget(lua_State *L, int index, int n) { lua_rawgeti(L, index, n); } /** * Like rawgeti but with pointer. * * @param L the Lua state * @param index the value index * @param p the pointer key */ static inline void rawget(lua_State *L, int index, const void *p) { lua_rawgetp(L, index, p); } /** * Get the value length. * * @param L the Lua state * @param index the value index * @return the raw length */ static inline int rawlen(lua_State *L, int index) { return lua_rawlen(L, index); } /** * Similar to settable but without raw assignment. * * @param L the Lua state * @param index the value index */ static inline void rawset(lua_State *L, int index) { lua_rawset(L, index); } /** * Set the value at the top of stack to the ntn value at the value * at the given index. * * @param L the Lua state * @param index the value index * @param n the nth index */ static inline void rawset(lua_State *L, int index, int n) { lua_rawseti(L, index, n); } /** * Like rawseti with a void pointer as the key. * * @param L the Lua state * @param index the value index * @param ptr the pointer key */ static inline void rawset(lua_State *L, int index, const void *ptr) { lua_rawsetp(L, index, ptr); } /** * Push a formatted string like lua_pushfstring. Warning, it is not type * safe and you should for instance not pass std::String to %s. * * @param L the Lua state * @param fmt the format * @param args the arguments * @return the formatted string */ template <typename... Args> static inline const char *pushfstring(lua_State *L, const char *fmt, Args&&... args) { return lua_pushfstring(L, fmt, std::forward<Args>(args)...); } /** * Push a function with an optional number of upvalues. * * @param L the Lua state * @param func the function * @param nup the number of up values */ static inline void pushfunction(lua_State *L, lua_CFunction func, int nup = 0) { lua_pushcclosure(L, func, nup); } /** * Create a unique reference to the table at the given index. * * @param L the Lua state * @param index the table index * @return the reference */ static inline int ref(lua_State *L, int index) { return luaL_ref(L, index); } /** * Remove the element at the given index. * * @param L the Lua state * @param index the table index */ static inline void remove(lua_State *L, int index) { lua_remove(L, index); } /** * Replace the element at the given index by the one at the top. * * @param L the Lua state * @param index the new index */ static inline void replace(lua_State *L, int index) { lua_replace(L, index); } /** * Set a field to the table at the given index. * * @param L the Lua state * @param idx the table index * @param name the field name * @see set */ static inline void setfield(lua_State *L, int idx, const std::string &name) { lua_setfield(L, idx, name.c_str()); } /** * Set the functions to the table at the top of stack. * * @param L the Lua state * @param functions the functions * @param nup the number of upvalues */ static inline void setfuncs(lua_State *L, const luaL_Reg *functions, int nup = 0) { luaL_setfuncs(L, functions, nup); } /** * Set the functions to the table at the top of stack. * * @param L the Lua state * @param functions the functions * @param nup the number of upvalues */ static inline void setfuncs(lua_State *L, const Reg &functions, int nup = 0) { luaL_checkversion(L); luaL_checkstack(L, nup, "too many upvalues"); for (auto &l : functions) { for (int i = 0; i < nup; i++) lua_pushvalue(L, -nup); lua_pushcclosure(L, l.second, nup); lua_setfield(L, -(nup + 2), l.first); } lua_pop(L, nup); } /** * Set a global. * * @param L the Lua state * @param name the name */ static inline void setglobal(lua_State *L, const std::string &name) { lua_setglobal(L, name.c_str()); } /** * Pops the table at the top of the stack and sets it as the metatable * of the value at the given index. * * @param L the Lua state * @param index the value index */ static inline void setmetatable(lua_State *L, int index) { lua_setmetatable(L, index); } /** * Does t[n] where n is the value at the top of the stack and the key * just below the value. * * @param L the Lua state * @param index the value index */ static inline void settable(lua_State *L, int index) { lua_settable(L, index); } /** * Set the stack size. * * @param L the Lua state * @param index the index */ static inline void settop(lua_State *L, int index = 0) { lua_settop(L, index); } /** * Pops a table or nil from the top stack and set it as the new * associated value to the userdata. * * @param L the Lua state * @param index the userdata index */ static inline void setuservalue(lua_State *L, int index) { lua_setuservalue(L, index); } /** * Get the type at the given index. * * @param L the Lua state * @param index the value index * @return the type */ static inline int type(lua_State *L, int index) { return lua_type(L, index); } /** * Get the type name. * * @param L the Lua state * @param type the type * @return the name * @see type */ static inline const char *typeName(lua_State *L, int type) { return lua_typename(L, type); } /** * Get the type name from a index. * * @param L the Lua state * @param index the value index * @return the name */ static inline const char *typeNamei(lua_State *L, int index) { return luaL_typename(L, index); } /** * Unref the value from the table. * * @param L the Lua state * @param index the table index * @param ref the reference */ static inline void unref(lua_State *L, int index, int ref) { luaL_unref(L, index, ref); } /** * Get the up value index. * * @param index the index * @return the real index */ static inline int upvalueindex(int index) { return lua_upvalueindex(index); } /* ------------------------------------------------- * Extended API * ------------------------------------------------- */ /** * Call this prior to assertEnd. * * @param L the Lua state */ static void assertBegin(lua_State *L); /** * Call this to check the stack size after asserBegin. The stack size * is automatically adjusted to the last size so the expected argument * can just be set to the real expected size just like if the stack size * were 0. * * @param L the Lua state * @param expected the stack size expected */ static void assertEnd(lua_State *L, int expected); /** * Preload a library, it will be added to package.preload so the * user can successfully call require "name". In order to work, you need * to open luaopen_package and luaopen_base first. * * @param L the Lua state * @param name the module name * @param func the opening library * @see require */ static void preload(lua_State *L, const std::string &name, lua_CFunction func); /** * Load a library just like it was loaded with require. * * @param L the Lua state * @param name the module name * @param func the function */ static void require(lua_State *L, const std::string &name, lua_CFunction func); /** * Push a custom type to Lua. * * @param L the Lua state * @param value the value * @return 1 */ template <typename T> static int push(lua_State *L, const T &value, EnableIf<IsCustom<T>::value, T> * = 0) { static_assert(TypeInfo<T>::canPush, "type not supported"); TypeInfo<T>::push(L, value); return 1; } /** * Push a userdata to Lua. * * @param L the Lua state * @param value the value * @return 1 */ template <typename T> static int push(lua_State *L, const T &value, EnableIf<IsUserdata<T>::value, T> * = 0) { new (L, TypeInfo<T>::name) T(value); return 1; } /** * Push a userdata as a shared pointer. * * @param L the Lua state * @param value the value */ template <typename T> static int push(lua_State *L, const std::shared_ptr<T> &value, EnableIf<IsSharedUserdata<std::shared_ptr<T>>::value, T> * = 0) { assertBegin(L); /* * If already in the registry use the same shared_ptr to get the same * pointer address within Lua. This let scripts using the object * as a table key for instance. */ getfield(L, LUA_REGISTRYINDEX, FieldRefs); if (type(L, -1) == LUA_TNIL) { pop(L); createtable(L, 0, 0); createtable(L, 0, 0); pushfstring(L, "v"); setfield(L, -2, "__mode"); setmetatable(L, -2); pushvalue(L, -1); setfield(L, LUA_REGISTRYINDEX, FieldRefs); } /* * Not already existing? Create and return it. */ rawget(L, -1, value.get()); if (type(L, -1) == LUA_TNIL) { pop(L); new (L, TypeInfo<T>::name) std::shared_ptr<T>(value); pushvalue(L, -1); rawset(L, -3, value.get()); } // Remove refs table remove(L, -2); return 1; } /** * Overload for string literals. * * @param L the Lua state * @param s the string * @return 1 */ template <size_t N> static int push(lua_State *L, const char (&s)[N]) { return push<const char *>(L, s); } /** * Get a custom type without check. * * @param L the Lua state * @param index the index * @return the type value */ template <typename T> static EnableIf<IsCustom<T>::value, T> get(lua_State *L, int index) { static_assert(TypeInfo<T>::canGet, "type not supported"); return TypeInfo<T>::get(L, index); } /** * Get a userdata without check. Absolute insecure. * * @param L the Lua state * @param index the index * @return T * */ template <typename T> static EnableIf<IsUserdata<T>::value, T *> get(lua_State *L, int index) { return Luae::toType<T *>(L, index); } /** * Get a userdata from a shared pointer without check. * * @param L the Lua state * @param index the index * @return the std::shared_ptr */ template <typename T> static EnableIf<IsSharedUserdata<T>::value, T> get(lua_State *L, int index) { return *Luae::toType<T *>(L, index); } /** * Get an optional custom type. Returns the value or the * def argument. * * @param L the Lua state * @param index the index * @param def the default value * @return the value or def */ template <typename T> static EnableIf<IsCustom<T>::value, T> optional(lua_State *L, int index, const T &def) { static_assert(TypeInfo<T>::canOptional, "type not supported"); return TypeInfo<T>::optional(L, index, def); } #if 0 /** * Get an optional userdata, returns the userdata pointer * or a new created one. * * @param L the Lua state * @param index the index * @param def the default value * @return the value or def */ template <typename T> static EnableIf<IsUserdata<T>::value, T *> optional(lua_State *L, int index, const T &def) { auto ptr = luaL_testudata(L, index, TypeInfo<T>::name); if (!ptr) return new (L, TypeInfo<T>::name) T(def); return ptr; } #endif /** * Get a custom type with check. * * @param L the Lua state * @param index the index * @return the type */ template <typename T> static EnableIf<IsCustom<T>::value, T> check(lua_State *L, int index) { static_assert(TypeInfo<T>::canCheck, "type not supported"); return TypeInfo<T>::check(L, index); } /** * Get a userdata with checks * * @param L the Lua state * @param index the index * @return T * */ template <typename T> static EnableIf<IsUserdata<T>::value, T *> check(lua_State *L, int index) { return Luae::toType<T *>(L, index, TypeInfo<T>::name); } /** * Get a userdata from a shared pointer with checks. * * @param L the Lua state * @param index the index * @return the std::shared_ptr */ template <typename T> static EnableIf<IsSharedUserdata<T>::value, T> check(lua_State *L, int index) { return *Luae::toType<T *>(L, index, TypeInfo<SharedType<T>>::name); } /** * Convert a new placement made object, without testing if its a real * object. * * @param L the Lua state * @param idx the object index * @return the converted object */ template<class T> static inline T toType(lua_State *L, int idx) { return reinterpret_cast<T>(lua_touserdata(L, idx)); } /** * * @param L the Lua state * @param idx the index * @param meta the metatable name * @return the object */ template <class T> static inline T toType(lua_State *L, int idx, const char *meta) { assertBegin(L); bool isclass(false); if (getmetafield(L, idx, FieldName)) { isclass = true; auto name = lua_tostring(L, -1); lua_pop(L, 1); lua_getfield(L, LUA_REGISTRYINDEX, FieldClasses); // No registered class if (lua_type(L, -1) != LUA_TTABLE) { lua_pop(L, 1); luaL_error(L, "%s has not been registered as a class", name); // NOTREACHED } lua_getfield(L, -1, name); // classes[name] lua_getfield(L, -1, meta); // t[meta] == true? auto value = lua_toboolean(L, -1); lua_pop(L, 3); if (!value) luaL_error(L, "invalid cast from %s to %s", name, meta); // NOTREACHED } assertEnd(L, 0); /* * If the object is a class, we don't need to check the * metatable anymore. */ if (!isclass) return reinterpret_cast<T>(luaL_checkudata(L, idx, meta)); return reinterpret_cast<T>(lua_touserdata(L, idx)); } }; /** * @brief Overload for nil. */ template <> struct Luae::TypeInfo<std::nullptr_t> : Luae::TypeCustom { static const bool canGet = false; static const bool canCheck = false; /** * Push nil. * * @param L the Lua state */ static void push(lua_State *L, const std::nullptr_t &) { lua_pushnil(L); } }; /** * @brief Overload for booleans. */ template <> struct Luae::TypeInfo<bool> : Luae::TypeCustom { /** * Push the boolean value. * * @param L the Lua state * @param value the value */ static void push(lua_State *L, const bool &value) { lua_pushboolean(L, value); } /** * Get a boolean. * * @param L the Lua state * @param index the index * @return a boolean */ static bool get(lua_State *L, int index) { return lua_toboolean(L, index); } /** * Check for a bool. * * @param L the Lua state * @param index the index */ static bool check(lua_State *L, int index) { return lua_toboolean(L, index); } /** * Get an optional boolean. * * @param L the Lua state * @param index the index * @param def the default value if not boolean * @return the value or def */ static bool optional(lua_State *L, int index, const bool &def) { if (lua_type(L, index) == LUA_TBOOLEAN) return lua_toboolean(L, index); return def; } }; /** * @brief Overload for integers. */ template <> struct Luae::TypeInfo<int> : Luae::TypeCustom { /** * Push the integer value. * * @param L the Lua state * @param value the value */ static void push(lua_State *L, const int &value) { lua_pushinteger(L, value); } /** * Get a integer. * * @param L the Lua state * @param index the index * @return a boolean */ static int get(lua_State *L, int index) { return lua_tointeger(L, index); } /** * Check for an integer. * * @param L the Lua state * @param index the index */ static int check(lua_State *L, int index) { return luaL_checkinteger(L, index); } /** * Get an optional integer. * * @param L the Lua state * @param index the index * @param def the default value * @return the value or def */ static int optional(lua_State *L, int index, const int &def) { return luaL_optint(L, index, def); } }; /** * @brief Overload for longs. */ template <> struct Luae::TypeInfo<long> : Luae::TypeCustom { /** * Push the integer value. * * @param L the Lua state * @param value the value */ static void push(lua_State *L, const long &value) { lua_pushinteger(L, value); } /** * Get a integer. * * @param L the Lua state * @param index the index * @return a boolean */ static long get(lua_State *L, int index) { return lua_tointeger(L, index); } /** * Check for an integer. * * @param L the Lua state * @param index the index */ static long check(lua_State *L, int index) { return luaL_checkinteger(L, index); } /** * Get an optional long. * * @param L the Lua state * @param index the index * @param def the default value * @return the value or def */ static long optional(lua_State *L, int index, const long &def) { return luaL_optlong(L, index, def); } }; /** * @brief Overload for doubles. */ template <> struct Luae::TypeInfo<double> : Luae::TypeCustom { /** * Push the double value. * * @param L the Lua state * @param value the value */ static void push(lua_State *L, const double &value) { lua_pushnumber(L, value); } /** * Get a double. * * @param L the Lua state * @param index the index * @return a boolean */ static double get(lua_State *L, int index) { return lua_tonumber(L, index); } /** * Check for a double. * * @param L the Lua state * @param index the index */ static double check(lua_State *L, int index) { return luaL_checknumber(L, index); } /** * Get an optional double. * * @param L the Lua state * @param index the index * @param def the default value * @return the value or def */ static double optional(lua_State *L, int index, const double &def) { return luaL_optnumber(L, index, def); } }; /** * @brief Overload for std::string. */ template <> struct Luae::TypeInfo<std::string> : Luae::TypeCustom { /** * Push the string value. * * @param L the Lua state * @param value the value */ static void push(lua_State *L, const std::string &value) { lua_pushlstring(L, value.c_str(), value.length()); } /** * Get a string. * * @param L the Lua state * @param index the index * @return the string or "" */ static std::string get(lua_State *L, int index) { size_t length; const char *str = lua_tolstring(L, index, &length); if (!str) return ""; return std::string(str, length); } /** * Check for a string. * * @param L the Lua state * @param index the index * @return the string */ static std::string check(lua_State *L, int index) { size_t length; const char *str = luaL_tolstring(L, index, &length); return std::string(str, length); } /** * Get an optional string. * * @param L the Lua state * @param index the index * @param def the default value * @return the value or def */ static std::string optional(lua_State *L, int index, const std::string &def) { size_t length; const char *str = luaL_optlstring(L, index, def.c_str(), &length); return std::string(str, length); } }; /** * @brief Overload for std::u32string. */ template <> struct Luae::TypeInfo<std::u32string> : Luae::TypeCustom { /** * Push the string value. * * @param L the Lua state * @param str the value */ static void push(lua_State *L, const std::u32string &str) { lua_createtable(L, str.size(), 0); for (size_t i = 0; i < str.size(); ++i) { lua_pushinteger(L, str[i]); lua_rawseti(L, -2, i + 1); } } /** * Get a string. * * @param L the Lua state * @param index the index * @return a boolean */ static std::u32string get(lua_State *L, int index) { std::u32string result; if (lua_type(L, index) == LUA_TNUMBER) { result.push_back(lua_tonumber(L, index)); } else if (lua_type(L, index) == LUA_TTABLE) { if (index < 0) -- index; lua_pushnil(L); while (lua_next(L, index)) { if (lua_type(L, -1) == LUA_TNUMBER) result.push_back(lua_tonumber(L, -1)); lua_pop(L, 1); } } return result; } /** * Check for a string. * * @param L the Lua state * @param index the index */ static std::u32string check(lua_State *L, int index) { if (lua_type(L, index) != LUA_TNUMBER && lua_type(L, index) != LUA_TTABLE) luaL_error(L, "expected table or number"); // NOTREACHED return get(L, index); } /** * Get an optional std::u32string. * * @param L the Lua state * @param index the index * @param def the default value * @return the value or def */ static std::u32string optional(lua_State *L, int index, const std::u32string &def) { if (lua_type(L, index) != LUA_TNUMBER && lua_type(L, index) != LUA_TTABLE) return def; return get(L, index); } }; /** * @brief Overload for const char * */ template <> struct Luae::TypeInfo<const char *> : Luae::TypeCustom { /** * Push the string value. * * @param L the Lua state * @param value the value */ static void push(lua_State *L, const char *value) { lua_pushstring(L, value); } /** * Get a string. * * @param L the Lua state * @param index the index * @return a boolean */ static const char *get(lua_State *L, int index) { return lua_tostring(L, index); } /** * Check for a string. * * @param L the Lua state * @param index the index */ static const char *check(lua_State *L, int index) { return luaL_checkstring(L, index); } /** * Get an optional C string. * * @param L the Lua state * @param index the index * @param def the default value * @return the value or def */ static const char *optional(lua_State *L, int index, const char *& def) { return luaL_optstring(L, index, def); } }; /** * Push a Lua userdata. * * @param size the object size * @param L the Lua state * @return the allocated data */ void *operator new(size_t size, lua_State *L); /** * Push a Lua userdata with a metatable. * * @param size the object size * @param L the Lua state * @param metaname the metatable name * @return the allocated data */ void *operator new(size_t size, lua_State *L, const char *metaname); /** * Delete the Lua userdata. * * @param ptr the data * @param L the Lua state */ void operator delete(void *ptr, lua_State *L); /** * Delete the Lua userdata. * * @param ptr the data * @param L the Lua state * @param metaname the metatable name */ void operator delete(void *ptr, lua_State *L, const char *metaname); #endif // !_LUAE_H_