├── LICENSE ├── LuaIntf ├── LuaCompat.h ├── LuaContext.h ├── LuaIntf.h ├── LuaRef.h ├── LuaState.h ├── QtLuaIntf.h ├── impl │ ├── CppArg.h │ ├── CppBindClass.h │ ├── CppBindModule.h │ ├── CppFunction.h │ ├── CppInvoke.h │ ├── CppObject.h │ ├── LuaException.h │ └── LuaType.h └── src │ ├── CppBindClass.cpp │ ├── CppBindModule.cpp │ ├── CppFunction.cpp │ ├── CppObject.cpp │ ├── LuaCompat.cpp │ ├── LuaRef.cpp │ ├── LuaState.cpp │ └── QtLuaIntf.cpp └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright 2014, Steve K. Chiu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /LuaIntf/LuaCompat.h: -------------------------------------------------------------------------------- 1 | // 2 | // https://github.com/SteveKChiu/lua-intf 3 | // 4 | // Copyright 2014, Steve K. Chiu 5 | // 6 | // The MIT License (http://www.opensource.org/licenses/mit-license.php) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a 9 | // copy of this software and associated documentation files (the "Software"), 10 | // to deal in the Software without restriction, including without limitation 11 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the 13 | // Software is furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | // DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | #ifndef LUACOMPAT_H 28 | #define LUACOMPAT_H 29 | 30 | //--------------------------------------------------------------------------- 31 | 32 | /** 33 | * Set LUAINTF_HEADERS_ONLY to 1 if you want this to be headers only library; 34 | * otherwise you need to compile some of the .cpp file separately. 35 | */ 36 | #ifndef LUAINTF_HEADERS_ONLY 37 | #define LUAINTF_HEADERS_ONLY 1 38 | #endif 39 | 40 | /** 41 | * Set LUAINTF_LINK_LUA_COMPILED_IN_CXX to 1 if you compile Lua library under C++ 42 | * (it is *Lua* library, not LuaIntf); it is highly recommended to build Lua library 43 | * under C++, so it is safer and easier to work with Lua error handling. 44 | * 45 | * If Lua is compiled under C, it will use longjmp for error handling, longjmp will ignore 46 | * any destructor of object on stack, and may cause memory leak and other problem. 47 | * 48 | * If Lua is compiled under C++, it will throw C++ exception for error handling, and 49 | * destructor of object on stack will be called as expected. 50 | */ 51 | #ifndef LUAINTF_LINK_LUA_COMPILED_IN_CXX 52 | #define LUAINTF_LINK_LUA_COMPILED_IN_CXX 1 53 | #endif 54 | 55 | /** 56 | * Set LUAINTF_UNSAFE_INT64 to 1 if you want to include partial int64_t support. 57 | * 58 | * This option applies to lua 5.2 or earlier version only, or with 32-bit configuration. 59 | * This option has no effect to lua 5.3 or later version, which has native 64 bit int support. 60 | */ 61 | #ifndef LUAINTF_UNSAFE_INT64 62 | #define LUAINTF_UNSAFE_INT64 1 63 | #endif 64 | 65 | /** 66 | * Set LUAINTF_UNSAFE_INT64_CHECK to 1 if you want to make sure every pushed int64_t is safe, 67 | * that is, it can be converted from/to lua_Number without loss. 68 | * 69 | * This check will throw Lua runtime error if the conversion is not safe. 70 | * This check has no effect to lua 5.3 or later version, which has native 64 bit int support. 71 | */ 72 | #ifndef LUAINTF_UNSAFE_INT64_CHECK 73 | #define LUAINTF_UNSAFE_INT64_CHECK 0 74 | #endif 75 | 76 | /** 77 | * Set LUAINTF_STD_FUNCTION_WRAPPER to 1 if you want to automatically create std::function 78 | * wrapper for the Lua function. 79 | */ 80 | #ifndef LUAINTF_STD_FUNCTION_WRAPPER 81 | #define LUAINTF_STD_FUNCTION_WRAPPER 1 82 | #endif 83 | 84 | /** 85 | * Set LUAINTF_STD_WIDE_STRING to 1 if you want to include support for std wide string conversion. 86 | */ 87 | #ifndef LUAINTF_STD_WIDE_STRING 88 | #define LUAINTF_STD_WIDE_STRING 0 89 | #endif 90 | 91 | /** 92 | * Set LUAINTF_EXTRA_LUA_FIELDS to 1 if you want to include support for adding extra lua fields 93 | * for the exported C++ objects. Otherwise setting missing field will raise lua error. 94 | * 95 | * Note the extra fields is attached to Lua object, different Lua objects will have different 96 | * set of extra fields even they refer to the same C++ object (in the pointer or reference case). 97 | */ 98 | #ifndef LUAINTF_EXTRA_LUA_FIELDS 99 | #define LUAINTF_EXTRA_LUA_FIELDS 0 100 | #endif 101 | 102 | /** 103 | * Set LUAINTF_AUTO_DOWNCAST to 1 if you want to include support for auto downcast. 104 | * This will allow Lua object to access the correct class even the C++ function returns the base class. 105 | */ 106 | #ifndef LUAINTF_AUTO_DOWNCAST 107 | #define LUAINTF_AUTO_DOWNCAST 1 108 | #endif 109 | 110 | //--------------------------------------------------------------------------- 111 | 112 | #if LUAINTF_HEADERS_ONLY 113 | #define LUA_INLINE inline 114 | #else 115 | #define LUA_INLINE 116 | #endif 117 | 118 | #if !LUAINTF_LINK_LUA_COMPILED_IN_CXX 119 | extern "C" 120 | { 121 | #endif 122 | 123 | #include "lualib.h" 124 | #include "lauxlib.h" 125 | 126 | #if !LUAINTF_LINK_LUA_COMPILED_IN_CXX 127 | } 128 | #endif 129 | 130 | //--------------------------------------------------------------------------- 131 | 132 | #if LUA_VERSION_NUM == 501 133 | 134 | #include 135 | 136 | #if !LUAINTF_LINK_LUA_COMPILED_IN_CXX 137 | extern "C" 138 | { 139 | #endif 140 | 141 | typedef uint32_t lua_Unsigned; 142 | 143 | #define LUA_OK 0 144 | 145 | #define LUA_OPEQ 0 146 | #define LUA_OPLT 1 147 | #define LUA_OPLE 2 148 | 149 | #define lua_rawlen(L, i) \ 150 | lua_objlen(L, i) 151 | 152 | #define lua_pushglobaltable(L) \ 153 | lua_pushvalue(L, LUA_GLOBALSINDEX) 154 | 155 | #define lua_tounsigned(L, i) \ 156 | lua_tounsignedx(L, i, NULL) 157 | 158 | const lua_Number* lua_version(lua_State* L); 159 | 160 | int lua_absindex(lua_State* L, int i); 161 | void lua_copy(lua_State* L, int from, int to); 162 | 163 | void lua_pushunsigned(lua_State* L, lua_Unsigned n); 164 | lua_Number lua_tonumberx(lua_State* L, int i, int* isnum); 165 | lua_Integer lua_tointegerx(lua_State* L, int i, int* isnum); 166 | lua_Unsigned lua_tounsignedx(lua_State* L, int i, int* isnum); 167 | 168 | int lua_compare(lua_State* L, int index1, int index2, int op); 169 | 170 | void lua_len(lua_State* L, int i); 171 | void lua_rawgetp(lua_State* L, int i, const void* p); 172 | void lua_rawsetp(lua_State* L, int i, const void* p); 173 | 174 | void lua_getuservalue(lua_State* L, int i); 175 | void lua_setuservalue(lua_State* L, int i); 176 | 177 | #define luaL_newlib(L, l) \ 178 | (lua_newtable(L), luaL_setfuncs(L, l, 0)) 179 | 180 | void luaL_checkversion(lua_State* L); 181 | 182 | lua_Unsigned luaL_checkunsigned(lua_State* L, int i); 183 | lua_Unsigned luaL_optunsigned(lua_State* L, int i, lua_Unsigned def); 184 | const char* luaL_tolstring(lua_State* L, int idx, size_t* len); 185 | 186 | void* luaL_testudata(lua_State* L, int i, const char* tname); 187 | void luaL_setfuncs(lua_State* L, const luaL_Reg* l, int nup); 188 | 189 | int luaL_len(lua_State* L, int i); 190 | void luaL_setmetatable(lua_State* L, const char* tname); 191 | int luaL_getsubtable(lua_State* L, int i, const char* name); 192 | 193 | void luaL_traceback(lua_State* L, lua_State* L1, const char* msg, int level); 194 | int luaL_fileresult(lua_State* L, int stat, const char* fname); 195 | 196 | #if !LUAINTF_LINK_LUA_COMPILED_IN_CXX 197 | } 198 | #endif 199 | 200 | //--------------------------------------------------------------------------- 201 | 202 | #elif LUA_VERSION_NUM >= 503 203 | 204 | #ifndef lua_pushunsigned 205 | #define lua_pushunsigned(L, n) \ 206 | lua_pushinteger(L, static_cast(n)) 207 | 208 | #define lua_tounsignedx(L, i, is) \ 209 | static_cast(lua_tointegerx(L, i, is)) 210 | 211 | #define lua_tounsigned(L, i) \ 212 | lua_tounsignedx(L, (i), nullptr) 213 | #endif 214 | 215 | #ifndef luaL_checkunsigned 216 | #define luaL_checkunsigned(L, a) \ 217 | static_cast(luaL_checkinteger(L, a)) 218 | 219 | #define luaL_optunsigned(L, a, d) \ 220 | static_cast(luaL_optinteger(L, a, static_cast(d))) 221 | #endif 222 | 223 | #endif 224 | 225 | //--------------------------------------------------------------------------- 226 | 227 | #if LUAINTF_HEADERS_ONLY 228 | #include "src/LuaCompat.cpp" 229 | #endif 230 | 231 | //--------------------------------------------------------------------------- 232 | 233 | #endif 234 | -------------------------------------------------------------------------------- /LuaIntf/LuaContext.h: -------------------------------------------------------------------------------- 1 | // 2 | // https://github.com/SteveKChiu/lua-intf 3 | // 4 | // Copyright 2014, Steve K. Chiu 5 | // 6 | // The MIT License (http://www.opensource.org/licenses/mit-license.php) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a 9 | // copy of this software and associated documentation files (the "Software"), 10 | // to deal in the Software without restriction, including without limitation 11 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the 13 | // Software is furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | // DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | #ifndef LUACONTEXT_H 28 | #define LUACONTEXT_H 29 | 30 | //--------------------------------------------------------------------------- 31 | 32 | #include "LuaRef.h" 33 | 34 | namespace LuaIntf 35 | { 36 | 37 | //--------------------------------------------------------------------------- 38 | 39 | /** 40 | * Lua state context 41 | * 42 | * Object representing an instance of Lua. 43 | */ 44 | class LuaContext 45 | { 46 | public: 47 | /** 48 | * Create a new Lua state 49 | * 50 | * @param needImportLibs - true if need to import the standard libraries. 51 | */ 52 | explicit LuaContext(bool needImportLibs = true) 53 | : L(nullptr) 54 | , m_own(true) 55 | { 56 | L = luaL_newstate(); 57 | if (!L) throw LuaException("can not allocate new lua state"); 58 | 59 | #if LUAINTF_LINK_LUA_COMPILED_IN_CXX 60 | lua_atpanic(L, panic); 61 | #endif 62 | 63 | if (needImportLibs) { 64 | importLibs(); 65 | } 66 | } 67 | 68 | /** 69 | * Create a new wrapper for an existing state 70 | * 71 | * Wraps an existing lua_State. The underlying state will not be closed when this object is destroyed. 72 | * This constructor is useful if your lua_State is not managed by your code. 73 | * 74 | * @param state lua_State object to wrap 75 | */ 76 | explicit LuaContext(lua_State* state) 77 | : L(state) 78 | , m_own(false) 79 | {} 80 | 81 | /** 82 | * Lua state is closed if it is not wrapper for an existing state 83 | */ 84 | ~LuaContext() 85 | { 86 | if (m_own) { 87 | lua_close(L); 88 | } 89 | } 90 | 91 | /** 92 | * Copy is not allowed 93 | */ 94 | LuaContext(const LuaContext&) = delete; 95 | 96 | /** 97 | * Copy assignment is not allowed 98 | */ 99 | LuaContext& operator = (const LuaContext&) = delete; 100 | 101 | /** 102 | * Implicit conversion for lua_State* 103 | */ 104 | operator lua_State* () const 105 | { 106 | return L; 107 | } 108 | 109 | /** 110 | * get underlying lua_State 111 | */ 112 | lua_State* state() const 113 | { 114 | return L; 115 | } 116 | 117 | /** 118 | * Import standard Lua libraries 119 | * 120 | * The standard Lua library is not available until this function is called. 121 | */ 122 | void importLibs() 123 | { 124 | luaL_openlibs(L); 125 | } 126 | 127 | /** 128 | * Run a string of Lua 129 | * 130 | * @param code Lua code to execute 131 | * @throw LuaException for syntax errors and uncaught runtime errors 132 | */ 133 | void doString(const char* code) 134 | { 135 | int err = luaL_dostring(L, code); 136 | if (err) throw LuaException(L); 137 | } 138 | 139 | /** 140 | * Run a Lua script, the path is probably not unicode friendly 141 | * 142 | * @param path Path to script file to execute 143 | * @throw LuaException for syntax errors and uncaught runtime errors 144 | */ 145 | void doFile(const char* path) 146 | { 147 | int err = luaL_dofile(L, path); 148 | if (err) throw LuaException(L); 149 | } 150 | 151 | /** 152 | * Get global table (_G) 153 | */ 154 | LuaRef globals() const 155 | { 156 | return LuaRef::globals(L); 157 | } 158 | 159 | /** 160 | * Get value from global variable 161 | */ 162 | template 163 | V getGlobal(const char* name) const 164 | { 165 | return Lua::getGlobal(L, name); 166 | } 167 | 168 | /** 169 | * Set value of global variable 170 | */ 171 | template 172 | void setGlobal(const char* name, const V& v) 173 | { 174 | Lua::setGlobal(L, name, v); 175 | } 176 | 177 | /** 178 | * Get registry table 179 | */ 180 | LuaRef registry() const 181 | { 182 | return LuaRef::registry(L); 183 | } 184 | 185 | /** 186 | * Access Lua garbage collection. 187 | * Defaults to collecting all garbage. 188 | */ 189 | int gc(int what = LUA_GCCOLLECT, int data = 0) 190 | { 191 | return lua_gc(L, what, data); 192 | } 193 | 194 | #if LUAINTF_LINK_LUA_COMPILED_IN_CXX 195 | private: 196 | static int panic(lua_State* L) 197 | { 198 | throw LuaException(L); 199 | } 200 | #endif 201 | 202 | private: 203 | lua_State* L; 204 | bool m_own; 205 | }; 206 | 207 | //--------------------------------------------------------------------------- 208 | 209 | } 210 | 211 | #endif 212 | -------------------------------------------------------------------------------- /LuaIntf/LuaIntf.h: -------------------------------------------------------------------------------- 1 | // 2 | // https://github.com/SteveKChiu/lua-intf 3 | // 4 | // Copyright 2014, Steve K. Chiu 5 | // 6 | // The MIT License (http://www.opensource.org/licenses/mit-license.php) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a 9 | // copy of this software and associated documentation files (the "Software"), 10 | // to deal in the Software without restriction, including without limitation 11 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the 13 | // Software is furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | // DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | #ifndef LUAINTF_H 28 | #define LUAINTF_H 29 | 30 | //--------------------------------------------------------------------------- 31 | 32 | #include "LuaContext.h" 33 | 34 | namespace LuaIntf 35 | { 36 | 37 | //--------------------------------------------------------------------------- 38 | 39 | #include "impl/CppArg.h" 40 | #include "impl/CppInvoke.h" 41 | #include "impl/CppObject.h" 42 | #include "impl/CppBindModule.h" 43 | #include "impl/CppBindClass.h" 44 | #include "impl/CppFunction.h" 45 | 46 | #if LUAINTF_HEADERS_ONLY 47 | #include "src/CppBindModule.cpp" 48 | #include "src/CppBindClass.cpp" 49 | #include "src/CppObject.cpp" 50 | #include "src/CppFunction.cpp" 51 | #endif 52 | 53 | //--------------------------------------------------------------------------- 54 | 55 | } 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /LuaIntf/QtLuaIntf.h: -------------------------------------------------------------------------------- 1 | // 2 | // https://github.com/SteveKChiu/lua-intf 3 | // 4 | // Copyright 2014, Steve K. Chiu 5 | // 6 | // The MIT License (http://www.opensource.org/licenses/mit-license.php) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a 9 | // copy of this software and associated documentation files (the "Software"), 10 | // to deal in the Software without restriction, including without limitation 11 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the 13 | // Software is furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | // DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | #ifndef QTLUAINTF_H 28 | #define QTLUAINTF_H 29 | 30 | //--------------------------------------------------------------------------- 31 | 32 | #include "LuaIntf.h" 33 | #include 34 | 35 | namespace LuaIntf 36 | { 37 | 38 | //--------------------------------------------------------------------------- 39 | 40 | namespace Lua 41 | { 42 | void pushVariant(lua_State* L, const QVariant& v); 43 | QVariant getVariant(lua_State* L, int index); 44 | 45 | /** 46 | * Push QMap as Lua table onto Lua stack. 47 | */ 48 | template 49 | inline void pushMap(lua_State* L, const QMap& map) 50 | { 51 | lua_newtable(L); 52 | for (auto it = map.begin(); it != map.end(); ++it) { 53 | push(L, it.key()); 54 | push(L, it.value()); 55 | lua_settable(L, -3); 56 | } 57 | } 58 | 59 | /** 60 | * Push QHash as Lua table onto Lua stack. 61 | */ 62 | template 63 | inline void pushMap(lua_State* L, const QHash& map) 64 | { 65 | lua_newtable(L); 66 | for (auto it = map.begin(); it != map.end(); ++it) { 67 | push(L, it.key()); 68 | push(L, it.value()); 69 | lua_settable(L, -3); 70 | } 71 | } 72 | } 73 | 74 | //--------------------------------------------------------------------------- 75 | 76 | template <> 77 | struct LuaTypeMapping 78 | { 79 | static void push(lua_State* L, const QByteArray& str) 80 | { 81 | if (str.isEmpty()) { 82 | lua_pushliteral(L, ""); 83 | } else { 84 | lua_pushlstring(L, str.data(), str.length()); 85 | } 86 | } 87 | 88 | static QByteArray get(lua_State* L, int index) 89 | { 90 | size_t len; 91 | const char* p = luaL_checklstring(L, index, &len); 92 | return QByteArray(p, len); 93 | } 94 | 95 | static QByteArray opt(lua_State* L, int index, const QByteArray& def) 96 | { 97 | return lua_isnoneornil(L, index) ? def : get(L, index); 98 | } 99 | }; 100 | 101 | //--------------------------------------------------------------------------- 102 | 103 | template <> 104 | struct LuaTypeMapping 105 | { 106 | static void push(lua_State* L, const QString& str) 107 | { 108 | if (str.isEmpty()) { 109 | lua_pushliteral(L, ""); 110 | } else { 111 | QByteArray buf = str.toUtf8(); 112 | lua_pushlstring(L, buf.data(), buf.length()); 113 | } 114 | } 115 | 116 | static QString get(lua_State* L, int index) 117 | { 118 | size_t len; 119 | const char* p = luaL_checklstring(L, index, &len); 120 | return QString::fromUtf8(p, len); 121 | } 122 | 123 | static QString opt(lua_State* L, int index, const QString& def) 124 | { 125 | return lua_isnoneornil(L, index) ? def : get(L, index); 126 | } 127 | }; 128 | 129 | //--------------------------------------------------------------------------- 130 | 131 | template <> 132 | struct LuaTypeMapping 133 | { 134 | static void push(lua_State* L, const QVariant& v) 135 | { 136 | Lua::pushVariant(L, v); 137 | } 138 | 139 | static QVariant get(lua_State* L, int index) 140 | { 141 | return Lua::getVariant(L, index); 142 | } 143 | 144 | static QVariant opt(lua_State* L, int index, const QVariant& def) 145 | { 146 | return lua_isnoneornil(L, index) ? def : Lua::getVariant(L, index); 147 | } 148 | }; 149 | 150 | //--------------------------------------------------------------------------- 151 | 152 | LUA_USING_LIST_TYPE_X(QStringList) 153 | LUA_USING_LIST_TYPE_X(QVariantList) 154 | LUA_USING_MAP_TYPE_X(QVariantMap) 155 | 156 | //--------------------------------------------------------------------------- 157 | 158 | #if LUAINTF_HEADERS_ONLY 159 | #include "src/QtLuaIntf.cpp" 160 | #endif 161 | 162 | //--------------------------------------------------------------------------- 163 | 164 | } 165 | 166 | #endif 167 | -------------------------------------------------------------------------------- /LuaIntf/impl/CppArg.h: -------------------------------------------------------------------------------- 1 | // 2 | // https://github.com/SteveKChiu/lua-intf 3 | // 4 | // Copyright 2014, Steve K. Chiu 5 | // 6 | // The MIT License (http://www.opensource.org/licenses/mit-license.php) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a 9 | // copy of this software and associated documentation files (the "Software"), 10 | // to deal in the Software without restriction, including without limitation 11 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the 13 | // Software is furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | // DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | struct _arg {}; 28 | 29 | template 30 | struct _opt {}; 31 | 32 | template 33 | struct _def {}; 34 | 35 | template 36 | struct _out {}; 37 | 38 | template 39 | struct _ref {}; 40 | 41 | template 42 | struct _ref_opt {}; 43 | 44 | template 45 | struct _ref_def {}; 46 | 47 | #define LUA_ARGS_TYPE(...) LuaIntf::_arg(*)(__VA_ARGS__) 48 | #define LUA_ARGS(...) static_cast(nullptr) 49 | 50 | #define LUA_FN(r, m, ...) static_cast(&m) 51 | #define LUA_MEMFN(t, r, m, ...) static_cast(&t::m) 52 | 53 | //--------------------------------------------------------------------------- 54 | 55 | template 56 | struct CppArgHolder 57 | { 58 | T& value() 59 | { 60 | return holder; 61 | } 62 | 63 | const T& value() const 64 | { 65 | return holder; 66 | } 67 | 68 | void hold(const T& v) 69 | { 70 | holder = v; 71 | } 72 | 73 | T holder; 74 | }; 75 | 76 | template 77 | struct CppArgHolder 78 | { 79 | T& value() const 80 | { 81 | return *holder; 82 | } 83 | 84 | void hold(T& v) 85 | { 86 | holder = &v; 87 | } 88 | 89 | T* holder; 90 | }; 91 | 92 | //--------------------------------------------------------------------------- 93 | 94 | template 95 | struct CppArgTraits 96 | { 97 | using Type = T; 98 | using ValueType = typename std::result_of::get)(lua_State*, int)>::type; 99 | using HolderType = CppArgHolder; 100 | 101 | static constexpr bool isInput = true; 102 | static constexpr bool isOutput = false; 103 | static constexpr bool isOptonal = false; 104 | static constexpr bool hasDefault = false; 105 | }; 106 | 107 | template 108 | struct CppArgTraits <_opt> 109 | : CppArgTraits 110 | { 111 | using Type = T; 112 | using ValueType = typename std::decay::type; 113 | using HolderType = CppArgHolder; 114 | 115 | static constexpr bool isOptonal = true; 116 | }; 117 | 118 | template 119 | struct CppArgTraits <_def> 120 | : CppArgTraits <_opt> 121 | { 122 | static constexpr bool hasDefault = true; 123 | static constexpr T defaultValue = T(T(NUM) / DEN); 124 | }; 125 | 126 | template 127 | struct CppArgTraits <_out> 128 | : CppArgTraits 129 | { 130 | static_assert(std::is_lvalue_reference::value 131 | && !std::is_const::type>::value, 132 | "argument with out spec must be non-const reference type"); 133 | static constexpr bool isInput = false; 134 | static constexpr bool isOutput = true; 135 | }; 136 | 137 | template 138 | struct CppArgTraits <_ref> 139 | : CppArgTraits 140 | { 141 | static_assert(std::is_lvalue_reference::value 142 | && !std::is_const::type>::value, 143 | "argument with ref spec must be non-const reference type"); 144 | static constexpr bool isOutput = true; 145 | }; 146 | 147 | template 148 | struct CppArgTraits <_ref_opt> 149 | : CppArgTraits <_opt> 150 | { 151 | static_assert(std::is_lvalue_reference::value 152 | && !std::is_const::type>::value, 153 | "argument with ref spec must be non-const reference type"); 154 | static constexpr bool isOutput = true; 155 | }; 156 | 157 | template 158 | struct CppArgTraits <_ref_def> 159 | : CppArgTraits <_def> 160 | { 161 | static_assert(std::is_lvalue_reference::value 162 | && !std::is_const::type>::value, 163 | "argument with ref spec must be non-const reference type"); 164 | static constexpr bool isOutput = true; 165 | }; 166 | 167 | template <> 168 | struct CppArgTraits 169 | { 170 | using Type = lua_State*; 171 | using ValueType = lua_State*; 172 | using HolderType = CppArgHolder; 173 | 174 | static constexpr bool isInput = false; 175 | static constexpr bool isOutput = false; 176 | static constexpr bool isOptonal = false; 177 | static constexpr bool hasDefault = false; 178 | }; 179 | 180 | template <> 181 | struct CppArgTraits 182 | { 183 | using Type = LuaState; 184 | using ValueType = LuaState; 185 | using HolderType = CppArgHolder; 186 | 187 | static constexpr bool isInput = false; 188 | static constexpr bool isOutput = false; 189 | static constexpr bool isOptonal = false; 190 | static constexpr bool hasDefault = false; 191 | }; 192 | 193 | //--------------------------------------------------------------------------- 194 | 195 | template 196 | struct CppArgInput; 197 | 198 | template 199 | struct CppArgInput 200 | { 201 | static int get(lua_State*, int, typename Traits::HolderType&) 202 | { 203 | return 0; 204 | } 205 | }; 206 | 207 | template 208 | struct CppArgInput 209 | { 210 | static int get(lua_State* L, int index, typename Traits::HolderType& r) 211 | { 212 | r.hold(LuaType::get(L, index)); 213 | return 1; 214 | } 215 | }; 216 | 217 | template 218 | struct CppArgInput 219 | { 220 | static int get(lua_State* L, int index, typename Traits::HolderType& r) 221 | { 222 | using DefaultType = typename std::decay::type; 223 | r.hold(LuaType::opt(L, index, DefaultType())); 224 | return 1; 225 | } 226 | }; 227 | 228 | template 229 | struct CppArgInput 230 | { 231 | static int get(lua_State* L, int index, typename Traits::HolderType& r) 232 | { 233 | r.hold(LuaType::opt(L, index, Traits::defaultValue)); 234 | return 1; 235 | } 236 | }; 237 | 238 | template <> 239 | struct CppArgInput , false, false, false> 240 | { 241 | static int get(lua_State* L, int, CppArgHolder& r) 242 | { 243 | r.hold(L); 244 | return 0; 245 | } 246 | }; 247 | 248 | template <> 249 | struct CppArgInput , false, false, false> 250 | { 251 | static int get(lua_State* L, int, CppArgHolder& r) 252 | { 253 | r.hold(L); 254 | return 0; 255 | } 256 | }; 257 | 258 | //--------------------------------------------------------------------------- 259 | 260 | template 261 | struct CppArgOutput; 262 | 263 | template 264 | struct CppArgOutput 265 | { 266 | static int push(lua_State*, const typename Traits::ValueType&) 267 | { 268 | return 0; 269 | } 270 | }; 271 | 272 | template 273 | struct CppArgOutput 274 | { 275 | static int push(lua_State* L, const typename Traits::ValueType& v) 276 | { 277 | LuaType::push(L, v); 278 | return 1; 279 | } 280 | }; 281 | 282 | //--------------------------------------------------------------------------- 283 | 284 | template 285 | struct CppArg 286 | { 287 | using Traits = CppArgTraits; 288 | using Type = typename Traits::Type; 289 | using HolderType = typename Traits::HolderType; 290 | 291 | static int get(lua_State* L, int index, HolderType& r) 292 | { 293 | return CppArgInput::get(L, index, r); 294 | } 295 | 296 | static int push(lua_State* L, const HolderType& v) 297 | { 298 | return CppArgOutput::push(L, v.value()); 299 | } 300 | }; 301 | 302 | template 303 | using CppArgTuple = std::tuple::HolderType...>; 304 | 305 | //--------------------------------------------------------------------------- 306 | 307 | template 308 | struct CppArgTupleInput; 309 | 310 | template <> 311 | struct CppArgTupleInput <> 312 | { 313 | template 314 | static void get(lua_State*, int, std::tuple&) 315 | { 316 | // template terminate function 317 | } 318 | }; 319 | 320 | template 321 | struct CppArgTupleInput 322 | { 323 | template 324 | static void get(lua_State* L, int index, std::tuple& t) 325 | { 326 | index += CppArg::get(L, index, std::get(t)); 327 | CppArgTupleInput::get(L, index, t); 328 | } 329 | }; 330 | 331 | //--------------------------------------------------------------------------- 332 | 333 | template 334 | struct CppArgTupleOutput; 335 | 336 | template <> 337 | struct CppArgTupleOutput <> 338 | { 339 | template 340 | static int push(lua_State*, const std::tuple&) 341 | { 342 | // template terminate function 343 | return 0; 344 | } 345 | }; 346 | 347 | template 348 | struct CppArgTupleOutput 349 | { 350 | template 351 | static int push(lua_State* L, const std::tuple& t) 352 | { 353 | int n = CppArg::push(L, std::get(t)); 354 | return n + CppArgTupleOutput::push(L, t); 355 | } 356 | }; 357 | -------------------------------------------------------------------------------- /LuaIntf/impl/CppBindModule.h: -------------------------------------------------------------------------------- 1 | // 2 | // https://github.com/SteveKChiu/lua-intf 3 | // 4 | // Copyright 2014, Steve K. Chiu 5 | // 6 | // The MIT License (http://www.opensource.org/licenses/mit-license.php) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a 9 | // copy of this software and associated documentation files (the "Software"), 10 | // to deal in the Software without restriction, including without limitation 11 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the 13 | // Software is furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | // DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | struct CppBindConstant 28 | { 29 | /** 30 | * lua_CFunction to get a constant 31 | * 32 | * The constant data is in the first upvalue. 33 | */ 34 | static int call(lua_State* L) 35 | { 36 | lua_pushvalue(L, lua_upvalueindex(1)); 37 | return 1; 38 | } 39 | }; 40 | 41 | template 42 | struct CppBindVariableGetter 43 | { 44 | /** 45 | * lua_CFunction to get a variable 46 | * 47 | * This is used for global variables or class static data members. 48 | * 49 | * The pointer to the data is in the first upvalue. 50 | */ 51 | static int call(lua_State* L) 52 | { 53 | try { 54 | assert(lua_islightuserdata(L, lua_upvalueindex(1))); 55 | auto ptr = static_cast(lua_touserdata(L, lua_upvalueindex(1))); 56 | assert(ptr); 57 | 58 | LuaType::push(L, *ptr); 59 | return 1; 60 | } catch (std::exception& e) { 61 | return luaL_error(L, "%s", e.what()); 62 | } 63 | } 64 | }; 65 | 66 | template 67 | struct CppBindVariableSetter 68 | { 69 | /** 70 | * lua_CFunction to set a variable. 71 | * 72 | * This is used for global variables or class static data members. 73 | * 74 | * The pointer to the data is in the first upvalue. 75 | */ 76 | static int call(lua_State* L) 77 | { 78 | try { 79 | assert(lua_islightuserdata(L, lua_upvalueindex(1))); 80 | auto ptr = static_cast(lua_touserdata(L, lua_upvalueindex(1))); 81 | assert(ptr); 82 | 83 | *ptr = LuaType::get(L, 1); 84 | return 0; 85 | } catch (std::exception& e) { 86 | return luaL_error(L, "%s", e.what()); 87 | } 88 | } 89 | }; 90 | 91 | //---------------------------------------------------------------------------- 92 | 93 | enum CppBindMethodCheck 94 | { 95 | CHK_NORMAL, 96 | CHK_GETTER, 97 | CHK_SETTER, 98 | CHK_GETTER_INDEXED, 99 | CHK_SETTER_INDEXED 100 | }; 101 | 102 | template 103 | struct CppBindMethodBase 104 | { 105 | static_assert(CHK != CHK_GETTER || (!std::is_same::value && sizeof...(P) == 0), 106 | "the specified function is not getter function"); 107 | 108 | static_assert(CHK != CHK_SETTER || (std::is_same::value && sizeof...(P) == 1), 109 | "the specified function is not setter function"); 110 | 111 | /** 112 | * lua_CFunction to call a function 113 | * 114 | * The pointer to function object is in the first upvalue. 115 | */ 116 | static int call(lua_State* L) 117 | { 118 | try { 119 | assert(lua_isuserdata(L, lua_upvalueindex(1))); 120 | const FN& fn = *reinterpret_cast(lua_touserdata(L, lua_upvalueindex(1))); 121 | assert(fn); 122 | 123 | CppArgTuple args; 124 | CppArgTupleInput::get(L, IARG, args); 125 | 126 | int n = CppInvokeMethod::HolderType...>::push(L, fn, args); 127 | return n + CppArgTupleOutput::push(L, args); 128 | } catch (std::exception& e) { 129 | return luaL_error(L, "%s", e.what()); 130 | } 131 | } 132 | 133 | template 134 | static FN function(const PROC& fn) 135 | { 136 | return static_cast(fn); 137 | } 138 | }; 139 | 140 | template 141 | struct CppBindMethod; 142 | 143 | template 144 | struct CppBindMethod 145 | : CppBindMethodBase {}; 146 | 147 | template 148 | struct CppBindMethod , std::function, IARG, CHK> 149 | : CppBindMethodBase , IARG, R, P...> {}; 150 | 151 | template 152 | struct CppBindMethod 153 | : CppBindMethodBase 154 | { 155 | static_assert(sizeof...(A) == sizeof...(P), 156 | "the number of arguments and argument-specs do not match"); 157 | }; 158 | 159 | template 160 | struct CppBindMethod , _arg(*)(P...), IARG, CHK> 161 | : CppBindMethodBase , IARG, R, P...> 162 | { 163 | static_assert(sizeof...(A) == sizeof...(P), 164 | "the number of arguments and argument-specs do not match"); 165 | }; 166 | 167 | template 168 | struct CppBindMethod ::value>::type> 170 | : CppBindMethod ::FunctionType, typename CppLambdaTraits::FunctionType, IARG, CHK> {}; 171 | 172 | template 173 | struct CppBindMethod ::value>::type> 175 | : CppBindMethod ::FunctionType, _arg(*)(P...), IARG, CHK> {}; 176 | 177 | template 178 | struct CppBindMethod ::value>::type> 180 | : CppBindMethod {}; 181 | 182 | template 183 | struct CppBindMethod ::value>::type> 185 | : CppBindMethod {}; 186 | 187 | //---------------------------------------------------------------------------- 188 | 189 | struct CppBindModuleMetaMethod 190 | { 191 | /** 192 | * __index metamethod for module members. 193 | * 194 | * Retrieving global functions methods, stored in the metatable. 195 | * Reading global variable and properties, stored in the ___getters table. 196 | */ 197 | static int index(lua_State* L); 198 | 199 | /** 200 | * __newindex metamethod for module members. 201 | * 202 | * The ___setters table stores proxy functions for assignment to 203 | * global variable and properties 204 | */ 205 | static int newIndex(lua_State* L); 206 | 207 | /** 208 | * Forward __call to sub class or module. 209 | * The name of sub class/module is in upvalue(1) 210 | */ 211 | static int forwardCall(lua_State* L); 212 | 213 | /** 214 | * lua_CFunction to report an error writing to a read-only value. 215 | * 216 | * The name of the variable is in the first upvalue. 217 | */ 218 | static int errorReadOnly(lua_State* L); 219 | }; 220 | 221 | //---------------------------------------------------------------------------- 222 | 223 | class CppBindModuleBase 224 | { 225 | friend class CppBindClassBase; 226 | 227 | protected: 228 | explicit CppBindModuleBase(const LuaRef& meta) 229 | : m_meta(meta) 230 | { 231 | m_meta.checkTable(); 232 | } 233 | 234 | CppBindModuleBase(LuaRef& meta, const char* module); 235 | 236 | static std::string getFullName(const LuaRef& parent, const char* name); 237 | static std::string getMemberName(const LuaRef& parent, const char* name); 238 | 239 | void setGetter(const char* name, const LuaRef& getter); 240 | void setSetter(const char* name, const LuaRef& setter); 241 | void setReadOnly(const char* name); 242 | 243 | public: 244 | /** 245 | * Copy constructor. 246 | */ 247 | CppBindModuleBase(const CppBindModuleBase& that) 248 | : m_meta(that.m_meta) 249 | {} 250 | 251 | /** 252 | * Move constructor for temporaries. 253 | */ 254 | CppBindModuleBase(CppBindModuleBase&& that) 255 | : m_meta(std::move(that.m_meta)) 256 | {} 257 | 258 | /** 259 | * Copy assignment. 260 | */ 261 | CppBindModuleBase& operator = (const CppBindModuleBase& that) 262 | { 263 | m_meta = that.m_meta; 264 | return *this; 265 | } 266 | 267 | /** 268 | * Move assignment for temporaries. 269 | */ 270 | CppBindModuleBase& operator = (CppBindModuleBase&& that) 271 | { 272 | m_meta = std::move(that.m_meta); 273 | return *this; 274 | } 275 | 276 | /** 277 | * The underlying lua state. 278 | */ 279 | lua_State* state() const 280 | { 281 | return m_meta.state(); 282 | } 283 | 284 | /** 285 | * The underlying meta table. 286 | */ 287 | LuaRef meta() const 288 | { 289 | return m_meta; 290 | } 291 | 292 | protected: 293 | LuaRef m_meta; 294 | }; 295 | 296 | //---------------------------------------------------------------------------- 297 | 298 | template 299 | class CppBindClass; 300 | 301 | /** 302 | * Provides C++ to Lua registration capabilities. 303 | * 304 | * This class is not instantiated directly, call LuaBinding(L) to start 305 | * the registration process. 306 | */ 307 | template 308 | class CppBindModule : public CppBindModuleBase 309 | { 310 | friend class LuaBinding; 311 | template friend class CppBindClass; 312 | template friend class CppBindModule; 313 | 314 | explicit CppBindModule(const LuaRef& meta) 315 | : CppBindModuleBase(meta) 316 | {} 317 | 318 | CppBindModule(LuaRef& meta, const char* module) 319 | : CppBindModuleBase(meta, module) 320 | {} 321 | 322 | public: 323 | /** 324 | * Copy constructor. 325 | */ 326 | CppBindModule(const CppBindModule& that) 327 | : CppBindModuleBase(that) 328 | {} 329 | 330 | /** 331 | * Move constructor for temporaries. 332 | */ 333 | CppBindModule(CppBindModule&& that) 334 | : CppBindModuleBase(std::move(that)) 335 | {} 336 | 337 | /** 338 | * Copy assignment. 339 | */ 340 | CppBindModule& operator = (const CppBindModule& that) 341 | { 342 | m_meta = that.m_meta; 343 | return *this; 344 | } 345 | 346 | /** 347 | * Move assignment for temporaries. 348 | */ 349 | CppBindModule& operator = (CppBindModule&& that) 350 | { 351 | m_meta = std::move(that.m_meta); 352 | return *this; 353 | } 354 | 355 | /** 356 | * Add or replace a constant value. 357 | */ 358 | template 359 | CppBindModule& addConstant(const char* name, const V& v) 360 | { 361 | LuaRef r = LuaRef::fromValue(state(), v); 362 | if (r.isFunction()) { 363 | r = LuaRef::createFunctionWith(state(), &CppBindConstant::call, r); 364 | } 365 | setGetter(name, r); 366 | setReadOnly(name); 367 | return *this; 368 | } 369 | 370 | /** 371 | * Add or replace a non-const variable. 372 | * The value return to lua is pass-by-value, that will create a local copy in lua. 373 | * This is different from addVariableRef, which is pass-by-reference, and allow direct access to the variable. 374 | * This apply only to the class type, the primitive types are always pass-by-value. 375 | */ 376 | template 377 | CppBindModule& addVariable(const char* name, V* v, bool writable = true) 378 | { 379 | setGetter(name, LuaRef::createFunctionWithPtr(state(), &CppBindVariableGetter::call, v)); 380 | if (writable) { 381 | setSetter(name, LuaRef::createFunctionWithPtr(state(), &CppBindVariableSetter::call, v)); 382 | } else { 383 | setReadOnly(name); 384 | } 385 | return *this; 386 | } 387 | 388 | /** 389 | * Add or replace a const read-only variable. 390 | * The value return to lua is pass-by-value, that will create a local copy in lua. 391 | * This is different from addVariableRef, which is pass-by-reference, and allow direct access to the variable. 392 | * This apply only to the class type, the primitive types are always pass-by-value. 393 | */ 394 | template 395 | CppBindModule& addVariable(const char* name, const V* v) 396 | { 397 | setGetter(name, LuaRef::createFunctionWithPtr(state(), &CppBindVariableGetter::call, v)); 398 | setReadOnly(name); 399 | return *this; 400 | } 401 | 402 | /** 403 | * Add or replace a non-const variable. 404 | * The value return to lua is pass-by-reference, and allow direct access to the variable. 405 | * This is different from addVariable, which is pass-by-value, and will create a local copy upon access. 406 | * This apply only to the class type, the primitive types are always pass-by-value. 407 | */ 408 | template 409 | typename std::enable_if::value, CppBindModule&>::type 410 | addVariableRef(const char* name, V* v, bool writable = true) 411 | { 412 | setGetter(name, LuaRef::createFunctionWithPtr(state(), &CppBindVariableGetter::call, v)); 413 | if (writable) { 414 | setSetter(name, LuaRef::createFunctionWithPtr(state(), &CppBindVariableSetter::call, v)); 415 | } else { 416 | setReadOnly(name); 417 | } 418 | return *this; 419 | } 420 | 421 | /** 422 | * Add or replace a non-const variable. 423 | * The value return to lua is pass-by-reference, and allow direct access to the variable. 424 | * This is different from addVariable, which is pass-by-value, and will create a local copy upon access. 425 | * This apply only to the class type, the primitive types are always pass-by-value. 426 | */ 427 | template 428 | typename std::enable_if::value, CppBindModule&>::type 429 | addVariableRef(const char* name, V* v) 430 | { 431 | setGetter(name, LuaRef::createFunctionWithPtr(state(), &CppBindVariableGetter::call, v)); 432 | setReadOnly(name); 433 | return *this; 434 | } 435 | 436 | /** 437 | * Add or replace a const read-only variable. 438 | * The value return to lua is pass-by-reference, and allow direct access to the variable. 439 | * This is different from addVariable, which is pass-by-value, and will create a local copy upon access. 440 | * This apply only to the class type, the primitive types are always pass-by-value. 441 | */ 442 | template 443 | CppBindModule& addVariableRef(const char* name, const V* v) 444 | { 445 | setGetter(name, LuaRef::createFunctionWithPtr(state(), &CppBindVariableGetter::call, v)); 446 | setReadOnly(name); 447 | return *this; 448 | } 449 | 450 | /** 451 | * Add or replace a read-write property. 452 | */ 453 | template 454 | CppBindModule& addProperty(const char* name, const FG& get, const FS& set) 455 | { 456 | using CppGetter = CppBindMethod; 457 | using CppSetter = CppBindMethod; 458 | setGetter(name, LuaRef::createFunction(state(), &CppGetter::call, CppGetter::function(get))); 459 | setSetter(name, LuaRef::createFunction(state(), &CppSetter::call, CppSetter::function(set))); 460 | return *this; 461 | } 462 | 463 | /** 464 | * Add or replace a read-only property. 465 | */ 466 | template 467 | CppBindModule& addProperty(const char* name, const FN& get) 468 | { 469 | using CppGetter = CppBindMethod; 470 | setGetter(name, LuaRef::createFunction(state(), &CppGetter::call, CppGetter::function(get))); 471 | setReadOnly(name); 472 | return *this; 473 | } 474 | 475 | /** 476 | * Add or replace a function. 477 | */ 478 | template 479 | CppBindModule& addFunction(const char* name, const FN& proc) 480 | { 481 | using CppProc = CppBindMethod; 482 | m_meta.rawset(name, LuaRef::createFunction(state(), &CppProc::call, CppProc::function(proc))); 483 | return *this; 484 | } 485 | 486 | /** 487 | * Add or replace a function, user can specify augument spec. 488 | */ 489 | template 490 | CppBindModule& addFunction(const char* name, const FN& proc, ARGS) 491 | { 492 | using CppProc = CppBindMethod; 493 | m_meta.rawset(name, LuaRef::createFunction(state(), &CppProc::call, CppProc::function(proc))); 494 | return *this; 495 | } 496 | 497 | /** 498 | * Add or replace a factory function. 499 | */ 500 | template 501 | CppBindModule& addFactory(const FN& proc) 502 | { 503 | using CppProc = CppBindMethod; 504 | m_meta.rawset("__call", LuaRef::createFunction(state(), &CppProc::call, CppProc::function(proc))); 505 | return *this; 506 | } 507 | 508 | /** 509 | * Add or replace a factory function, user can specify augument spec. 510 | */ 511 | template 512 | CppBindModule& addFactory(const FN& proc, ARGS) 513 | { 514 | using CppProc = CppBindMethod; 515 | m_meta.rawset("__call", LuaRef::createFunction(state(), &CppProc::call, CppProc::function(proc))); 516 | return *this; 517 | } 518 | 519 | /** 520 | * Add or replace a factory function, that forward call to sub module factory (or class constructor). 521 | */ 522 | CppBindModule& addFactory(const char* name) 523 | { 524 | m_meta.rawset("__call", LuaRef::createFunctionWith(state(), &CppBindModuleMetaMethod::forwardCall, name)); 525 | return *this; 526 | } 527 | 528 | /** 529 | * Open a new or existing CppBindModule for registrations. 530 | */ 531 | CppBindModule> beginModule(const char* name) 532 | { 533 | return CppBindModule>(m_meta, name); 534 | } 535 | 536 | /** 537 | * Continue CppBindModule registration in the parent. 538 | */ 539 | PARENT endModule() 540 | { 541 | return PARENT(m_meta.rawget("___parent")); 542 | } 543 | 544 | /** 545 | * Open a new or existing class for registrations. 546 | */ 547 | template 548 | CppBindClass> beginClass(const char* name) 549 | { 550 | return CppBindClass>::bind(m_meta, name); 551 | } 552 | 553 | /** 554 | * Open a new class to extend the base class. 555 | */ 556 | template 557 | CppBindClass> beginExtendClass(const char* name) 558 | { 559 | return CppBindClass>::template extend(m_meta, name); 560 | } 561 | }; 562 | 563 | //--------------------------------------------------------------------------- 564 | 565 | class LuaBinding 566 | { 567 | public: 568 | /** 569 | * Module binds to a global variable (lua 5.0 style) 570 | * 571 | * It is recommended to put your module inside the global, and 572 | * then add your classes and functions to it, rather than adding many classes 573 | * and functions directly to the global. 574 | */ 575 | explicit LuaBinding(lua_State* L) 576 | : m_meta(LuaRef::globals(L)) 577 | {} 578 | 579 | /** 580 | * Module binds to a local LuaRef value. 581 | * 582 | * This can be used to implement Lua 5.1 module style: 583 | * 584 | * extern "C" int luaopen_modname(lua_State* L) 585 | * { 586 | * LuaRef mod = LuaRef::createTable(L); 587 | * LuaBinding(mod) 588 | * ...; 589 | * mod.pushToStack(); 590 | * return 1; 591 | * } 592 | */ 593 | explicit LuaBinding(const LuaRef& mod) 594 | : m_meta(mod) 595 | {} 596 | 597 | /** 598 | * Copy constructor. 599 | */ 600 | LuaBinding(const LuaBinding& that) 601 | : m_meta(that.m_meta) 602 | {} 603 | 604 | /** 605 | * Move constructor for temporaries. 606 | */ 607 | LuaBinding(LuaBinding&& that) 608 | : m_meta(std::move(that.m_meta)) 609 | {} 610 | 611 | /** 612 | * Copy assignment. 613 | */ 614 | LuaBinding& operator = (const LuaBinding& that) 615 | { 616 | m_meta = that.m_meta; 617 | return *this; 618 | } 619 | 620 | /** 621 | * Move assignment for temporaries. 622 | */ 623 | LuaBinding& operator = (LuaBinding&& that) 624 | { 625 | m_meta = std::move(that.m_meta); 626 | return *this; 627 | } 628 | 629 | /** 630 | * The underlying lua state. 631 | */ 632 | lua_State* state() const 633 | { 634 | return m_meta.state(); 635 | } 636 | 637 | /** 638 | * Add or replace a function. 639 | */ 640 | template 641 | LuaBinding& addFunction(const char* name, const FN& proc) 642 | { 643 | using CppProc = CppBindMethod; 644 | m_meta.rawset(name, LuaRef::createFunction(state(), &CppProc::call, CppProc::function(proc))); 645 | return *this; 646 | } 647 | 648 | /** 649 | * Add or replace a function, user can specify augument spec. 650 | */ 651 | template 652 | LuaBinding& addFunction(const char* name, const FN& proc, ARGS) 653 | { 654 | using CppProc = CppBindMethod; 655 | m_meta.rawset(name, LuaRef::createFunction(state(), &CppProc::call, CppProc::function(proc))); 656 | return *this; 657 | } 658 | 659 | /** 660 | * Open a new or existing CppBindModule for registrations. 661 | */ 662 | CppBindModule beginModule(const char* name) 663 | { 664 | return CppBindModule(m_meta, name); 665 | } 666 | 667 | /** 668 | * Open a new or existing class for registrations. 669 | */ 670 | template 671 | CppBindClass beginClass(const char* name) 672 | { 673 | return CppBindClass::bind(m_meta, name); 674 | } 675 | 676 | /** 677 | * Open a new class to extend the base class. 678 | */ 679 | template 680 | CppBindClass beginExtendClass(const char* name) 681 | { 682 | return CppBindClass::template extend(m_meta, name); 683 | } 684 | 685 | private: 686 | LuaRef m_meta; 687 | }; 688 | -------------------------------------------------------------------------------- /LuaIntf/impl/CppFunction.h: -------------------------------------------------------------------------------- 1 | // 2 | // https://github.com/SteveKChiu/lua-intf 3 | // 4 | // Copyright 2014, Steve K. Chiu 5 | // 6 | // The MIT License (http://www.opensource.org/licenses/mit-license.php) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a 9 | // copy of this software and associated documentation files (the "Software"), 10 | // to deal in the Software without restriction, including without limitation 11 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the 13 | // Software is furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | // DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | /** 28 | * A template for temporately object created as lua function (with proper gc) 29 | * This is usually used for iterator function. 30 | * 31 | * To use this, user need to inherit CppFunctor, and override run method and optional descructor. 32 | * Then call make or pushToStack to create the functor object on lua stack. 33 | */ 34 | class CppFunctor 35 | { 36 | public: 37 | /** 38 | * Override destructor if you need to perform any cleanup action 39 | */ 40 | virtual ~CppFunctor() {} 41 | 42 | /** 43 | * Override this method to perform lua function 44 | */ 45 | virtual int run(lua_State* L) = 0; 46 | 47 | /** 48 | * Create the specified functor as callable lua object on stack 49 | */ 50 | static int pushToStack(lua_State* L, CppFunctor* f); 51 | 52 | /** 53 | * Create the specified functor as callable lua object on stack, 54 | * the functor is created inside userdata. This is different from 55 | * pushToStack, which only keep the functor pointer. This reduces the 56 | * overhead of extra pointer and memory allocation. 57 | */ 58 | template 59 | static int make(lua_State* L, ARGS&&... args) 60 | { 61 | void* mem = lua_newuserdata(L, sizeof(FUNCTOR)); 62 | ::new (mem) FUNCTOR(std::forward(args)...); 63 | return bind(L, &call, &gc); 64 | } 65 | 66 | private: 67 | static int call(lua_State* L); 68 | static int gc(lua_State* L); 69 | 70 | static int callp(lua_State* L); 71 | static int gcp(lua_State* L); 72 | 73 | static int bind(lua_State* L, lua_CFunction call, lua_CFunction gc); 74 | }; 75 | 76 | //--------------------------------------------------------------------------- 77 | 78 | template <> 79 | struct LuaTypeMapping 80 | { 81 | static void push(lua_State* L, lua_CFunction f) 82 | { 83 | lua_pushcfunction(L, f); 84 | } 85 | 86 | static lua_CFunction get(lua_State* L, int index) 87 | { 88 | return lua_tocfunction(L, index); 89 | } 90 | 91 | static lua_CFunction opt(lua_State* L, int index, lua_CFunction def) 92 | { 93 | return lua_isnoneornil(L, index) ? def : lua_tocfunction(L, index); 94 | } 95 | }; 96 | 97 | //---------------------------------------------------------------------------- 98 | 99 | template 100 | struct LuaCppFunctionWrapper 101 | { 102 | [[noreturn]] 103 | static const FN& get(lua_State* L, int) 104 | { 105 | luaL_error(L, "invalid c++ function reference"); 106 | } 107 | }; 108 | 109 | #if LUAINTF_STD_FUNCTION_WRAPPER 110 | 111 | template 112 | struct LuaCppFunctionWrapper > 113 | { 114 | static std::function get(lua_State* L, int index) 115 | { 116 | LuaRef ref(L, index); 117 | return [ref] (P&&... arg) mutable { 118 | return ref.call(std::forward

(arg)...); 119 | }; 120 | } 121 | }; 122 | 123 | #endif 124 | 125 | //---------------------------------------------------------------------------- 126 | 127 | /** 128 | * Lua conversion for std::function type 129 | */ 130 | template 131 | struct LuaCppFunction 132 | { 133 | using ReturnType = typename std::conditional::type; 134 | 135 | static void push(lua_State* L, const FN& proc) 136 | { 137 | using CppProc = CppBindMethod; 138 | LuaRef ref = LuaRef::createUserDataFrom(L, proc); 139 | ref.pushToStack(); 140 | lua_pushlightuserdata(L, CppSignature::value()); 141 | lua_pushcclosure(L, &CppProc::call, 2); 142 | } 143 | 144 | static ReturnType get(lua_State* L, int index) 145 | { 146 | index = lua_absindex(L, index); 147 | if (lua_iscfunction(L, index)) { 148 | const char* name = lua_getupvalue(L, index, 1); 149 | if (name && lua_isuserdata(L, -1)) { 150 | name = lua_getupvalue(L, index, 2); 151 | if (name && lua_touserdata(L, -1) == CppSignature::value()) { 152 | const FN& func = *reinterpret_cast(lua_touserdata(L, -2)); 153 | assert(func); 154 | lua_pop(L, 2); 155 | return func; 156 | } 157 | lua_pop(L, 1); 158 | } 159 | lua_pop(L, 1); 160 | } 161 | 162 | return LuaCppFunctionWrapper::get(L, index); 163 | } 164 | 165 | static ReturnType opt(lua_State* L, int index, const FN& def) 166 | { 167 | if (lua_isnoneornil(L, index)) { 168 | return def; 169 | } else { 170 | return get(L, index); 171 | } 172 | } 173 | }; 174 | 175 | template 176 | struct LuaTypeMapping 177 | : LuaCppFunction {}; 178 | 179 | template 180 | struct LuaTypeMapping > 181 | : LuaCppFunction > {}; 182 | 183 | -------------------------------------------------------------------------------- /LuaIntf/impl/CppInvoke.h: -------------------------------------------------------------------------------- 1 | // 2 | // https://github.com/SteveKChiu/lua-intf 3 | // 4 | // Copyright 2014, Steve K. Chiu 5 | // 6 | // The MIT License (http://www.opensource.org/licenses/mit-license.php) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a 9 | // copy of this software and associated documentation files (the "Software"), 10 | // to deal in the Software without restriction, including without limitation 11 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the 13 | // Software is furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | // DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | template 28 | struct CppCouldBeLambda 29 | { 30 | static constexpr bool value = std::is_class::value; 31 | }; 32 | 33 | template 34 | struct CppCouldBeLambda > 35 | { 36 | static constexpr bool value = false; 37 | }; 38 | 39 | template 40 | struct CppLambdaTraits 41 | : public CppLambdaTraits {}; 42 | 43 | template 44 | struct CppLambdaTraits 45 | { 46 | using FunctionType = std::function; 47 | }; 48 | 49 | template 50 | struct CppLambdaTraits 51 | { 52 | using FunctionType = std::function; 53 | }; 54 | 55 | //---------------------------------------------------------------------------- 56 | 57 | template 58 | struct CppDispatchMethod 59 | : CppDispatchMethod {}; 60 | 61 | template 62 | struct CppDispatchMethod 63 | { 64 | static R call(const FN& func, TUPLE& args) 65 | { 66 | return func(std::get(args).value()...); 67 | } 68 | }; 69 | 70 | template 71 | struct CppInvokeMethod 72 | { 73 | static R call(const FN& func, std::tuple& args) 74 | { 75 | return CppDispatchMethod, sizeof...(P)>::call(func, args); 76 | } 77 | 78 | static int push(lua_State* L, const FN& func, std::tuple& args) 79 | { 80 | LuaType::push(L, call(func, args)); 81 | return 1; 82 | } 83 | }; 84 | 85 | template 86 | struct CppInvokeMethod 87 | { 88 | static void call(const FN& func, std::tuple& args) 89 | { 90 | CppDispatchMethod, sizeof...(P)>::call(func, args); 91 | } 92 | 93 | static int push(lua_State*, const FN& func, std::tuple& args) 94 | { 95 | call(func, args); 96 | return 0; 97 | } 98 | }; 99 | 100 | template 101 | struct CppInvokeMethod , P...> 102 | { 103 | static int call(const FN& func, std::tuple, P...>& args) 104 | { 105 | return CppDispatchMethod, P...>, sizeof...(P) + 1>::call(func, args); 106 | } 107 | 108 | static int push(lua_State*, const FN& func, std::tuple, P...>& args) 109 | { 110 | return call(func, args); 111 | } 112 | }; 113 | 114 | template 115 | struct CppInvokeMethod , P...> 116 | { 117 | static int call(const FN& func, std::tuple, P...>& args) 118 | { 119 | return CppDispatchMethod, P...>, sizeof...(P) + 1>::call(func, args); 120 | } 121 | 122 | static int push(lua_State*, const FN& func, std::tuple, P...>& args) 123 | { 124 | return call(func, args); 125 | } 126 | }; 127 | 128 | template 129 | struct CppInvokeMethod , P...> 130 | { 131 | static std::tuple call(const FN& func, std::tuple& args) 132 | { 133 | return CppDispatchMethod, std::tuple, sizeof...(P)>::call(func, args); 134 | } 135 | 136 | static int push(lua_State* L, const FN& func, std::tuple& args) 137 | { 138 | std::tuple ret = call(func, args); 139 | return pushTuple<0, RP...>(L, ret); 140 | } 141 | 142 | private: 143 | template 144 | static int pushTuple(lua_State* L, const std::tuple& ret) 145 | { 146 | LuaType::push(L, std::get(ret)); 147 | return 1 + pushTuple(L, ret); 148 | } 149 | 150 | template 151 | static int pushTuple(lua_State*, const std::tuple&) 152 | { 153 | return 0; 154 | } 155 | }; 156 | 157 | //---------------------------------------------------------------------------- 158 | 159 | template 160 | struct CppDispatchClassConstructor 161 | : CppDispatchClassConstructor {}; 162 | 163 | template 164 | struct CppDispatchClassConstructor 165 | { 166 | static T* call(TUPLE& args) 167 | { 168 | return new T(std::get(args).value()...); 169 | } 170 | 171 | static T* call(void* mem, TUPLE& args) 172 | { 173 | return ::new (mem) T(std::get(args).value()...); 174 | } 175 | }; 176 | 177 | template 178 | struct CppInvokeClassConstructor 179 | { 180 | template 181 | static T* call(std::tuple& args) 182 | { 183 | return CppDispatchClassConstructor, sizeof...(P)>::call(args); 184 | } 185 | 186 | template 187 | static T* call(void* mem, std::tuple& args) 188 | { 189 | return CppDispatchClassConstructor, sizeof...(P)>::call(mem, args); 190 | } 191 | }; 192 | 193 | //---------------------------------------------------------------------------- 194 | 195 | template 196 | struct CppDispatchClassMethod 197 | : CppDispatchClassMethod {}; 198 | 199 | template 200 | struct CppDispatchClassMethod 201 | { 202 | static R call(T* t, const FN& fn, TUPLE& args) 203 | { 204 | return (t->*fn)(std::get(args).value()...); 205 | } 206 | }; 207 | 208 | template 209 | struct CppDispatchClassMethod 210 | { 211 | static R call(T* t, const FN& fn, TUPLE& args) 212 | { 213 | return fn(t, std::get(args).value()...); 214 | } 215 | }; 216 | 217 | template 218 | struct CppInvokeClassMethod 219 | { 220 | static R call(T* t, const FN& func, std::tuple& args) 221 | { 222 | return CppDispatchClassMethod, sizeof...(P)>::call(t, func, args); 223 | } 224 | 225 | static int push(lua_State* L, T* t, const FN& func, std::tuple& args) 226 | { 227 | LuaType::push(L, call(t, func, args)); 228 | return 1; 229 | } 230 | }; 231 | 232 | template 233 | struct CppInvokeClassMethod 234 | { 235 | static void call(T* t, const FN& func, std::tuple& args) 236 | { 237 | CppDispatchClassMethod, sizeof...(P)>::call(t, func, args); 238 | } 239 | 240 | static int push(lua_State*, T* t, const FN& func, std::tuple& args) 241 | { 242 | call(t, func, args); 243 | return 0; 244 | } 245 | }; 246 | 247 | template 248 | struct CppInvokeClassMethod , P...> 249 | { 250 | static int call(T* t, const FN& func, std::tuple, P...>& args) 251 | { 252 | return CppDispatchClassMethod, P...>, sizeof...(P) + 1>::call(t, func, args); 253 | } 254 | 255 | static int push(lua_State*, T* t, const FN& func, std::tuple, P...>& args) 256 | { 257 | return call(t, func, args); 258 | } 259 | }; 260 | 261 | template 262 | struct CppInvokeClassMethod , P...> 263 | { 264 | static int call(T* t, const FN& func, std::tuple, P...>& args) 265 | { 266 | return CppDispatchClassMethod, P...>, sizeof...(P) + 1>::call(t, func, args); 267 | } 268 | 269 | static int push(lua_State*, T* t, const FN& func, std::tuple, P...>& args) 270 | { 271 | return call(t, func, args); 272 | } 273 | }; 274 | 275 | template 276 | struct CppInvokeClassMethod , P...> 277 | { 278 | static std::tuple call(T* t, const FN& func, std::tuple& args) 279 | { 280 | return CppDispatchClassMethod, std::tuple, sizeof...(P)>::call(t, func, args); 281 | } 282 | 283 | static int push(lua_State* L, T* t, const FN& func, std::tuple& args) 284 | { 285 | std::tuple ret = call(t, func, args); 286 | return pushTuple<0, RP...>(L, ret); 287 | } 288 | 289 | private: 290 | template 291 | static int pushTuple(lua_State* L, const std::tuple& ret) 292 | { 293 | LuaType::push(L, std::get(ret)); 294 | return 1 + pushTuple(L, ret); 295 | } 296 | 297 | template 298 | static int pushTuple(lua_State*, const std::tuple&) 299 | { 300 | return 0; 301 | } 302 | }; 303 | -------------------------------------------------------------------------------- /LuaIntf/impl/CppObject.h: -------------------------------------------------------------------------------- 1 | // 2 | // https://github.com/SteveKChiu/lua-intf 3 | // 4 | // Copyright 2014, Steve K. Chiu 5 | // 6 | // The MIT License (http://www.opensource.org/licenses/mit-license.php) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a 9 | // copy of this software and associated documentation files (the "Software"), 10 | // to deal in the Software without restriction, including without limitation 11 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the 13 | // Software is furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | // DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | template 28 | struct CppSignature 29 | { 30 | /** 31 | * Get the signature id for type 32 | * 33 | * The id is unique in the process 34 | */ 35 | static void* value() 36 | { 37 | static bool v = false; 38 | return &v; 39 | } 40 | }; 41 | 42 | template 43 | using CppClassSignature = CppSignature; 44 | 45 | template 46 | using CppConstSignature = CppSignature; 47 | 48 | //-------------------------------------------------------------------------- 49 | 50 | /** 51 | * Because of Lua's dynamic typing and our improvised system of imposing C++ 52 | * class structure, there is the possibility that executing scripts may 53 | * knowingly or unknowingly cause invalid data to get passed to the C functions 54 | * created by LuaIntf. To improve type security, we have the following policy: 55 | * 56 | * 1. Scripts cannot set the metatable on a userdata 57 | * 2. CppObject's metatable has been tagged by typeid 58 | * 3. CppObject's typeid is a unique pointer in the process. 59 | * 4. Access to CppObject class method will check for typeid, and raise error if not matched 60 | */ 61 | class CppObject 62 | { 63 | protected: 64 | CppObject() {} 65 | 66 | template 67 | static void* allocate(lua_State* L, void* class_id) 68 | { 69 | void* mem = lua_newuserdata(L, sizeof(OBJ)); 70 | lua_rawgetp(L, LUA_REGISTRYINDEX, class_id); 71 | luaL_checktype(L, -1, LUA_TTABLE); 72 | lua_setmetatable(L, -2); 73 | return mem; 74 | } 75 | 76 | public: 77 | virtual ~CppObject() {} 78 | 79 | CppObject(const CppObject&) = delete; 80 | CppObject& operator = (const CppObject&) = delete; 81 | 82 | /** 83 | * Whether the object is shared pointer 84 | */ 85 | virtual bool isSharedPtr() const 86 | { 87 | return false; 88 | } 89 | 90 | /** 91 | * The object pointer 92 | */ 93 | virtual void* objectPtr() = 0; 94 | 95 | /** 96 | * Get internal class id of the given class 97 | */ 98 | template 99 | static void* getClassID(bool is_const) 100 | { 101 | return is_const ? CppConstSignature::value() : CppClassSignature::value(); 102 | } 103 | 104 | /** 105 | * Returns the CppObject* if the class on the Lua stack is exact the same class (not one of the subclass). 106 | * If the class does not match, a Lua error is raised. 107 | */ 108 | template 109 | static CppObject* getExactObject(lua_State* L, int index, bool is_const) 110 | { 111 | return getObject(L, index, getClassID(is_const), is_const, true, true); 112 | } 113 | 114 | /** 115 | * Returns the CppObject* if the object on the Lua stack is an instance of the given class. 116 | * If the object is not the class or a subclass, a Lua error is raised. 117 | */ 118 | template 119 | static CppObject* getObject(lua_State* L, int index, bool is_const) 120 | { 121 | return getObject(L, index, getClassID(is_const), is_const, false, true); 122 | } 123 | 124 | /** 125 | * Get a pointer to the class from the Lua stack. 126 | * 127 | * If the object is not the class or a subclass, return nullptr. 128 | */ 129 | template 130 | static T* cast(lua_State* L, int index, bool is_const) 131 | { 132 | CppObject* object = getObject(L, index, getClassID(is_const), is_const, false, false); 133 | return object ? static_cast(object->objectPtr()) : nullptr; 134 | } 135 | 136 | /** 137 | * Get a pointer to the class from the Lua stack. 138 | * 139 | * If the object is not the class or a subclass, a Lua error is raised. 140 | */ 141 | template 142 | static T* get(lua_State* L, int index, bool is_const) 143 | { 144 | return static_cast(getObject(L, index, is_const)->objectPtr()); 145 | } 146 | 147 | private: 148 | static void typeMismatchError(lua_State* L, int index); 149 | static CppObject* getObject(lua_State* L, int index, void* class_id, 150 | bool is_const, bool is_exact, bool raise_error); 151 | }; 152 | 153 | //---------------------------------------------------------------------------- 154 | 155 | class CppAutoDowncast 156 | { 157 | #if LUAINTF_AUTO_DOWNCAST 158 | 159 | private: 160 | template 161 | static void* tryDowncast(SUPER* obj) { 162 | void* casted = dynamic_cast(obj); 163 | if (casted == obj) { 164 | return CppObject::getClassID(IS_CONST); 165 | } else { 166 | return nullptr; 167 | } 168 | } 169 | 170 | template 171 | static void addDowncast(LuaRef super) { 172 | lua_State* L = super.state(); 173 | LuaRef downcast = LuaRef::createUserDataFrom(L, &tryDowncast); 174 | 175 | void* class_id = CppObject::getClassID(IS_CONST); 176 | bool* class_may_downcast = static_cast(class_id); 177 | *class_may_downcast = true; 178 | 179 | LuaRef list = super.rawget("__downcast"); 180 | if (list == nullptr) { 181 | list = LuaRef::createTable(L); 182 | super.rawset("__downcast", list); 183 | } 184 | list.rawset(list.rawlen() + 1, downcast); 185 | } 186 | 187 | static void* findClassID(lua_State* L, void* obj, void* class_id) { 188 | bool class_may_downcast = *static_cast(class_id); 189 | if (!class_may_downcast) return class_id; 190 | 191 | // 192 | lua_rawgetp(L, LUA_REGISTRYINDEX, class_id); 193 | luaL_checktype(L, -1, LUA_TTABLE); 194 | 195 | // 196 | lua_pushliteral(L, "__downcast"); 197 | lua_rawget(L, -2); 198 | 199 | if (!lua_isnil(L, -1)) { 200 | int len = int(lua_rawlen(L, -1)); 201 | for (int i = 1; i <= len; i++) { 202 | // 203 | lua_rawgeti(L, -1, i); 204 | auto downcast = *reinterpret_cast(lua_touserdata(L, -1)); 205 | 206 | void* cast_class_id = downcast(obj); 207 | if (cast_class_id) { 208 | lua_pop(L, 3); 209 | return findClassID(L, obj, cast_class_id); 210 | } 211 | 212 | lua_pop(L, 1); 213 | } 214 | } 215 | 216 | lua_pop(L, 2); 217 | return class_id; 218 | } 219 | 220 | public: 221 | template 222 | static void add(lua_State* L) { 223 | LuaRef registry(L, LUA_REGISTRYINDEX); 224 | LuaRef super = registry.rawgetp(CppSignature::value()); 225 | addDowncast(super.rawget("___class")); 226 | addDowncast(super.rawget("___const")); 227 | } 228 | 229 | template 230 | static void* getClassID(lua_State* L, T* obj, bool is_const) { 231 | void* class_id = CppObject::getClassID(is_const); 232 | return findClassID(L, obj, class_id); 233 | } 234 | 235 | #else 236 | 237 | public: 238 | template 239 | static void* getClassID(lua_State*, T*, bool is_const) { 240 | return CppObject::getClassID(is_const); 241 | } 242 | 243 | #endif 244 | }; 245 | 246 | //---------------------------------------------------------------------------- 247 | 248 | /** 249 | * Wraps a class object stored in a Lua userdata. 250 | * 251 | * The lifetime of the object is managed by Lua. The object is constructed 252 | * inside the userdata using placement new. 253 | */ 254 | template 255 | class CppObjectValue : public CppObject 256 | { 257 | private: 258 | CppObjectValue() 259 | { 260 | if (MAX_PADDING > 0) { 261 | uintptr_t offset = reinterpret_cast(&m_data[0]) % alignof(T); 262 | if (offset > 0) offset = alignof(T) - offset; 263 | assert(offset < MAX_PADDING); 264 | m_data[sizeof(m_data) - 1] = static_cast(offset); 265 | } 266 | } 267 | 268 | public: 269 | virtual ~CppObjectValue() 270 | { 271 | T* obj = static_cast(objectPtr()); 272 | obj->~T(); 273 | } 274 | 275 | virtual void* objectPtr() override 276 | { 277 | if (MAX_PADDING == 0) { 278 | return &m_data[0]; 279 | } else { 280 | return &m_data[0] + m_data[sizeof(m_data) - 1]; 281 | } 282 | } 283 | 284 | template 285 | static void pushToStack(lua_State* L, bool is_const, P&&... args) 286 | { 287 | void* mem = allocate>(L, getClassID(is_const)); 288 | CppObjectValue* v = ::new (mem) CppObjectValue(); 289 | ::new (v->objectPtr()) T(std::forward

(args)...); 290 | } 291 | 292 | template 293 | static void pushToStack(lua_State* L, std::tuple& args, bool is_const) 294 | { 295 | void* mem = allocate>(L, getClassID(is_const)); 296 | CppObjectValue* v = ::new (mem) CppObjectValue(); 297 | CppInvokeClassConstructor::call(v->objectPtr(), args); 298 | } 299 | 300 | static void pushToStack(lua_State* L, const T& obj, bool is_const) 301 | { 302 | void* mem = allocate>(L, getClassID(is_const)); 303 | CppObjectValue* v = ::new (mem) CppObjectValue(); 304 | ::new (v->objectPtr()) T(obj); 305 | } 306 | 307 | private: 308 | using AlignType = typename std::conditional::type; 309 | static constexpr int MAX_PADDING = alignof(T) <= alignof(AlignType) ? 0 : alignof(T) - alignof(AlignType) + 1; 310 | alignas(AlignType) unsigned char m_data[sizeof(T) + MAX_PADDING]; 311 | }; 312 | 313 | //---------------------------------------------------------------------------- 314 | 315 | /** 316 | * Wraps a pointer to a class object inside a Lua userdata. 317 | * 318 | * The lifetime of the object is managed by C++. 319 | */ 320 | class CppObjectPtr : public CppObject 321 | { 322 | private: 323 | explicit CppObjectPtr(void* obj) 324 | : m_ptr(obj) 325 | { 326 | assert(obj != nullptr); 327 | } 328 | 329 | public: 330 | virtual void* objectPtr() override 331 | { 332 | return m_ptr; 333 | } 334 | 335 | template 336 | static void pushToStack(lua_State* L, T* obj, bool is_const) 337 | { 338 | void* mem = allocate(L, CppAutoDowncast::getClassID(L, obj, is_const)); 339 | ::new (mem) CppObjectPtr(obj); 340 | } 341 | 342 | private: 343 | void* m_ptr; 344 | }; 345 | 346 | //---------------------------------------------------------------------------- 347 | 348 | /** 349 | * Wraps a shared ptr that references a class object. 350 | * 351 | * The template argument SP is the smart pointer type 352 | */ 353 | template 354 | class CppObjectSharedPtr : public CppObject 355 | { 356 | private: 357 | explicit CppObjectSharedPtr(T* obj) 358 | : m_sp(obj) 359 | {} 360 | 361 | explicit CppObjectSharedPtr(const SP& sp) 362 | : m_sp(sp) 363 | {} 364 | 365 | public: 366 | virtual bool isSharedPtr() const override 367 | { 368 | return true; 369 | } 370 | 371 | virtual void* objectPtr() override 372 | { 373 | return const_cast(&*m_sp); 374 | } 375 | 376 | SP& sharedPtr() 377 | { 378 | return m_sp; 379 | } 380 | 381 | static void pushToStack(lua_State* L, T* obj, bool is_const) 382 | { 383 | void* mem = allocate>(L, 384 | CppAutoDowncast::getClassID(L, obj, is_const)); 385 | ::new (mem) CppObjectSharedPtr(obj); 386 | } 387 | 388 | static void pushToStack(lua_State* L, const SP& sp, bool is_const) 389 | { 390 | void* mem = allocate>(L, 391 | CppAutoDowncast::getClassID(L, const_cast(&*sp), is_const)); 392 | ::new (mem) CppObjectSharedPtr(sp); 393 | } 394 | 395 | private: 396 | SP m_sp; 397 | }; 398 | 399 | //---------------------------------------------------------------------------- 400 | 401 | template 402 | struct CppObjectTraits 403 | { 404 | using ObjectType = T; 405 | 406 | static constexpr bool isSharedPtr = false; 407 | static constexpr bool isSharedConst = false; 408 | }; 409 | 410 | #define LUA_USING_SHARED_PTR_TYPE(SP) \ 411 | template \ 412 | struct CppObjectTraits > \ 413 | { \ 414 | using ObjectType = typename std::remove_cv::type; \ 415 | \ 416 | static constexpr bool isSharedPtr = true; \ 417 | static constexpr bool isSharedConst = std::is_const::value; \ 418 | }; 419 | 420 | //--------------------------------------------------------------------------- 421 | 422 | template 423 | struct LuaCppObjectFactory; 424 | 425 | template 426 | struct LuaCppObjectFactory 427 | { 428 | static void push(lua_State* L, const T& obj, bool is_const) 429 | { 430 | CppObjectValue::pushToStack(L, obj, is_const); 431 | } 432 | 433 | static T& cast(lua_State*, CppObject* obj) 434 | { 435 | return *static_cast(obj->objectPtr()); 436 | } 437 | }; 438 | 439 | template 440 | struct LuaCppObjectFactory 441 | { 442 | static void push(lua_State* L, const T& obj, bool is_const) 443 | { 444 | CppObjectPtr::pushToStack(L, const_cast(&obj), is_const); 445 | } 446 | 447 | static T& cast(lua_State*, CppObject* obj) 448 | { 449 | return *static_cast(obj->objectPtr()); 450 | } 451 | }; 452 | 453 | template 454 | struct LuaCppObjectFactory 455 | { 456 | static void push(lua_State* L, const SP& sp, bool is_const) 457 | { 458 | if (!sp) { 459 | lua_pushnil(L); 460 | } else { 461 | CppObjectSharedPtr::pushToStack(L, sp, is_const); 462 | } 463 | } 464 | 465 | static SP& cast(lua_State* L, CppObject* obj) 466 | { 467 | if (!obj->isSharedPtr()) { 468 | luaL_error(L, "is not shared object"); 469 | } 470 | return static_cast*>(obj)->sharedPtr(); 471 | } 472 | }; 473 | 474 | //--------------------------------------------------------------------------- 475 | 476 | /** 477 | * Lua conversion for reference or value to the class type, 478 | * this will catch all C++ class unless LuaTypeMapping<> exists. 479 | */ 480 | template 481 | struct LuaClassMapping 482 | { 483 | using ObjectType = typename CppObjectTraits::ObjectType; 484 | 485 | static constexpr bool isShared = CppObjectTraits::isSharedPtr; 486 | static constexpr bool isRef = isShared ? true : IS_REF; 487 | static constexpr bool isConst = isShared ? CppObjectTraits::isSharedConst : IS_CONST; 488 | 489 | static void push(lua_State* L, const T& t) 490 | { 491 | LuaCppObjectFactory::push(L, t, isConst); 492 | } 493 | 494 | static T& get(lua_State* L, int index) 495 | { 496 | CppObject* obj = CppObject::getObject(L, index, isConst); 497 | return LuaCppObjectFactory::cast(L, obj); 498 | } 499 | 500 | static const T& opt(lua_State* L, int index, const T& def) 501 | { 502 | if (lua_isnoneornil(L, index)) { 503 | return def; 504 | } else { 505 | return get(L, index); 506 | } 507 | } 508 | }; 509 | 510 | //---------------------------------------------------------------------------- 511 | 512 | /** 513 | * Lua conversion for pointer to the class type 514 | */ 515 | template 516 | struct LuaTypeMapping 517 | { 518 | using Type = typename std::decay::type; 519 | using PtrType = T*; 520 | 521 | static constexpr bool isConst = std::is_const::value; 522 | 523 | static void push(lua_State* L, const Type* p) 524 | { 525 | if (p == nullptr) { 526 | lua_pushnil(L); 527 | } else { 528 | CppObjectPtr::pushToStack(L, const_cast(p), isConst); 529 | } 530 | } 531 | 532 | static PtrType get(lua_State* L, int index) 533 | { 534 | return CppObject::get(L, index, isConst); 535 | } 536 | 537 | static PtrType opt(lua_State* L, int index, PtrType def) 538 | { 539 | if (lua_isnoneornil(L, index)) { 540 | return def; 541 | } else { 542 | return CppObject::get(L, index, isConst); 543 | } 544 | } 545 | }; 546 | 547 | //---------------------------------------------------------------------------- 548 | 549 | namespace Lua 550 | { 551 | /** 552 | * Create new object inside userdata directly and push onto Lua stack. 553 | */ 554 | template 555 | inline void pushNew(lua_State* L, P&&... args) 556 | { 557 | CppObjectValue::type>::pushToStack(L, std::is_const::value, std::forward

(args)...); 558 | } 559 | 560 | /** 561 | * Cast stack value at the index to the given class, return nullptr if it is not. 562 | */ 563 | template 564 | inline T* objectCast(lua_State* L, int index) 565 | { 566 | return CppObject::cast::type>(L, index, std::is_const::value); 567 | } 568 | 569 | /** 570 | * Cast LuaRef to the given class, return nullptr if it is not. 571 | */ 572 | template 573 | inline T* objectCast(const LuaRef& ref) 574 | { 575 | ref.pushToStack(); 576 | T* object = objectCast(ref.state(), -1); 577 | lua_pop(ref.state(), 1); 578 | return object; 579 | } 580 | } 581 | 582 | /** 583 | * Create LuaRef for cpp class, the object is created inside userdata directly. 584 | */ 585 | template 586 | inline LuaRef LuaRefObject(lua_State* L, P&&... args) 587 | { 588 | Lua::pushNew(L, std::forward

(args)...); 589 | return LuaRef::popFromStack(L); 590 | } 591 | -------------------------------------------------------------------------------- /LuaIntf/impl/LuaException.h: -------------------------------------------------------------------------------- 1 | // 2 | // https://github.com/SteveKChiu/lua-intf 3 | // 4 | // Copyright 2014, Steve K. Chiu 5 | // 6 | // The MIT License (http://www.opensource.org/licenses/mit-license.php) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a 9 | // copy of this software and associated documentation files (the "Software"), 10 | // to deal in the Software without restriction, including without limitation 11 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the 13 | // Software is furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | // DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | class LuaException : public std::exception 28 | { 29 | public: 30 | explicit LuaException(lua_State* L) noexcept 31 | { 32 | if (lua_gettop(L) > 0) { 33 | m_what = lua_tostring(L, -1); 34 | } else { 35 | m_what = "unknown error"; 36 | } 37 | } 38 | 39 | explicit LuaException(const char* msg) noexcept 40 | : m_what(msg) 41 | {} 42 | 43 | explicit LuaException(const std::string& msg) noexcept 44 | : m_what(msg) 45 | {} 46 | 47 | const char* what() const noexcept 48 | { 49 | return m_what.c_str(); 50 | } 51 | 52 | static int traceback(lua_State* L) 53 | { 54 | if (!lua_isstring(L, 1)) return 1; 55 | lua_getglobal(L, "debug"); 56 | if (!lua_istable(L, -1)) { 57 | lua_pop(L, 1); 58 | return 1; 59 | } 60 | lua_getfield(L, -1, "traceback"); 61 | if (!lua_isfunction(L, -1)) { 62 | lua_pop(L, 2); 63 | return 1; 64 | } 65 | lua_pushvalue(L, 1); // pass error message 66 | lua_call(L, 1, 1); // call debug.traceback 67 | return 1; 68 | } 69 | 70 | private: 71 | std::string m_what; 72 | }; 73 | -------------------------------------------------------------------------------- /LuaIntf/impl/LuaType.h: -------------------------------------------------------------------------------- 1 | // 2 | // https://github.com/SteveKChiu/lua-intf 3 | // 4 | // Copyright 2014, Steve K. Chiu 5 | // 6 | // The MIT License (http://www.opensource.org/licenses/mit-license.php) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a 9 | // copy of this software and associated documentation files (the "Software"), 10 | // to deal in the Software without restriction, including without limitation 11 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the 13 | // Software is furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | // DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | enum class LuaTypeID 28 | { 29 | NONE = LUA_TNONE, 30 | NIL = LUA_TNIL, 31 | STRING = LUA_TSTRING, 32 | NUMBER = LUA_TNUMBER, 33 | THREAD = LUA_TTHREAD, 34 | BOOLEAN = LUA_TBOOLEAN, 35 | FUNCTION = LUA_TFUNCTION, 36 | TABLE = LUA_TTABLE, 37 | USERDATA = LUA_TUSERDATA, 38 | LIGHTUSERDATA = LUA_TLIGHTUSERDATA 39 | }; 40 | 41 | template 42 | struct LuaTypeMapping; 43 | 44 | template 45 | struct LuaClassMapping; 46 | 47 | //--------------------------------------------------------------------------- 48 | 49 | struct LuaTypeExists 50 | { 51 | template 52 | static std::true_type test(int); 53 | 54 | template 55 | static std::false_type test(...); 56 | }; 57 | 58 | template 59 | struct LuaTypeMappingExists 60 | { 61 | using Type = decltype(LuaTypeExists::test>(0)); 62 | static constexpr bool value = Type::value; 63 | }; 64 | 65 | template 66 | struct LuaType 67 | : std::conditional< 68 | std::is_class::type>::value 69 | && !LuaTypeMappingExists::type>::value, 70 | LuaClassMapping::type, 71 | std::is_const::type>::value, 72 | std::is_reference::value>, 73 | LuaTypeMapping::type> 74 | >::type {}; 75 | 76 | //--------------------------------------------------------------------------- 77 | 78 | template <> 79 | struct LuaTypeMapping 80 | { 81 | static void push(lua_State* L, bool value) 82 | { 83 | lua_pushboolean(L, value); 84 | } 85 | 86 | static bool get(lua_State* L, int index) 87 | { 88 | return lua_toboolean(L, index) != 0; 89 | } 90 | 91 | static bool opt(lua_State* L, int index, bool def) 92 | { 93 | return lua_isnone(L, index) ? def : lua_toboolean(L, index) != 0; 94 | } 95 | }; 96 | 97 | //--------------------------------------------------------------------------- 98 | 99 | template 100 | struct LuaIntegerTypeMapping 101 | { 102 | static void push(lua_State* L, T value) 103 | { 104 | lua_pushinteger(L, static_cast(value)); 105 | } 106 | 107 | static T get(lua_State* L, int index) 108 | { 109 | return static_cast(luaL_checkinteger(L, index)); 110 | } 111 | 112 | static T opt(lua_State* L, int index, T def) 113 | { 114 | return static_cast(luaL_optinteger(L, index, static_cast(def))); 115 | } 116 | }; 117 | 118 | template <> 119 | struct LuaTypeMapping 120 | : LuaIntegerTypeMapping {}; 121 | 122 | template <> 123 | struct LuaTypeMapping 124 | : LuaIntegerTypeMapping {}; 125 | 126 | template <> 127 | struct LuaTypeMapping 128 | : LuaIntegerTypeMapping {}; 129 | 130 | template <> 131 | struct LuaTypeMapping 132 | : LuaIntegerTypeMapping {}; 133 | 134 | //--------------------------------------------------------------------------- 135 | 136 | #if LUA_VERSION_NUM <= 502 137 | 138 | template 139 | struct LuaUnsignedTypeMapping 140 | { 141 | static void push(lua_State* L, T value) 142 | { 143 | lua_pushunsigned(L, static_cast(value)); 144 | } 145 | 146 | static T get(lua_State* L, int index) 147 | { 148 | return static_cast(luaL_checkunsigned(L, index)); 149 | } 150 | 151 | static T opt(lua_State* L, int index, T def) 152 | { 153 | return static_cast(luaL_optunsigned(L, index, static_cast(def))); 154 | } 155 | }; 156 | 157 | #else 158 | 159 | template 160 | using LuaUnsignedTypeMapping = LuaIntegerTypeMapping; 161 | 162 | #endif 163 | 164 | template <> 165 | struct LuaTypeMapping 166 | : LuaUnsignedTypeMapping {}; 167 | 168 | template <> 169 | struct LuaTypeMapping 170 | : LuaUnsignedTypeMapping {}; 171 | 172 | template <> 173 | struct LuaTypeMapping 174 | : LuaUnsignedTypeMapping {}; 175 | 176 | template <> 177 | struct LuaTypeMapping 178 | : LuaUnsignedTypeMapping {}; 179 | 180 | //--------------------------------------------------------------------------- 181 | 182 | template 183 | struct LuaNumberTypeMapping 184 | { 185 | static void push(lua_State* L, T value) 186 | { 187 | lua_pushnumber(L, static_cast(value)); 188 | } 189 | 190 | static T get(lua_State* L, int index) 191 | { 192 | return static_cast(luaL_checknumber(L, index)); 193 | } 194 | 195 | static T opt(lua_State* L, int index, T def) 196 | { 197 | return static_cast(luaL_optnumber(L, index, static_cast(def))); 198 | } 199 | }; 200 | 201 | template <> 202 | struct LuaTypeMapping 203 | : LuaNumberTypeMapping {}; 204 | 205 | template <> 206 | struct LuaTypeMapping 207 | : LuaNumberTypeMapping {}; 208 | 209 | template <> 210 | struct LuaTypeMapping 211 | : LuaNumberTypeMapping {}; 212 | 213 | //--------------------------------------------------------------------------- 214 | 215 | #if LUAINTF_UNSAFE_INT64 && (LUA_VERSION_NUM <= 502 || defined(LUA_32BITS)) 216 | 217 | template 218 | struct LuaUnsafeInt64TypeMapping 219 | { 220 | static void push(lua_State* L, T value) 221 | { 222 | lua_Number f = static_cast(value); 223 | #if LUAINTF_UNSAFE_INT64_CHECK 224 | T verify = static_cast(f); 225 | if (value != verify) { 226 | luaL_error(L, "unsafe cast from 64-bit int"); 227 | } 228 | #endif 229 | lua_pushnumber(L, f); 230 | } 231 | 232 | static T get(lua_State* L, int index) 233 | { 234 | return static_cast(luaL_checknumber(L, index)); 235 | } 236 | 237 | static T opt(lua_State* L, int index, T def) 238 | { 239 | return lua_isnoneornil(L, index) ? def : static_cast(luaL_checknumber(L, index)); 240 | } 241 | }; 242 | 243 | template <> 244 | struct LuaTypeMapping 245 | : LuaUnsafeInt64TypeMapping {}; 246 | 247 | template <> 248 | struct LuaTypeMapping 249 | : LuaUnsafeInt64TypeMapping {}; 250 | 251 | #elif LUA_VERSION_NUM >= 503 252 | 253 | template <> 254 | struct LuaTypeMapping 255 | : LuaIntegerTypeMapping {}; 256 | 257 | template <> 258 | struct LuaTypeMapping 259 | : LuaIntegerTypeMapping {}; 260 | 261 | #endif 262 | 263 | //--------------------------------------------------------------------------- 264 | 265 | template <> 266 | struct LuaTypeMapping 267 | { 268 | static void push(lua_State* L, char value) 269 | { 270 | char str[] = { value, 0 }; 271 | lua_pushstring(L, str); 272 | } 273 | 274 | static char get(lua_State* L, int index) 275 | { 276 | return luaL_checkstring(L, index)[0]; 277 | } 278 | 279 | static char opt(lua_State* L, int index, char def) 280 | { 281 | return lua_isnoneornil(L, index) ? def : get(L, index); 282 | } 283 | }; 284 | 285 | //--------------------------------------------------------------------------- 286 | 287 | template <> 288 | struct LuaTypeMapping 289 | { 290 | static void push(lua_State* L, const char* str) 291 | { 292 | lua_pushstring(L, str); 293 | } 294 | 295 | static const char* get(lua_State* L, int index) 296 | { 297 | return luaL_checkstring(L, index); 298 | } 299 | 300 | static const char* opt(lua_State* L, int index, const char* def) 301 | { 302 | return luaL_optstring(L, index, def); 303 | } 304 | }; 305 | 306 | //--------------------------------------------------------------------------- 307 | 308 | template <> 309 | struct LuaTypeMapping 310 | { 311 | static void push(lua_State* L, const char* str) 312 | { 313 | lua_pushstring(L, str); 314 | } 315 | }; 316 | 317 | //--------------------------------------------------------------------------- 318 | 319 | template <> 320 | struct LuaTypeMapping 321 | { 322 | static void push(lua_State* L, const std::string& str) 323 | { 324 | lua_pushlstring(L, str.data(), str.length()); 325 | } 326 | 327 | static std::string get(lua_State* L, int index) 328 | { 329 | size_t len; 330 | const char* p = luaL_checklstring(L, index, &len); 331 | return std::string(p, len); 332 | } 333 | 334 | static std::string opt(lua_State* L, int index, const std::string& def) 335 | { 336 | return lua_isnoneornil(L, index) ? def : get(L, index); 337 | } 338 | }; 339 | 340 | //--------------------------------------------------------------------------- 341 | 342 | #if LUAINTF_STD_WIDE_STRING 343 | 344 | template 345 | struct LuaTypeMapping > 346 | { 347 | using WString = std::basic_string; 348 | using WStringConvert = std::wstring_convert, CH>; 349 | 350 | static void push(lua_State* L, const WString& str) 351 | { 352 | if (str.empty()) { 353 | lua_pushliteral(L, ""); 354 | } else { 355 | WStringConvert conv; 356 | std::string buf = conv.to_bytes(str); 357 | lua_pushlstring(L, buf.data(), buf.length()); 358 | } 359 | } 360 | 361 | static WString get(lua_State* L, int index) 362 | { 363 | size_t len; 364 | const char* p = luaL_checklstring(L, index, &len); 365 | WStringConvert conv; 366 | return conv.from_bytes(p, p + len); 367 | } 368 | 369 | static WString opt(lua_State* L, int index, const WString& def) 370 | { 371 | return lua_isnoneornil(L, index) ? def : get(L, index); 372 | } 373 | }; 374 | 375 | #endif 376 | 377 | //--------------------------------------------------------------------------- 378 | 379 | /** 380 | * Transitient string type without copying underlying char values, use with caution. 381 | * It works like const char* with length field. 382 | */ 383 | struct LuaString 384 | { 385 | constexpr LuaString() 386 | : data(nullptr) 387 | , size(0) 388 | {} 389 | 390 | LuaString(const std::string& str) 391 | : data(str.data()) 392 | , size(str.size()) 393 | {} 394 | 395 | LuaString(const char* str) 396 | : data(str) 397 | , size(std::strlen(str)) 398 | {} 399 | 400 | LuaString(const char* str, size_t len) 401 | : data(str) 402 | , size(len) 403 | {} 404 | 405 | LuaString(lua_State* L, int index) 406 | { 407 | data = luaL_checklstring(L, index, &size); 408 | } 409 | 410 | explicit operator bool () const 411 | { 412 | return data != nullptr; 413 | } 414 | 415 | const char* data; 416 | size_t size; 417 | }; 418 | 419 | template <> 420 | struct LuaTypeMapping 421 | { 422 | static void push(lua_State* L, const LuaString& str) 423 | { 424 | if (str.data) { 425 | lua_pushlstring(L, str.data, str.size); 426 | } else { 427 | lua_pushnil(L); 428 | } 429 | } 430 | 431 | static LuaString get(lua_State* L, int index) 432 | { 433 | return LuaString(L, index); 434 | } 435 | 436 | static LuaString opt(lua_State* L, int index, const LuaString& def) 437 | { 438 | return lua_isnoneornil(L, index) ? def : LuaString(L, index); 439 | } 440 | }; 441 | 442 | //--------------------------------------------------------------------------- 443 | 444 | /** 445 | * Default type mapping to catch all enum conversion 446 | */ 447 | #if LUA_VERSION_NUM <= 502 448 | 449 | template 450 | struct LuaTypeMapping ::value>::type> 451 | : std::conditional< 452 | std::is_unsigned::type>::value, 453 | LuaUnsignedTypeMapping, 454 | LuaIntegerTypeMapping 455 | >::type {}; 456 | 457 | #else 458 | 459 | template 460 | struct LuaTypeMapping ::value>::type> 461 | : LuaIntegerTypeMapping {}; 462 | 463 | #endif 464 | 465 | //--------------------------------------------------------------------------- 466 | 467 | /** 468 | * Template for list container type 469 | */ 470 | #define LUA_USING_LIST_TYPE_X(LIST, ...) \ 471 | template <__VA_ARGS__> \ 472 | struct LuaTypeMapping \ 473 | { \ 474 | static void push(lua_State* L, const LIST& v) \ 475 | { \ 476 | if (v.empty()) { \ 477 | lua_newtable(L); \ 478 | } else { \ 479 | Lua::pushList(L, v); \ 480 | } \ 481 | } \ 482 | \ 483 | static LIST get(lua_State* L, int index) \ 484 | { \ 485 | return lua_isnoneornil(L, index) ? LIST() : Lua::getList(L, index); \ 486 | } \ 487 | \ 488 | static LIST opt(lua_State* L, int index, const LIST& def) \ 489 | { \ 490 | return lua_isnoneornil(L, index) ? def : Lua::getList(L, index); \ 491 | } \ 492 | }; 493 | 494 | #define LUA_USING_LIST_TYPE(LIST) \ 495 | LUA_USING_LIST_TYPE_X(LIST, typename T) 496 | 497 | //--------------------------------------------------------------------------- 498 | 499 | /** 500 | * Template for map container type 501 | */ 502 | #define LUA_USING_MAP_TYPE_X(MAP, ...) \ 503 | template <__VA_ARGS__> \ 504 | struct LuaTypeMapping \ 505 | { \ 506 | static void push(lua_State* L, const MAP& v) \ 507 | { \ 508 | if (v.empty()) { \ 509 | lua_newtable(L); \ 510 | } else { \ 511 | Lua::pushMap(L, v); \ 512 | } \ 513 | } \ 514 | \ 515 | static MAP get(lua_State* L, int index) \ 516 | { \ 517 | return lua_isnoneornil(L, index) ? MAP() : Lua::getMap(L, index); \ 518 | } \ 519 | \ 520 | static MAP opt(lua_State* L, int index, const MAP& def) \ 521 | { \ 522 | return lua_isnoneornil(L, index) ? def : Lua::getMap(L, index); \ 523 | } \ 524 | }; 525 | 526 | #define LUA_COMMA , 527 | 528 | #define LUA_USING_MAP_TYPE(MAP) \ 529 | LUA_USING_MAP_TYPE_X(MAP, typename K, typename V) 530 | -------------------------------------------------------------------------------- /LuaIntf/src/CppBindClass.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // https://github.com/SteveKChiu/lua-intf 3 | // 4 | // Copyright 2014, Steve K. Chiu 5 | // 6 | // The MIT License (http://www.opensource.org/licenses/mit-license.php) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a 9 | // copy of this software and associated documentation files (the "Software"), 10 | // to deal in the Software without restriction, including without limitation 11 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the 13 | // Software is furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | // DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | #ifndef LUAINTF_H 28 | #include "LuaIntf/LuaIntf.h" 29 | using namespace LuaIntf; 30 | #endif 31 | 32 | //--------------------------------------------------------------------------- 33 | 34 | LUA_INLINE int CppBindClassMetaMethod::index(lua_State* L) 35 | { 36 | // -> table or userdata 37 | // -> key 38 | 39 | // get signature metatable -> 40 | lua_getmetatable(L, 1); 41 | lua_rawgetp(L, -1, CppSignature::value()); 42 | lua_rawget(L, LUA_REGISTRYINDEX); 43 | 44 | // check if both are equal 45 | if (!lua_rawequal(L, -1, -2)) { 46 | // not match, panic now -> 47 | lua_pushliteral(L, "___type"); 48 | lua_rawget(L, -3); 49 | return luaL_error(L, "invalid meta table found when try to get property '%s.%s'", 50 | luaL_optstring(L, -1, ""), lua_tostring(L, 2)); 51 | } else { 52 | // matched, pop -> 53 | lua_pop(L, 1); 54 | } 55 | 56 | for (;;) { 57 | // push metatable[key] -> 58 | lua_pushvalue(L, 2); 59 | lua_rawget(L, -2); 60 | 61 | if (!lua_isnil(L, -1)) { 62 | // value is found 63 | break; 64 | } 65 | 66 | 67 | // get metatable.getters -> 68 | lua_pop(L, 1); // pop nil 69 | 70 | if (lua_isnumber(L, 2)) { 71 | lua_pushliteral(L, "___get_indexed"); 72 | lua_rawget(L, -2); 73 | 74 | if (!lua_isnil(L, -1)) { 75 | assert(lua_iscfunction(L, -1)); 76 | lua_pushvalue(L, 1); 77 | lua_pushvalue(L, 2); 78 | lua_call(L, 2, 1); 79 | break; 80 | } else { 81 | lua_pop(L, 1); 82 | } 83 | } 84 | 85 | lua_pushliteral(L, "___getters"); 86 | lua_rawget(L, -2); 87 | assert(lua_istable(L, -1)); 88 | 89 | // get metatable.getters[key] -> 90 | lua_pushvalue(L, 2); // push key 91 | lua_rawget(L, -2); // lookup key in getters 92 | 93 | // call the getter if it is function, or leave it as value 94 | if (!lua_isnil(L, -1)) { 95 | if (lua_iscfunction(L, -1)) { 96 | if (lua_isuserdata(L, 1)) { 97 | // if it is userdata, that means instance 98 | lua_pushvalue(L, 1); // push userdata as object param for member function 99 | lua_call(L, 1, 1); 100 | } else { 101 | // otherwise, it is static (class getters) 102 | assert(lua_istable(L, 1)); 103 | lua_call(L, 0, 1); 104 | } 105 | } 106 | break; 107 | } 108 | 109 | // now try super metatable -> 110 | lua_pop(L, 2); // pop 111 | lua_pushliteral(L, "___super"); 112 | lua_rawget(L, -2); 113 | 114 | if (lua_isnil(L, -1)) { 115 | 116 | #if LUAINTF_EXTRA_LUA_FIELDS 117 | if (lua_isuserdata(L, 1)) { 118 | lua_getuservalue(L, 1); 119 | if (!lua_isnil(L, -1)) { 120 | // get extra_fields[key] -> 121 | lua_pushvalue(L, 2); // push key 122 | lua_rawget(L, -2); // lookup key in extra fields 123 | } 124 | } 125 | #endif 126 | 127 | // leave value on top -> or 128 | break; 129 | } 130 | 131 | // yes, now continue with 132 | assert(lua_istable(L, -1)); 133 | lua_remove(L, -2); // pop 134 | } 135 | 136 | return 1; 137 | } 138 | 139 | LUA_INLINE int CppBindClassMetaMethod::newIndex(lua_State* L) 140 | { 141 | // -> table or userdata 142 | // -> key 143 | // -> value 144 | 145 | // get signature metatable -> 146 | lua_getmetatable(L, 1); 147 | lua_rawgetp(L, -1, CppSignature::value()); 148 | lua_rawget(L, LUA_REGISTRYINDEX); 149 | 150 | // check if both are equal 151 | if (!lua_rawequal(L, -1, -2)) { 152 | // not match, panic now -> 153 | lua_pushliteral(L, "___type"); 154 | lua_rawget(L, -3); 155 | return luaL_error(L, "invalid meta table found when try to set property '%s.%s'", 156 | luaL_optstring(L, -1, ""), lua_tostring(L, 2)); 157 | } else { 158 | // matched, pop -> 159 | lua_pop(L, 1); 160 | } 161 | 162 | for (;;) { 163 | if (lua_isnumber(L, 2)) { 164 | lua_pushliteral(L, "___set_indexed"); 165 | lua_rawget(L, -2); 166 | 167 | if (!lua_isnil(L, -1)) { 168 | assert(lua_iscfunction(L, -1)); 169 | lua_pushvalue(L, 1); 170 | lua_pushvalue(L, 2); 171 | lua_pushvalue(L, 3); 172 | lua_call(L, 3, 0); 173 | break; 174 | } else { 175 | lua_pop(L, 1); 176 | } 177 | } 178 | 179 | // get setters subtable of metatable -> 180 | lua_pushliteral(L, "___setters"); 181 | lua_rawget(L, -2); // get __setters table 182 | assert(lua_istable(L, -1)); 183 | 184 | // get setters[key] -> 185 | lua_pushvalue(L, 2); // push key arg2 186 | lua_rawget(L, -2); // lookup key in setters 187 | 188 | if (lua_iscfunction(L, -1)) { 189 | // setter function found, now need to test whether it is object (== userdata) 190 | int n = 1; 191 | if (lua_isuserdata(L, 1)) { 192 | lua_pushvalue(L, 1); // push userdata as object param for member function 193 | n++; 194 | } else { 195 | assert(lua_istable(L, 1)); 196 | } 197 | 198 | lua_pushvalue(L, 3); // push new value as arg 199 | lua_call(L, n, 0); 200 | break; 201 | } 202 | 203 | // now try super metatable -> 204 | assert(lua_isnil(L, -1)); 205 | lua_pop(L, 2); // pop 206 | lua_pushliteral(L, "___super"); 207 | lua_rawget(L, -2); 208 | 209 | // check if there is one 210 | if (lua_isnil(L, -1)) { 211 | 212 | #if LUAINTF_EXTRA_LUA_FIELDS 213 | if (lua_isuserdata(L, 1)) { 214 | // set instance fields 215 | lua_pushliteral(L, "___const"); 216 | lua_rawget(L, -3); 217 | if (!lua_rawequal(L, -1, -3)) { 218 | // set field only if not const 219 | lua_getuservalue(L, 1); 220 | if (lua_isnil(L, -1)) { 221 | lua_newtable(L); 222 | lua_pushvalue(L, 2); 223 | lua_pushvalue(L, 3); 224 | lua_rawset(L, -3); 225 | lua_setuservalue(L, 1); 226 | } else { 227 | lua_pushvalue(L, 2); 228 | lua_pushvalue(L, 3); 229 | lua_rawset(L, -3); 230 | } 231 | break; 232 | } 233 | lua_pop(L, 1); 234 | } else { 235 | // set class fields 236 | lua_pushvalue(L, 2); 237 | lua_pushvalue(L, 3); 238 | lua_rawset(L, 1); 239 | break; 240 | } 241 | #endif 242 | 243 | // give up 244 | lua_pushliteral(L, "___type"); 245 | lua_rawget(L, -3); 246 | return luaL_error(L, "property '%s.%s' is not found or not writable", 247 | luaL_optstring(L, -1, ""), lua_tostring(L, 2)); 248 | } 249 | 250 | // yes, now continue with 251 | assert(lua_istable(L, -1)); 252 | lua_remove(L, -2); // pop 253 | } 254 | 255 | return 0; 256 | } 257 | 258 | LUA_INLINE int CppBindClassMetaMethod::errorReadOnly(lua_State* L) 259 | { 260 | return luaL_error(L, "property '%s' is read-only", 261 | lua_tostring(L, lua_upvalueindex(1))); 262 | } 263 | 264 | LUA_INLINE int CppBindClassMetaMethod::errorConstMismatch(lua_State* L) 265 | { 266 | return luaL_error(L, "member function '%s' can not be access by const object", 267 | lua_tostring(L, lua_upvalueindex(1))); 268 | } 269 | 270 | //--------------------------------------------------------------------------- 271 | 272 | LUA_INLINE bool CppBindClassBase::buildMetaTable(LuaRef& meta, LuaRef& parent, const char* name, 273 | void* static_id, void* clazz_id, void* const_id) 274 | { 275 | LuaRef ref = parent.rawget(name); 276 | if (ref != nullptr) { 277 | meta = ref; 278 | return false; 279 | } 280 | 281 | auto L = parent.state(); 282 | std::string type_name = "class<" + CppBindModuleBase::getFullName(parent, name) + ">"; 283 | 284 | LuaRef type_const = LuaRef::fromPtr(L, const_id); 285 | LuaRef type_clazz = LuaRef::fromPtr(L, clazz_id); 286 | LuaRef type_static = LuaRef::fromPtr(L, static_id); 287 | 288 | LuaRef clazz_const = LuaRef::createTable(L); 289 | clazz_const.setMetaTable(clazz_const); 290 | clazz_const.rawset("__index", &CppBindClassMetaMethod::index); 291 | clazz_const.rawset("__newindex", &CppBindClassMetaMethod::newIndex); 292 | clazz_const.rawset("___getters", LuaRef::createTable(L)); 293 | clazz_const.rawset("___setters", LuaRef::createTable(L)); 294 | clazz_const.rawset("___type", "const_" + type_name); 295 | clazz_const.rawset("___const", clazz_const); 296 | clazz_const.rawsetp(CppSignature::value(), type_const); 297 | 298 | LuaRef clazz = LuaRef::createTable(L); 299 | clazz.setMetaTable(clazz); 300 | clazz.rawset("__index", &CppBindClassMetaMethod::index); 301 | clazz.rawset("__newindex", &CppBindClassMetaMethod::newIndex); 302 | clazz.rawset("___getters", LuaRef::createTable(L)); 303 | clazz.rawset("___setters", LuaRef::createTable(L)); 304 | clazz.rawset("___type", type_name); 305 | clazz.rawset("___const", clazz_const); 306 | clazz.rawsetp(CppSignature::value(), type_clazz); 307 | 308 | LuaRef clazz_static = LuaRef::createTable(L); 309 | clazz_static.setMetaTable(clazz_static); 310 | clazz_static.rawset("__index", &CppBindClassMetaMethod::index); 311 | clazz_static.rawset("__newindex", &CppBindClassMetaMethod::newIndex); 312 | clazz_static.rawset("___getters", LuaRef::createTable(L)); 313 | clazz_static.rawset("___setters", LuaRef::createTable(L)); 314 | clazz_static.rawset("___type", "static_" + type_name); 315 | clazz_static.rawset("___class", clazz); 316 | clazz_static.rawset("___const", clazz_const); 317 | clazz_static.rawset("___parent", parent); 318 | clazz_static.rawsetp(CppSignature::value(), type_static); 319 | 320 | clazz_const.rawset("class", clazz_static); 321 | clazz.rawset("class", clazz_static); 322 | 323 | LuaRef registry(L, LUA_REGISTRYINDEX); 324 | registry.rawset(type_clazz, clazz); 325 | registry.rawset(type_const, clazz_const); 326 | registry.rawset(type_static, clazz_static); 327 | parent.rawset(name, clazz_static); 328 | 329 | meta = clazz_static; 330 | return true; 331 | } 332 | 333 | LUA_INLINE bool CppBindClassBase::buildMetaTable(LuaRef& meta, LuaRef& parent, const char* name, 334 | void* static_id, void* clazz_id, void* const_id, void* super_static_id) 335 | { 336 | if (buildMetaTable(meta, parent, name, static_id, clazz_id, const_id)) { 337 | LuaRef registry(parent.state(), LUA_REGISTRYINDEX); 338 | LuaRef super = registry.rawgetp(super_static_id); 339 | meta.rawset("___super", super); 340 | meta.rawget("___class").rawset("___super", super.rawget("___class")); 341 | meta.rawget("___const").rawset("___super", super.rawget("___const")); 342 | return true; 343 | } 344 | return false; 345 | } 346 | 347 | LUA_INLINE void CppBindClassBase::setStaticGetter(const char* name, const LuaRef& getter) 348 | { 349 | m_meta.rawget("___getters").rawset(name, getter); 350 | } 351 | 352 | LUA_INLINE void CppBindClassBase::setStaticSetter(const char* name, const LuaRef& setter) 353 | { 354 | m_meta.rawget("___setters").rawset(name, setter); 355 | } 356 | 357 | LUA_INLINE void CppBindClassBase::setStaticReadOnly(const char* name) 358 | { 359 | std::string full_name = CppBindModuleBase::getMemberName(m_meta, name); 360 | setStaticSetter(name, LuaRef::createFunctionWith(state(), &CppBindClassMetaMethod::errorReadOnly, full_name)); 361 | } 362 | 363 | LUA_INLINE void CppBindClassBase::setMemberGetter(const char* name, const LuaRef& getter, const LuaRef& getter_const) 364 | { 365 | m_meta.rawget("___class").rawget("___getters").rawset(name, getter); 366 | m_meta.rawget("___const").rawget("___getters").rawset(name, getter_const); 367 | } 368 | 369 | LUA_INLINE void CppBindClassBase::setMemberGetter(const char* name, const LuaRef& getter) 370 | { 371 | setMemberGetter(name, getter, getter); 372 | } 373 | 374 | LUA_INLINE void CppBindClassBase::setMemberSetter(const char* name, const LuaRef& setter) 375 | { 376 | LuaRef meta_class = m_meta.rawget("___class"); 377 | LuaRef meta_const = m_meta.rawget("___const"); 378 | std::string full_name = CppBindModuleBase::getMemberName(meta_class, name); 379 | LuaRef err = LuaRef::createFunctionWith(state(), &CppBindClassMetaMethod::errorConstMismatch, full_name); 380 | meta_class.rawget("___setters").rawset(name, setter); 381 | meta_const.rawget("___setters").rawset(name, err); 382 | } 383 | 384 | LUA_INLINE void CppBindClassBase::setMemberReadOnly(const char* name) 385 | { 386 | LuaRef meta_class = m_meta.rawget("___class"); 387 | LuaRef meta_const = m_meta.rawget("___const"); 388 | std::string full_name = CppBindModuleBase::getMemberName(meta_class, name); 389 | LuaRef err = LuaRef::createFunctionWith(state(), &CppBindClassMetaMethod::errorReadOnly, full_name); 390 | meta_class.rawget("___setters").rawset(name, err); 391 | meta_const.rawget("___setters").rawset(name, err); 392 | } 393 | 394 | LUA_INLINE void CppBindClassBase::setMemberFunction(const char* name, const LuaRef& proc, bool is_const) 395 | { 396 | LuaRef meta_class = m_meta.rawget("___class"); 397 | LuaRef meta_const = m_meta.rawget("___const"); 398 | meta_class.rawset(name, proc); 399 | if (is_const) { 400 | meta_const.rawset(name, proc); 401 | } else { 402 | std::string full_name = CppBindModuleBase::getMemberName(meta_class, name); 403 | LuaRef err = LuaRef::createFunctionWith(state(), &CppBindClassMetaMethod::errorConstMismatch, full_name); 404 | meta_const.rawset(name, err); 405 | } 406 | } 407 | -------------------------------------------------------------------------------- /LuaIntf/src/CppBindModule.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // https://github.com/SteveKChiu/lua-intf 3 | // 4 | // Copyright 2014, Steve K. Chiu 5 | // 6 | // The MIT License (http://www.opensource.org/licenses/mit-license.php) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a 9 | // copy of this software and associated documentation files (the "Software"), 10 | // to deal in the Software without restriction, including without limitation 11 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the 13 | // Software is furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | // DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | #ifndef LUAINTF_H 28 | #include "LuaIntf/LuaIntf.h" 29 | using namespace LuaIntf; 30 | #endif 31 | 32 | //--------------------------------------------------------------------------- 33 | 34 | LUA_INLINE int CppBindModuleMetaMethod::index(lua_State* L) 35 | { 36 | // -> table 37 | // -> key 38 | 39 | // push metatable of table -> 40 | lua_getmetatable(L, 1); 41 | 42 | // push metatable[key] -> 43 | lua_pushvalue(L, 2); 44 | lua_rawget(L, -2); 45 | 46 | if (lua_isnil(L, -1)) { 47 | // get metatable.getters -> 48 | lua_pop(L, 1); // pop nil 49 | lua_pushliteral(L, "___getters"); 50 | lua_rawget(L, -2); // get getters table 51 | assert(lua_istable(L, -1)); 52 | 53 | // get metatable.getters[key] -> 54 | lua_pushvalue(L, 2); // push key 55 | lua_rawget(L, -2); // lookup key in getters 56 | 57 | if (lua_iscfunction(L, -1)) { 58 | // getter function found 59 | lua_call(L, 0, 1); 60 | } 61 | } 62 | 63 | return 1; 64 | } 65 | 66 | LUA_INLINE int CppBindModuleMetaMethod::newIndex(lua_State* L) 67 | { 68 | // -> table 69 | // -> key 70 | // -> value 71 | 72 | // push metatable of table -> 73 | lua_getmetatable(L, 1); 74 | 75 | // get setters subtable of metatable -> 76 | lua_pushliteral(L, "___setters"); 77 | lua_rawget(L, -2); // get __setters table 78 | assert(lua_istable(L, -1)); 79 | 80 | // get setters[key] -> 81 | lua_pushvalue(L, 2); // push key arg2 82 | lua_rawget(L, -2); // lookup key in setters 83 | 84 | if (lua_iscfunction(L, -1)) { 85 | // setter function found 86 | lua_pushvalue(L, 3); // push new value as arg 87 | lua_call(L, 1, 0); 88 | } else { 89 | // no setter found, just set the table field 90 | assert(lua_isnil(L, -1)); 91 | lua_pop(L, 3); 92 | lua_rawset(L, 1); 93 | } 94 | return 0; 95 | } 96 | 97 | LUA_INLINE int CppBindModuleMetaMethod::forwardCall(lua_State* L) 98 | { 99 | // -> table (table's metatable is set to itself) 100 | // ~ -> args 101 | int top = lua_gettop(L); 102 | 103 | lua_pushvalue(L, lua_upvalueindex(1)); 104 | lua_rawget(L, 1); // get sub module metatable -> 105 | 106 | lua_pushliteral(L, "__call"); 107 | lua_rawget(L, -2); // get call function -> 108 | 109 | lua_insert(L, 1); // move to top -> now is at index 2 110 | lua_replace(L, 2); // replace original with 111 | lua_call(L, top, 1); 112 | return 1; 113 | } 114 | 115 | LUA_INLINE int CppBindModuleMetaMethod::errorReadOnly(lua_State* L) 116 | { 117 | return luaL_error(L, "property '%s' is read-only", lua_tostring(L, lua_upvalueindex(1))); 118 | } 119 | 120 | //--------------------------------------------------------------------------- 121 | 122 | LUA_INLINE CppBindModuleBase::CppBindModuleBase(LuaRef& meta, const char* name) 123 | { 124 | LuaRef ref = meta.rawget(name); 125 | if (ref != nullptr) { 126 | m_meta = ref; 127 | return; 128 | } 129 | 130 | lua_State* L = meta.state(); 131 | std::string type_name = "module<" + getFullName(meta, name) + ">"; 132 | LuaRef module = LuaRef::createTable(L); 133 | module.setMetaTable(module); 134 | 135 | module.rawset("__index", &CppBindModuleMetaMethod::index); 136 | module.rawset("__newindex", &CppBindModuleMetaMethod::newIndex); 137 | module.rawset("___getters", LuaRef::createTable(L)); 138 | module.rawset("___setters", LuaRef::createTable(L)); 139 | module.rawset("___type", type_name); 140 | module.rawset("___parent", meta); 141 | meta.rawset(name, module); 142 | m_meta = module; 143 | } 144 | 145 | LUA_INLINE std::string CppBindModuleBase::getFullName(const LuaRef& parent, const char* name) 146 | { 147 | std::string full_name = parent.get("___type", ""); 148 | if (!full_name.empty()) { 149 | size_t pos = full_name.find('<'); 150 | if (pos != std::string::npos) full_name.erase(0, pos + 1); 151 | pos = full_name.rfind('>'); 152 | if (pos != std::string::npos) full_name.erase(pos); 153 | full_name += '.'; 154 | } 155 | full_name += name; 156 | return full_name; 157 | } 158 | 159 | LUA_INLINE std::string CppBindModuleBase::getMemberName(const LuaRef& parent, const char* name) 160 | { 161 | std::string full_name = parent.rawget("___type", ""); 162 | full_name += '.'; 163 | full_name += name; 164 | return full_name; 165 | } 166 | 167 | LUA_INLINE void CppBindModuleBase::setGetter(const char* name, const LuaRef& getter) 168 | { 169 | m_meta.rawget("___getters").rawset(name, getter); 170 | } 171 | 172 | LUA_INLINE void CppBindModuleBase::setSetter(const char* name, const LuaRef& setter) 173 | { 174 | m_meta.rawget("___setters").rawset(name, setter); 175 | } 176 | 177 | LUA_INLINE void CppBindModuleBase::setReadOnly(const char* name) 178 | { 179 | std::string full_name = getMemberName(m_meta, name); 180 | setSetter(name, LuaRef::createFunctionWith(state(), &CppBindModuleMetaMethod::errorReadOnly, full_name)); 181 | } 182 | -------------------------------------------------------------------------------- /LuaIntf/src/CppFunction.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // https://github.com/SteveKChiu/lua-intf 3 | // 4 | // Copyright 2014, Steve K. Chiu 5 | // 6 | // The MIT License (http://www.opensource.org/licenses/mit-license.php) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a 9 | // copy of this software and associated documentation files (the "Software"), 10 | // to deal in the Software without restriction, including without limitation 11 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the 13 | // Software is furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | // DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | #ifndef LUAINTF_H 28 | #include "LuaIntf/LuaIntf.h" 29 | using namespace LuaIntf; 30 | #endif 31 | 32 | //--------------------------------------------------------------------------- 33 | 34 | LUA_INLINE int CppFunctor::call(lua_State* L) 35 | { 36 | try { 37 | CppFunctor* f = static_cast(lua_touserdata(L, 1)); 38 | return f->run(L); 39 | } catch (std::exception& e) { 40 | return luaL_error(L, "%s", e.what()); 41 | } 42 | } 43 | 44 | LUA_INLINE int CppFunctor::gc(lua_State* L) 45 | { 46 | try { 47 | CppFunctor* f = static_cast(lua_touserdata(L, 1)); 48 | f->~CppFunctor(); 49 | return 0; 50 | } catch (std::exception& e) { 51 | return luaL_error(L, "%s", e.what()); 52 | } 53 | } 54 | 55 | LUA_INLINE int CppFunctor::callp(lua_State* L) 56 | { 57 | try { 58 | CppFunctor* f = *static_cast(lua_touserdata(L, 1)); 59 | return f->run(L); 60 | } catch (std::exception& e) { 61 | return luaL_error(L, "%s", e.what()); 62 | } 63 | } 64 | 65 | LUA_INLINE int CppFunctor::gcp(lua_State* L) 66 | { 67 | try { 68 | CppFunctor* f = *static_cast(lua_touserdata(L, 1)); 69 | delete f; 70 | return 0; 71 | } catch (std::exception& e) { 72 | return luaL_error(L, "%s", e.what()); 73 | } 74 | } 75 | 76 | LUA_INLINE int CppFunctor::bind(lua_State* L, lua_CFunction call, lua_CFunction gc) 77 | { 78 | lua_newtable(L); 79 | lua_pushcfunction(L, call); 80 | lua_setfield(L, -2, "__call"); 81 | lua_pushcfunction(L, gc); 82 | lua_setfield(L, -2, "__gc"); 83 | lua_setmetatable(L, -2); 84 | return 1; 85 | } 86 | 87 | LUA_INLINE int CppFunctor::pushToStack(lua_State* L, CppFunctor* f) 88 | { 89 | // need to create userdata, lightuserdata can't be gc 90 | CppFunctor** p = static_cast(lua_newuserdata(L, sizeof(CppFunctor*))); 91 | *p = f; 92 | return bind(L, &callp, &gcp); 93 | } 94 | -------------------------------------------------------------------------------- /LuaIntf/src/CppObject.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // https://github.com/SteveKChiu/lua-intf 3 | // 4 | // Copyright 2014, Steve K. Chiu 5 | // 6 | // The MIT License (http://www.opensource.org/licenses/mit-license.php) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a 9 | // copy of this software and associated documentation files (the "Software"), 10 | // to deal in the Software without restriction, including without limitation 11 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the 13 | // Software is furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | // DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | #ifndef LUAINTF_H 28 | #include "LuaIntf/LuaIntf.h" 29 | using namespace LuaIntf; 30 | #endif 31 | 32 | //--------------------------------------------------------------------------- 33 | 34 | LUA_INLINE void CppObject::typeMismatchError(lua_State* L, int index) 35 | { 36 | // = 37 | // = 38 | // = 39 | 40 | // now get the expected type -> 41 | lua_pushliteral(L, "___type"); 42 | lua_rawget(L, -3); 43 | const char* expected = lua_tostring(L, -1); 44 | 45 | // now get the actual got type -> 46 | lua_pushliteral(L, "___type"); 47 | lua_rawget(L, -3); 48 | const char* actual = lua_tostring(L, -1); 49 | if (actual == nullptr) { 50 | actual = lua_typename(L, lua_type(L, index)); 51 | } 52 | 53 | // now create error msg, put it into bottom and pop all others -> 54 | luaL_where(L, 1); 55 | lua_pushfstring(L, "%s expected, got %s", expected, actual); 56 | lua_concat(L, 2); 57 | lua_error(L); 58 | } 59 | 60 | LUA_INLINE CppObject* CppObject::getObject(lua_State* L, int index, void* class_id, 61 | bool is_const, bool is_exact, bool raise_error) 62 | { 63 | if (!lua_isuserdata(L, index)) { 64 | if (raise_error) { 65 | luaL_error(L, "expect userdata, got %s", lua_typename(L, lua_type(L, index))); 66 | } 67 | return nullptr; 68 | } 69 | 70 | // = 71 | index = lua_absindex(L, index); 72 | 73 | // get registry base class metatable -> 74 | lua_rawgetp(L, LUA_REGISTRYINDEX, class_id); 75 | 76 | // report error if no metatable 77 | if (!lua_istable(L, -1)) { 78 | if (raise_error) { 79 | luaL_error(L, "unknown class, you need to register this class with lua-intf first by using LuaBinding"); 80 | } else { 81 | lua_pop(L, 1); 82 | } 83 | return nullptr; 84 | } 85 | 86 | // get the object metatable -> 87 | lua_getmetatable(L, index); 88 | 89 | // use const metatable if needed 90 | if (is_const && !is_exact) { 91 | // get the const metatable -> 92 | lua_pushliteral(L, "___const"); 93 | lua_rawget(L, -2); 94 | lua_remove(L, -2); 95 | 96 | // report error if no const metatable 97 | if (!lua_istable(L, -1)) { 98 | if (raise_error) { 99 | luaL_error(L, "unknown class, you need to register this class with lua-intf first by using LuaBinding"); 100 | } else { 101 | lua_pop(L, 2); 102 | } 103 | return nullptr; 104 | } 105 | } 106 | 107 | for (;;) { 108 | // check if and are equal 109 | if (lua_rawequal(L, -1, -2)) { 110 | // matched, return this object 111 | lua_pop(L, 2); 112 | break; 113 | } 114 | 115 | // give up if exact match is needed 116 | if (is_exact) { 117 | if (raise_error) { 118 | typeMismatchError(L, index); 119 | } else { 120 | lua_pop(L, 2); 121 | } 122 | return nullptr; 123 | } 124 | 125 | // now try super class -> 126 | lua_pushliteral(L, "___super"); 127 | lua_rawget(L, -2); 128 | 129 | if (lua_isnil(L, -1)) { 130 | // no super class 131 | if (raise_error) { 132 | lua_pop(L, 1); // pop nil 133 | typeMismatchError(L, index); 134 | } else { 135 | lua_pop(L, 3); 136 | } 137 | return nullptr; 138 | } else { 139 | // continue with -> 140 | lua_remove(L, -2); 141 | } 142 | } 143 | 144 | return static_cast(lua_touserdata(L, index)); 145 | } 146 | 147 | -------------------------------------------------------------------------------- /LuaIntf/src/LuaCompat.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // https://github.com/SteveKChiu/lua-intf 3 | // 4 | // Copyright 2014, Steve K. Chiu 5 | // 6 | // The MIT License (http://www.opensource.org/licenses/mit-license.php) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a 9 | // copy of this software and associated documentation files (the "Software"), 10 | // to deal in the Software without restriction, including without limitation 11 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the 13 | // Software is furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | // DEALINGS IN THE SOFTWARE. 25 | // 26 | //--------------------------------------------------------------------------- 27 | // 28 | // Part of this file is derived from hishamhm's lua-compat-5.2 29 | // https://github.com/hishamhm/lua-compat-5.2 30 | // 31 | 32 | #ifndef LUACOMPAT_H 33 | #include "LuaIntf/LuaCompat.h" 34 | #endif 35 | 36 | #if LUA_VERSION_NUM == 501 37 | 38 | #include 39 | #include 40 | #include 41 | 42 | #define LUA_PACKAGE_KEY "_LUAINTF_COMPAT" 43 | 44 | #ifndef lua_number2unsigned 45 | #if defined(LUA_NUMBER_DOUBLE) || defined(LUA_NUMBER_FLOAT) 46 | #include 47 | 48 | #define LUA_SUPUNSIGNED \ 49 | ((lua_Number)(~(lua_Unsigned)0) + 1) 50 | 51 | #define lua_number2unsigned(i, n) \ 52 | ((i) = (lua_Unsigned)((n) - floor((n) / LUA_SUPUNSIGNED) * LUA_SUPUNSIGNED)) 53 | #else 54 | #define lua_number2unsigned(i,n) \ 55 | ((i) = (lua_Unsigned)(n)) 56 | #endif 57 | #endif 58 | 59 | #ifndef lua_unsigned2number 60 | #define lua_unsigned2number(u) \ 61 | (((u) <= (lua_Unsigned)INT_MAX) ? (lua_Number)(int)(u) : (lua_Number)(u)) 62 | #endif 63 | 64 | //--------------------------------------------------------------------------- 65 | 66 | LUA_INLINE const lua_Number* lua_version(lua_State*) 67 | { 68 | static const lua_Number version = LUA_VERSION_NUM; 69 | return &version; 70 | } 71 | 72 | LUA_INLINE int lua_absindex(lua_State* L, int i) 73 | { 74 | if (i < 0 && i > LUA_REGISTRYINDEX) { 75 | i += lua_gettop(L) + 1; 76 | } 77 | return i; 78 | } 79 | 80 | LUA_INLINE void lua_copy(lua_State* L, int from, int to) 81 | { 82 | int abs_to = lua_absindex(L, to); 83 | luaL_checkstack(L, 1, "not enough stack slots"); 84 | lua_pushvalue(L, from); 85 | lua_replace(L, abs_to); 86 | } 87 | 88 | LUA_INLINE void lua_rawgetp(lua_State* L, int i, const void* p) 89 | { 90 | int abs_i = lua_absindex(L, i); 91 | lua_pushlightuserdata(L, (void*)p); 92 | lua_rawget(L, abs_i); 93 | } 94 | 95 | LUA_INLINE void lua_rawsetp(lua_State* L, int i, const void* p) 96 | { 97 | int abs_i = lua_absindex(L, i); 98 | luaL_checkstack(L, 1, "not enough stack slots"); 99 | lua_pushlightuserdata(L, (void*)p); 100 | lua_insert(L, -2); 101 | lua_rawset(L, abs_i); 102 | } 103 | 104 | static LUA_INLINE void _lua_pushpackagetable(lua_State* L) 105 | { 106 | lua_pushliteral(L, LUA_PACKAGE_KEY); 107 | lua_rawget(L, LUA_REGISTRYINDEX); 108 | if (!lua_istable(L, -1)) { 109 | lua_pop(L, 1); 110 | /* try to get package table from globals */ 111 | lua_pushliteral(L, "package"); 112 | lua_rawget(L, LUA_GLOBALSINDEX); 113 | if (lua_istable(L, -1)) { 114 | lua_pushliteral(L, LUA_PACKAGE_KEY); 115 | lua_pushvalue(L, -2); 116 | lua_rawset(L, LUA_REGISTRYINDEX); 117 | } 118 | } 119 | } 120 | 121 | LUA_INLINE void lua_getuservalue(lua_State* L, int i) 122 | { 123 | luaL_checktype(L, i, LUA_TUSERDATA); 124 | luaL_checkstack(L, 2, "not enough stack slots"); 125 | lua_getfenv(L, i); 126 | lua_pushvalue(L, LUA_GLOBALSINDEX); 127 | if (lua_rawequal(L, -1, -2)) { 128 | lua_pop(L, 1); 129 | lua_pushnil(L); 130 | lua_replace(L, -2); 131 | } else { 132 | lua_pop(L, 1); 133 | _lua_pushpackagetable(L); 134 | if (lua_rawequal(L, -1, -2)) { 135 | lua_pop(L, 1); 136 | lua_pushnil(L); 137 | lua_replace(L, -2); 138 | } else { 139 | lua_pop(L, 1); 140 | } 141 | } 142 | } 143 | 144 | LUA_INLINE void lua_setuservalue(lua_State* L, int i) 145 | { 146 | luaL_checktype(L, i, LUA_TUSERDATA); 147 | if (lua_isnil(L, -1)) { 148 | luaL_checkstack(L, 1, "not enough stack slots"); 149 | lua_pushvalue(L, LUA_GLOBALSINDEX); 150 | lua_replace(L, -2); 151 | } 152 | lua_setfenv(L, i); 153 | } 154 | 155 | 156 | LUA_INLINE void lua_pushunsigned(lua_State* L, lua_Unsigned n) 157 | { 158 | lua_pushnumber(L, lua_unsigned2number(n)); 159 | } 160 | 161 | LUA_INLINE lua_Unsigned lua_tounsignedx(lua_State* L, int i, int* is_num) 162 | { 163 | lua_Unsigned result; 164 | lua_Number n = lua_tonumberx(L, i, is_num); 165 | lua_number2unsigned(result, n); 166 | return result; 167 | } 168 | 169 | LUA_INLINE lua_Number lua_tonumberx(lua_State* L, int i, int* is_num) 170 | { 171 | lua_Number n = lua_tonumber(L, i); 172 | if (is_num != NULL) { 173 | *is_num = (n != 0 || lua_isnumber(L, i)); 174 | } 175 | return n; 176 | } 177 | 178 | LUA_INLINE lua_Integer lua_tointegerx(lua_State* L, int i, int* is_num) 179 | { 180 | lua_Integer n = lua_tointeger(L, i); 181 | if (is_num) { 182 | *is_num = (n != 0 || lua_isnumber(L, i)); 183 | } 184 | return n; 185 | } 186 | 187 | LUA_INLINE void lua_len(lua_State* L, int i) 188 | { 189 | switch (lua_type(L, i)) { 190 | case LUA_TSTRING: 191 | case LUA_TTABLE: 192 | lua_pushnumber(L, (int)lua_objlen(L, i)); 193 | break; 194 | case LUA_TUSERDATA: 195 | if (luaL_callmeta(L, i, "__len")) { 196 | break; 197 | } 198 | // maybe fall through 199 | default: 200 | luaL_error(L, "attempt to get length of a %s value", lua_typename(L, lua_type(L, i))); 201 | break; 202 | } 203 | } 204 | 205 | LUA_INLINE int lua_compare(lua_State* L, int index1, int index2, int op) 206 | { 207 | if (op == LUA_OPEQ) { 208 | return lua_equal(L, index1, index2); 209 | } else if (op == LUA_OPLT) { 210 | return lua_lessthan(L, index1, index2); 211 | } else if (op == LUA_OPLE) { 212 | return lua_lessthan(L, index1, index2) || lua_equal(L, index1, index2); 213 | } else { 214 | return 0; 215 | } 216 | } 217 | 218 | //--------------------------------------------------------------------------- 219 | 220 | LUA_INLINE void luaL_checkversion(lua_State*) 221 | { 222 | // do nothing 223 | } 224 | 225 | LUA_INLINE lua_Unsigned luaL_checkunsigned(lua_State* L, int i) 226 | { 227 | lua_Unsigned result; 228 | lua_Number n = lua_tonumber(L, i); 229 | if (n == 0 && !lua_isnumber(L, i)) { 230 | luaL_checktype(L, i, LUA_TNUMBER); 231 | } 232 | lua_number2unsigned(result, n); 233 | return result; 234 | } 235 | 236 | LUA_INLINE lua_Unsigned luaL_optunsigned(lua_State* L, int i, lua_Unsigned def) 237 | { 238 | return luaL_opt(L, luaL_checkunsigned, i, def); 239 | } 240 | 241 | LUA_INLINE const char* luaL_tolstring(lua_State* L, int idx, size_t* len) 242 | { 243 | if (!luaL_callmeta(L, idx, "__tostring")) { 244 | int t = lua_type(L, idx); 245 | switch (t) { 246 | case LUA_TNIL: 247 | lua_pushliteral(L, "nil"); 248 | break; 249 | case LUA_TSTRING: 250 | case LUA_TNUMBER: 251 | lua_pushvalue(L, idx); 252 | break; 253 | case LUA_TBOOLEAN: 254 | if (lua_toboolean(L, idx)) { 255 | lua_pushliteral(L, "true"); 256 | } else { 257 | lua_pushliteral(L, "false"); 258 | } 259 | break; 260 | default: 261 | lua_pushfstring(L, "%s: %p", lua_typename(L, t), lua_topointer(L, idx)); 262 | break; 263 | } 264 | } 265 | return lua_tolstring(L, -1, len); 266 | } 267 | 268 | LUA_INLINE int luaL_len(lua_State* L, int i) 269 | { 270 | luaL_checkstack(L, 1, "not enough stack slots"); 271 | lua_len(L, i); 272 | int is_num = 0; 273 | int res = int(lua_tointegerx(L, -1, &is_num)); 274 | lua_pop(L, 1); 275 | if (!is_num) { 276 | luaL_error(L, "object length is not a number"); 277 | } 278 | return res; 279 | } 280 | 281 | LUA_INLINE void* luaL_testudata(lua_State* L, int i, const char* tname) 282 | { 283 | void *p = lua_touserdata(L, i); 284 | luaL_checkstack(L, 2, "not enough stack slots"); 285 | if (p == NULL || !lua_getmetatable(L, i)) { 286 | return NULL; 287 | } else { 288 | int res = 0; 289 | luaL_getmetatable(L, tname); 290 | res = lua_rawequal(L, -1, -2); 291 | lua_pop(L, 2); 292 | if (!res) { 293 | p = NULL; 294 | } 295 | } 296 | return p; 297 | } 298 | 299 | LUA_INLINE void luaL_setfuncs(lua_State* L, const luaL_Reg* l, int nup) 300 | { 301 | luaL_checkstack(L, nup + 1, "too many upvalues"); 302 | for (; l->name != NULL; l++) { /* fill the table with given functions */ 303 | int i; 304 | lua_pushstring(L, l->name); 305 | for (i = 0; i < nup; i++) { /* copy upvalues to the top */ 306 | lua_pushvalue(L, -(nup + 1)); 307 | } 308 | lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ 309 | lua_settable(L, -(nup + 3)); /* table must be below the upvalues, the name and the closure */ 310 | } 311 | lua_pop(L, nup); /* remove upvalues */ 312 | } 313 | 314 | LUA_INLINE void luaL_setmetatable(lua_State* L, const char* tname) 315 | { 316 | luaL_checkstack(L, 1, "not enough stack slots"); 317 | luaL_getmetatable(L, tname); 318 | lua_setmetatable(L, -2); 319 | } 320 | 321 | LUA_INLINE int luaL_getsubtable(lua_State* L, int i, const char* name) 322 | { 323 | int abs_i = lua_absindex(L, i); 324 | luaL_checkstack(L, 3, "not enough stack slots"); 325 | lua_pushstring(L, name); 326 | lua_gettable(L, abs_i); 327 | if (lua_istable(L, -1)) { 328 | return 1; 329 | } 330 | lua_pop(L, 1); 331 | lua_newtable(L); 332 | lua_pushstring(L, name); 333 | lua_pushvalue(L, -2); 334 | lua_settable(L, abs_i); 335 | return 0; 336 | } 337 | 338 | static LUA_INLINE int _luaL_countlevels(lua_State* L) 339 | { 340 | lua_Debug ar; 341 | int li = 1, le = 1; 342 | /* find an upper bound */ 343 | while (lua_getstack(L, le, &ar)) { 344 | li = le; 345 | le *= 2; 346 | } 347 | /* do a binary search */ 348 | while (li < le) { 349 | int m = (li + le) / 2; 350 | if (lua_getstack(L, m, &ar)) { 351 | li = m + 1; 352 | } else { 353 | le = m; 354 | } 355 | } 356 | return le - 1; 357 | } 358 | 359 | static LUA_INLINE int _luaL_findfield(lua_State* L, int objidx, int level) 360 | { 361 | if (level == 0 || !lua_istable(L, -1)) { 362 | return 0; /* not found */ 363 | } 364 | lua_pushnil(L); /* start 'next' loop */ 365 | while (lua_next(L, -2)) { /* for each pair in table */ 366 | if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */ 367 | if (lua_rawequal(L, objidx, -1)) { /* found object? */ 368 | lua_pop(L, 1); /* remove value (but keep name) */ 369 | return 1; 370 | } else if (_luaL_findfield(L, objidx, level - 1)) { /* try recursively */ 371 | lua_remove(L, -2); /* remove table (but keep name) */ 372 | lua_pushliteral(L, "."); 373 | lua_insert(L, -2); /* place '.' between the two names */ 374 | lua_concat(L, 3); 375 | return 1; 376 | } 377 | } 378 | lua_pop(L, 1); /* remove value */ 379 | } 380 | return 0; /* not found */ 381 | } 382 | 383 | static LUA_INLINE int _luaL_pushglobalfuncname(lua_State* L, lua_Debug* ar) 384 | { 385 | int top = lua_gettop(L); 386 | lua_getinfo(L, "f", ar); /* push function */ 387 | lua_pushvalue(L, LUA_GLOBALSINDEX); 388 | if (_luaL_findfield(L, top + 1, 2)) { 389 | lua_copy(L, -1, top + 1); /* move name to proper place */ 390 | lua_pop(L, 2); /* remove pushed values */ 391 | return 1; 392 | } else { 393 | lua_settop(L, top); /* remove function and global table */ 394 | return 0; 395 | } 396 | } 397 | 398 | static LUA_INLINE void _luaL_pushfuncname(lua_State* L, lua_Debug* ar) 399 | { 400 | if (*ar->namewhat != '\0') { /* is there a name? */ 401 | lua_pushfstring(L, "function " LUA_QS, ar->name); 402 | } else if (*ar->what == 'm') { /* main? */ 403 | lua_pushliteral(L, "main chunk"); 404 | } else if (*ar->what == 'C') { 405 | if (_luaL_pushglobalfuncname(L, ar)) { 406 | lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1)); 407 | lua_remove(L, -2); /* remove name */ 408 | } else { 409 | lua_pushliteral(L, "?"); 410 | } 411 | } else { 412 | lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); 413 | } 414 | } 415 | 416 | LUA_INLINE void luaL_traceback(lua_State* L, lua_State* L1, const char* msg, int level) 417 | { 418 | const int LEVELS1 = 12; /* size of the first part of the stack */ 419 | const int LEVELS2 = 10; /* size of the second part of the stack */ 420 | 421 | lua_Debug ar; 422 | int top = lua_gettop(L); 423 | int numlevels = _luaL_countlevels(L1); 424 | int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0; 425 | if (msg) lua_pushfstring(L, "%s\n", msg); 426 | lua_pushliteral(L, "stack traceback:"); 427 | while (lua_getstack(L1, level++, &ar)) { 428 | if (level == mark) { /* too many levels? */ 429 | lua_pushliteral(L, "\n\t..."); /* add a '...' */ 430 | level = numlevels - LEVELS2; /* and skip to last ones */ 431 | } else { 432 | lua_getinfo(L1, "Slnt", &ar); 433 | lua_pushfstring(L, "\n\t%s:", ar.short_src); 434 | if (ar.currentline > 0) { 435 | lua_pushfstring(L, "%d:", ar.currentline); 436 | } 437 | lua_pushliteral(L, " in "); 438 | _luaL_pushfuncname(L, &ar); 439 | lua_concat(L, lua_gettop(L) - top); 440 | } 441 | } 442 | lua_concat(L, lua_gettop(L) - top); 443 | } 444 | 445 | LUA_INLINE int luaL_fileresult(lua_State* L, int stat, const char* fname) 446 | { 447 | int err = errno; // calls to Lua API may change this value 448 | if (stat) { 449 | lua_pushboolean(L, 1); 450 | return 1; 451 | } else { 452 | lua_pushnil(L); 453 | if (fname) { 454 | lua_pushfstring(L, "%s: %s", fname, strerror(err)); 455 | } else { 456 | lua_pushstring(L, strerror(err)); 457 | } 458 | lua_pushnumber(L, (lua_Number)err); 459 | return 3; 460 | } 461 | } 462 | 463 | //--------------------------------------------------------------------------- 464 | 465 | #endif 466 | -------------------------------------------------------------------------------- /LuaIntf/src/LuaRef.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // https://github.com/SteveKChiu/lua-intf 3 | // 4 | // Copyright 2014, Steve K. Chiu 5 | // 6 | // The MIT License (http://www.opensource.org/licenses/mit-license.php) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a 9 | // copy of this software and associated documentation files (the "Software"), 10 | // to deal in the Software without restriction, including without limitation 11 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the 13 | // Software is furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | // DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | #ifndef LUAINTF_H 28 | #include "LuaIntf/LuaIntf.h" 29 | using namespace LuaIntf; 30 | #endif 31 | 32 | //--------------------------------------------------------------------------- 33 | 34 | LUA_INLINE LuaTableRef& LuaTableRef::operator = (const LuaTableRef& that) 35 | { 36 | assert(L == that.L); 37 | lua_rawgeti(L, LUA_REGISTRYINDEX, that.m_table); 38 | lua_rawgeti(L, LUA_REGISTRYINDEX, m_table); 39 | lua_rawgeti(L, LUA_REGISTRYINDEX, m_key); 40 | lua_rawgeti(L, LUA_REGISTRYINDEX, that.m_key); 41 | lua_gettable(L, -4); 42 | lua_settable(L, -3); 43 | lua_pop(L, 2); 44 | return *this; 45 | } 46 | 47 | LUA_INLINE LuaTableIterator::LuaTableIterator(lua_State* state, int table, bool fetch_next) 48 | : L(state) 49 | , m_table(table) 50 | , m_key(LUA_NOREF) 51 | , m_value(LUA_NOREF) 52 | { 53 | assert(L); 54 | if (fetch_next) { 55 | next(); 56 | } 57 | } 58 | 59 | LUA_INLINE LuaTableIterator::LuaTableIterator(const LuaTableIterator& that) 60 | : L(that.L) 61 | , m_table(that.m_table) 62 | { 63 | if (L) { 64 | lua_rawgeti(L, LUA_REGISTRYINDEX, that.m_key); 65 | m_key = luaL_ref(L, LUA_REGISTRYINDEX); 66 | lua_rawgeti(L, LUA_REGISTRYINDEX, that.m_value); 67 | m_value = luaL_ref(L, LUA_REGISTRYINDEX); 68 | } else { 69 | m_key = LUA_NOREF; 70 | m_value = LUA_NOREF; 71 | } 72 | } 73 | 74 | LUA_INLINE LuaTableIterator::LuaTableIterator(LuaTableIterator&& that) 75 | : L(that.L) 76 | , m_table(that.m_table) 77 | , m_key(that.m_key) 78 | , m_value(that.m_table) 79 | { 80 | that.m_key = LUA_NOREF; 81 | that.m_value = LUA_NOREF; 82 | } 83 | 84 | LUA_INLINE LuaTableIterator::~LuaTableIterator() 85 | { 86 | if (L) { 87 | luaL_unref(L, LUA_REGISTRYINDEX, m_key); 88 | luaL_unref(L, LUA_REGISTRYINDEX, m_value); 89 | } 90 | } 91 | 92 | LUA_INLINE LuaTableIterator& LuaTableIterator::operator = (const LuaTableIterator& that) 93 | { 94 | if (this != &that) { 95 | if (L) { 96 | luaL_unref(L, LUA_REGISTRYINDEX, m_key); 97 | luaL_unref(L, LUA_REGISTRYINDEX, m_value); 98 | } 99 | L = that.L; 100 | m_table = that.m_table; 101 | if (L) { 102 | lua_rawgeti(L, LUA_REGISTRYINDEX, that.m_key); 103 | m_key = luaL_ref(L, LUA_REGISTRYINDEX); 104 | lua_rawgeti(L, LUA_REGISTRYINDEX, that.m_value); 105 | m_value = luaL_ref(L, LUA_REGISTRYINDEX); 106 | } else { 107 | m_key = LUA_NOREF; 108 | m_value = LUA_NOREF; 109 | } 110 | } 111 | return *this; 112 | } 113 | 114 | LUA_INLINE LuaTableIterator& LuaTableIterator::operator = (LuaTableIterator&& that) 115 | { 116 | std::swap(L, that.L); 117 | std::swap(m_table, that.m_table); 118 | std::swap(m_key, that.m_key); 119 | std::swap(m_value, that.m_value); 120 | return *this; 121 | } 122 | 123 | LUA_INLINE bool LuaTableIterator::operator == (const LuaTableIterator& that) const 124 | { 125 | if (L != that.L || m_table != that.m_table) { 126 | return false; 127 | } else if (m_key == that.m_key) { 128 | return true; 129 | } else { 130 | lua_rawgeti(L, LUA_REGISTRYINDEX, m_key); 131 | lua_rawgeti(L, LUA_REGISTRYINDEX, that.m_key); 132 | bool ok = lua_rawequal(L, -1, -2) != 0; 133 | lua_pop(L, 2); 134 | return ok; 135 | } 136 | } 137 | 138 | LUA_INLINE void LuaTableIterator::next() 139 | { 140 | assert(L); 141 | lua_rawgeti(L, LUA_REGISTRYINDEX, m_table); 142 | lua_rawgeti(L, LUA_REGISTRYINDEX, m_key); 143 | luaL_unref(L, LUA_REGISTRYINDEX, m_key); 144 | luaL_unref(L, LUA_REGISTRYINDEX, m_value); 145 | if (lua_next(L, -2)) { 146 | m_value = luaL_ref(L, LUA_REGISTRYINDEX); 147 | m_key = luaL_ref(L, LUA_REGISTRYINDEX); 148 | } else { 149 | m_value = LUA_NOREF; 150 | m_key = LUA_NOREF; 151 | } 152 | lua_pop(L, 1); 153 | } 154 | 155 | LUA_INLINE LuaRef::LuaRef(const LuaRef& that) 156 | : L(that.L) 157 | { 158 | if (L) { 159 | lua_rawgeti(L, LUA_REGISTRYINDEX, that.m_ref); 160 | m_ref = luaL_ref(L, LUA_REGISTRYINDEX); 161 | } else { 162 | m_ref = LUA_NOREF; 163 | } 164 | } 165 | 166 | LUA_INLINE LuaRef& LuaRef::operator = (const LuaRef& that) 167 | { 168 | if (this != &that) { 169 | if (L) { 170 | luaL_unref(L, LUA_REGISTRYINDEX, m_ref); 171 | } 172 | L = that.L; 173 | if (L) { 174 | lua_rawgeti(L, LUA_REGISTRYINDEX, that.m_ref); 175 | m_ref = luaL_ref(L, LUA_REGISTRYINDEX); 176 | } else { 177 | m_ref = LUA_NOREF; 178 | } 179 | } 180 | return *this; 181 | } 182 | 183 | LUA_INLINE LuaTypeID LuaRef::type() const 184 | { 185 | if (m_ref == LUA_NOREF) { 186 | return LuaTypeID::NONE; 187 | } else if (m_ref == LUA_REFNIL) { 188 | return LuaTypeID::NIL; 189 | } else { 190 | pushToStack(); 191 | int t = lua_type(L, -1); 192 | lua_pop(L, 1); 193 | return static_cast(t); 194 | } 195 | } 196 | 197 | LUA_INLINE bool LuaRef::isIdenticalTo(const LuaRef& r) const 198 | { 199 | pushToStack(); 200 | r.pushToStack(); 201 | bool b = lua_rawequal(L, -2, -1) != 0; 202 | lua_pop(L, 2); 203 | return b; 204 | } 205 | 206 | LUA_INLINE int LuaRef::compareTo(const LuaRef& r) const 207 | { 208 | pushToStack(); 209 | r.pushToStack(); 210 | int d = lua_compare(L, -2, -1, LUA_OPEQ) 211 | ? 0 212 | : (lua_compare(L, -2, -1, LUA_OPLT) ? -1 : 1); 213 | lua_pop(L, 2); 214 | return d; 215 | } 216 | 217 | LUA_INLINE bool LuaRef::operator == (const LuaRef& r) const 218 | { 219 | pushToStack(); 220 | r.pushToStack(); 221 | bool b = lua_compare(L, -2, -1, LUA_OPEQ) != 0; 222 | lua_pop(L, 2); 223 | return b; 224 | } 225 | 226 | LUA_INLINE bool LuaRef::operator < (const LuaRef& r) const 227 | { 228 | pushToStack(); 229 | r.pushToStack(); 230 | bool b = lua_compare(L, -2, -1, LUA_OPLT) != 0; 231 | lua_pop(L, 2); 232 | return b; 233 | } 234 | 235 | LUA_INLINE bool LuaRef::operator <= (const LuaRef& r) const 236 | { 237 | pushToStack(); 238 | r.pushToStack(); 239 | bool b = lua_compare(L, -2, -1, LUA_OPLE) != 0; 240 | lua_pop(L, 2); 241 | return b; 242 | } 243 | 244 | LUA_INLINE LuaRef LuaRef::getMetaTable() const 245 | { 246 | LuaRef meta; 247 | pushToStack(); 248 | if (lua_getmetatable(L, -1)) { 249 | meta = popFromStack(L); 250 | } 251 | lua_pop(L, 1); 252 | return meta; 253 | } 254 | 255 | LUA_INLINE void LuaRef::setMetaTable(const LuaRef& meta) 256 | { 257 | pushToStack(); 258 | meta.pushToStack(); 259 | lua_setmetatable(L, -2); 260 | lua_pop(L, 1); 261 | } 262 | -------------------------------------------------------------------------------- /LuaIntf/src/LuaState.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // https://github.com/SteveKChiu/lua-intf 3 | // 4 | // Copyright 2014, Steve K. Chiu 5 | // 6 | // The MIT License (http://www.opensource.org/licenses/mit-license.php) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a 9 | // copy of this software and associated documentation files (the "Software"), 10 | // to deal in the Software without restriction, including without limitation 11 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the 13 | // Software is furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | // DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | #ifndef LUAINTF_H 28 | #include "LuaIntf/LuaIntf.h" 29 | using namespace LuaIntf; 30 | #endif 31 | 32 | //--------------------------------------------------------------------------- 33 | 34 | LUA_INLINE void Lua::pushGlobal(lua_State* L, const char* name) 35 | { 36 | const char* p = strchr(name, '.'); 37 | if (p) { 38 | lua_pushglobaltable(L); // 39 | while (p) { 40 | lua_pushlstring(L, name, p - name); //
41 | lua_gettable(L, -2); //
42 | lua_remove(L, -2); // 43 | if (lua_isnoneornil(L, -1)) return; 44 | name = p + 1; 45 | p = strchr(name, '.'); 46 | } 47 | lua_pushstring(L, name); // 48 | lua_gettable(L, -2); // 49 | lua_remove(L, -2); // 50 | } else { 51 | lua_getglobal(L, name); 52 | } 53 | } 54 | 55 | LUA_INLINE void Lua::popToGlobal(lua_State* L, const char* name) 56 | { 57 | const char* p = strchr(name, '.'); 58 | if (p) { 59 | lua_pushglobaltable(L); //
60 | while (p) { 61 | lua_pushlstring(L, name, p - name); //
62 | lua_gettable(L, -2); //
63 | lua_remove(L, -2); // 64 | name = p + 1; 65 | p = strchr(name, '.'); 66 | } 67 | lua_pushstring(L, name); // 68 | lua_pushvalue(L, -3); // 69 | lua_settable(L, -3); // 70 | lua_pop(L, 2); 71 | } else { 72 | lua_setglobal(L, name); 73 | } 74 | } 75 | 76 | LUA_INLINE void Lua::exec(lua_State* L, const char* lua_expr, int num_results) 77 | { 78 | lua_pushcfunction(L, &LuaException::traceback); 79 | 80 | int err = luaL_loadstring(L, lua_expr); 81 | 82 | if (err == LUA_OK) { 83 | err = lua_pcall(L, 0, num_results, -2); 84 | } 85 | 86 | if (err != LUA_OK) { 87 | lua_remove(L, -2); 88 | throw LuaException(L); 89 | } 90 | 91 | lua_remove(L, -(num_results + 1)); 92 | } 93 | 94 | LUA_INLINE const char* LuaState::pushf(const char* fmt, ...) const 95 | { 96 | va_list argp; 97 | va_start(argp, fmt); 98 | const char* ret = lua_pushvfstring(L, fmt, argp); 99 | va_end(argp); 100 | return ret; 101 | } 102 | 103 | LUA_INLINE int LuaState::error(const char* fmt, ...) const 104 | { 105 | va_list argp; 106 | va_start(argp, fmt); 107 | lua_pushvfstring(L, fmt, argp); 108 | va_end(argp); 109 | return lua_error(L); 110 | } 111 | -------------------------------------------------------------------------------- /LuaIntf/src/QtLuaIntf.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // https://github.com/SteveKChiu/lua-intf 3 | // 4 | // Copyright 2014, Steve K. Chiu 5 | // 6 | // The MIT License (http://www.opensource.org/licenses/mit-license.php) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a 9 | // copy of this software and associated documentation files (the "Software"), 10 | // to deal in the Software without restriction, including without limitation 11 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the 13 | // Software is furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | // DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | #ifndef QTLUAINTF_H 28 | #include "LuaIntf/QtLuaIntf.h" 29 | using namespace LuaIntf; 30 | #endif 31 | 32 | //--------------------------------------------------------------------------- 33 | 34 | LUA_INLINE void Lua::pushVariant(lua_State* L, const QVariant& v) 35 | { 36 | switch (v.type()) { 37 | case QVariant::Invalid: 38 | lua_pushnil(L); 39 | break; 40 | case QVariant::Bool: 41 | lua_pushboolean(L, v.toBool()); 42 | break; 43 | case QVariant::Int: 44 | lua_pushinteger(L, v.toInt()); 45 | break; 46 | case QVariant::UInt: 47 | lua_pushunsigned(L, v.toUInt()); 48 | break; 49 | case QVariant::LongLong: 50 | push(L, v.toLongLong()); 51 | break; 52 | case QVariant::ULongLong: 53 | push(L, v.toULongLong()); 54 | break; 55 | case QVariant::Double: 56 | lua_pushnumber(L, v.toDouble()); 57 | break; 58 | case QVariant::Map: 59 | pushMap(L, v.toMap()); 60 | break; 61 | case QVariant::List: 62 | pushList(L, v.toList()); 63 | break; 64 | case QVariant::StringList: 65 | pushList(L, v.toStringList()); 66 | break; 67 | case QVariant::ByteArray: 68 | push(L, v.toByteArray()); 69 | break; 70 | default: 71 | push(L, v.toString()); 72 | break; 73 | } 74 | } 75 | 76 | LUA_INLINE QVariant Lua::getVariant(lua_State* L, int idx) 77 | { 78 | int type = lua_type(L, idx); 79 | if (type == LUA_TNIL || type == LUA_TNONE) { 80 | return QVariant(); 81 | } else if (type == LUA_TNUMBER) { 82 | return lua_tonumber(L, idx); 83 | } else if (type == LUA_TBOOLEAN) { 84 | return lua_toboolean(L, idx) != 0; 85 | } else if (type == LUA_TSTRING) { 86 | size_t l; 87 | const char* s = lua_tolstring(L, idx, &l); 88 | return QByteArray(s, l); 89 | } else if (luaL_callmeta(L, idx, "__tostring")) { 90 | size_t l; 91 | const char* s = lua_tolstring(L, -1, &l); 92 | if (!s) { 93 | luaL_error(L, "'tostring' must return a string"); 94 | return QVariant(); 95 | } 96 | QByteArray buf(s, l); 97 | lua_pop(L, 1); 98 | return buf; 99 | } else if (type == LUA_TTABLE) { 100 | if (luaL_len(L, idx) > 0) { 101 | return getList(L, idx); 102 | } else { 103 | return getMap(L, idx); 104 | } 105 | } else { 106 | luaL_error(L, "unknown type, can not convert to variant"); 107 | return QVariant(); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | lua-intf 2 | ======== 3 | 4 | `lua-intf` is a binding between C++11 and Lua language, it provides three different set of API in one package: 5 | 6 | + `LuaBinding`, Export C++ class or function to Lua script 7 | + `LuaRef`, High level API to access Lua object 8 | + `LuaState`, Low level API as simple wrapper for Lua C API 9 | 10 | `lua-intf` has no dependencies other than Lua and C++11. And by default it is headers-only library, so there is no makefile or other install instruction, just copy the source, include `LuaIntf.h`, and you are ready to go. 11 | 12 | `lua-intf` is inspired by [vinniefalco's LuaBridge](https://github.com/vinniefalco/LuaBridge) work, but has been rewritten to take advantage of C++11 features. 13 | 14 | Lua and C++ error handling 15 | -------------------------- 16 | 17 | By default LuaIntf expect the Lua library to build under C++, this will allow Lua library to throw exception upon error, and make sure C++ objects on stack to be destructed correctly. For more info about error handling issues, please see: 18 | 19 | http://lua-users.org/wiki/ErrorHandlingBetweenLuaAndCplusplus 20 | 21 | If you really want to use Lua library compiled under C and want to live with `longjmp` issues, you can define `LUAINTF_LINK_LUA_COMPILED_IN_CXX` to 0 before including `lua-intf` headers: 22 | ````c++ 23 | #define LUAINTF_LINK_LUA_COMPILED_IN_CXX 0 24 | #include "LuaIntf/LuaIntf.h" 25 | ```` 26 | 27 | Compile Lua library in C++ 28 | -------------------------- 29 | 30 | Most distributions of precompiled Lua library are compiled under C, if you need Lua library compiled under C++, you probably need to compile it by yourself. It is actually very easy to build Lua library under C++, first get a copy of source code of the Lua library: 31 | ```` 32 | curl http://www.lua.org/ftp/lua-5.3.0.tar.gz -o lua-5.3.0.tar.gz 33 | tar xf lua-5.3.0.tar.gz 34 | cd lua-5.3.0 35 | ```` 36 | 37 | To compile on Linux: 38 | ```` 39 | make linux MYCFLAGS="-x c++" CC="g++" 40 | ```` 41 | 42 | To compile on Mac OSX: 43 | ```` 44 | make macosx MYCFLAGS="-x c++" MYLDFLAGS="-lc++" 45 | ```` 46 | 47 | To compile on Windows with MINGW and MSYS: 48 | ```` 49 | make mingw MYCFLAGS="-x c++" CC="g++" 50 | ```` 51 | 52 | And then install to your chosen directory in ``: 53 | ```` 54 | make install INSTALL_TOP= 55 | ```` 56 | 57 | Export C++ class or function to Lua script 58 | ------------------------------------------ 59 | 60 | You can easily export C++ class or function for Lua script, consider the following C++ class: 61 | ````c++ 62 | class Web 63 | { 64 | public: 65 | // base_url is optional 66 | Web(const std::string& base_url); 67 | ~Web(); 68 | 69 | static void go_home(); 70 | 71 | static std::string home_url(); 72 | static void set_home_url(const std::string& url); 73 | 74 | std::string url() const; 75 | void set_url(const std::string& url); 76 | std::string resolve_url(const std::string& uri); 77 | 78 | // doing reload if uri is empty 79 | std::string load(const std::string& uri); 80 | }; 81 | ```` 82 | You can export the `Web` class by the following code: 83 | ````c++ 84 | LuaBinding(L).beginClass("Web") 85 | .addConstructor(LUA_ARGS(_opt)) 86 | .addStaticProperty("home_url", &Web::home_url, &Web::set_home_url) 87 | .addStaticFunction("go_home", &Web::go_home) 88 | .addProperty("url", &Web::url, &Web::set_url) 89 | .addFunction("resolve_url", &Web::resolve_url) 90 | .addFunction("load", &Web::load, LUA_ARGS(_opt)) 91 | .addStaticFunction("lambda", [] { 92 | // you can use C++11 lambda expression here too 93 | return "yes"; 94 | }) 95 | .endClass(); 96 | ```` 97 | To access the exported `Web` class in Lua: 98 | ````lua 99 | local w = Web() -- auto w = Web(""); 100 | w.url = "http://www.yahoo.com" -- w.set_url("http://www.yahoo.com"); 101 | local page = w:load() -- auto page = w.load(""); 102 | page = w:load("http://www.google.com") -- page = w.load("http://www.google.com"); 103 | local url = w.url -- auto url = w.url(); 104 | ```` 105 | 106 | Module and class 107 | ---------------- 108 | 109 | C++ class or functions exported are organized by module and class. The general layout of binding looks like: 110 | ````c++ 111 | LuaBinding(L) 112 | .beginModule(string module_name) 113 | .addFactory(function* func) 114 | 115 | .addConstant(string constant_name, VALUE_TYPE value) 116 | 117 | .addVariable(string property_name, VARIABLE_TYPE* var, bool writable = true) 118 | .addVariableRef(string property_name, VARIABLE_TYPE* var, bool writable = true) 119 | 120 | .addProperty(string property_name, FUNCTION_TYPE getter, FUNCTION_TYPE setter) 121 | .addProperty(string property_name, FUNCTION_TYPE getter) 122 | 123 | .addFunction(string function_name, FUNCTION_TYPE func) 124 | 125 | .beginModule(string sub_module_name) 126 | ... 127 | .endModule() 128 | 129 | .beginClass(string class_name) 130 | ... 131 | .endClass() 132 | 133 | .beginExtendClass(string sub_class_name) 134 | ... 135 | .endClass() 136 | .endModule() 137 | 138 | .beginClass(string class_name) 139 | .addFactory(FUNCTION_TYPE func) // you can only have one addFactory or addConstructor 140 | .addConstructor(LUA_ARGS(...)) 141 | 142 | .addConstant(string constant_name, VALUE_TYPE value) 143 | 144 | .addStaticVariable(string property_name, VARIABLE_TYPE* var, bool writable = true) 145 | .addStaticVariableRef(string property_name, VARIABLE_TYPE* var, bool writable = true) 146 | 147 | .addStaticProperty(string property_name, FUNCTION_TYPE getter, FUNCTION_TYPE setter) 148 | .addStaticProperty(string property_name, FUNCTION_TYPE getter) 149 | 150 | .addStaticFunction(string function_name, FUNCTION_TYPE func) 151 | 152 | .addVariable(string property_name, CXX_TYPE::FIELD_TYPE* var, bool writable = true) 153 | .addVariableRef(string property_name, CXX_TYPE::FIELD_TYPE* var, bool writable = true) 154 | 155 | .addProperty(string property_name, CXX_TYPE::FUNCTION_TYPE getter, CXX_TYPE::FUNCTION_TYPE setter) 156 | .addProperty(string property_name, CXX_TYPE::FUNCTION_TYPE getter, CXX_TYPE::FUNCTION_TYPE getter_const, CXX_TYPE::FUNCTION_TYPE setter) 157 | .addProperty(string property_name, CXX_TYPE::FUNCTION_TYPE getter) 158 | 159 | .addPropertyReadOnly(string property_name, CXX_TYPE::FUNCTION_TYPE getter, CXX_TYPE::FUNCTION_TYPE getter_const) 160 | .addPropertyReadOnly(string property_name, CXX_TYPE::FUNCTION_TYPE getter) 161 | 162 | .addFunction(string function_name, CXX_TYPE::FUNCTION_TYPE func) 163 | .endClass() 164 | 165 | .beginExtendClass(string sub_class_name) 166 | ... 167 | .endClass() 168 | ```` 169 | A module binding is like a package or namespace, it can also contain other sub-module or class. A module can have the following bindings: 170 | 171 | + factory function - bind to global or static C++ functions, or forward to sub-class constructor or sub-module factory 172 | + constant - bind to constant value 173 | + variable - bind to global or static variable, the valued pushed to lua is by-value, can be read-only 174 | + variable reference - bind to global or static variable, the valued pushed to lua is by-reference, can be read-only 175 | + property - bind to getter and setter functions, can be read-only 176 | + function - bind to global or static function 177 | 178 | A class binding is modeled after C++ class, it models the const-ness correctly, so const object can not access non-const functions. It can have the following bindings: 179 | 180 | + constructor - bind to class constructor 181 | + factory function - bind to global or static function that return the newly created object 182 | + constant - bind to constant value, constant is static 183 | + static variable - bind to global or static variable, the valued pushed to lua is by-value, can be read-only 184 | + static variable reference - bind to global or static variable, the valued pushed to lua is by-reference, can be read-only 185 | + static property - bind to global or static getter and setter functions, can be read-only 186 | + static function - bind to global or static function 187 | + member variable - bind to member fields, the valued pushed to lua is by-value, can be read-only 188 | + member variable reference - bind to member fields, the valued pushed to lua is by-reference, can be read-only 189 | + member property - bind to member getter and setter functions, you can bind const and non-const version of getters, can be read-only 190 | + member function - bind to member functions 191 | 192 | For module and class, you can have only one constructor or factory function. To access the factory or constructor in Lua script, you call the module or class name like a function, for example the above `Web` class: 193 | ````lua 194 | local w = Web("http://www.google.com") 195 | ```` 196 | The static or module variable, property and constant is accessible by module/class name, it is just like table field: 197 | ````lua 198 | local url = Web.home_url 199 | Web.home_url = "http://www.google.com" 200 | ```` 201 | The static function can be called by the following, note the '.' syntax and class name: 202 | ````lua 203 | Web.go_home() 204 | ```` 205 | The member variable and property is associated with object, so it is accessible by variable: 206 | ````lua 207 | local session = Web("http://www.google.com") 208 | local url = session.url 209 | session.url = "http://www.google.com" 210 | ```` 211 | The member function can be called by the following, note the ':' syntax and object name: 212 | ````lua 213 | session:load("http://www.yahoo.com") 214 | ```` 215 | 216 | Integrate with Lua module system 217 | -------------------------------- 218 | 219 | The lua module system don't register modules in global variables. So you'll need to pass a local reference to `LuaBinding`. For example: 220 | ````c++ 221 | extern "C" int luaopen_modname(lua_State* L) 222 | { 223 | LuaRef mod = LuaRef::createTable(L); 224 | LuaBinding(mod) 225 | ...; 226 | mod.pushToStack(); 227 | return 1; 228 | } 229 | ```` 230 | 231 | C++ object life-cycle 232 | --------------------- 233 | 234 | `lua-intf` store C++ object via Lua `userdata`, and it stores the object in the following ways: 235 | 236 | + By value, the C++ object is stored inside `userdata`. So when Lua need to gc the `userdata`, the memory is automatically released. `lua-intf` will make sure the C++ destructor is called when that happened. C++ constructor or function returns object struct will create this kind of Lua object. 237 | 238 | + By pointer, only the pointer is stored inside `userdata`. So when Lua need to gc the `userdata`, the object is still alive. The object is owned by C++ code, it is important the registered function does not return pointer to newly allocated object that need to be deleted explicitly, otherwise there will be memory leak. C++ function returns pointer or reference to object will create this kind of Lua object. 239 | 240 | + By shared pointer, the shared pointer is stored inside `userdata`. So when Lua need to gc the `userdata`, the shared pointer is destructed, that usually means Lua is done with the object. If the object is still referenced by other shared pointer, it will keep alive, otherwise it will be deleted as expected. C++ function returns shared pointer will create this kind of Lua object. A special version of `addConstructor` will also create shared pointer automatically. 241 | 242 | Using shared pointer 243 | -------------------- 244 | 245 | If both C++ and Lua code need to access the same object, it is usually better to use shared pointer in both side, thus avoiding memory leak. You can use any kind of shared pointer class, as long as it provides: 246 | 247 | + `operator ->` 248 | + `operator *` 249 | + `operator bool` 250 | + default constructor 251 | + copy constructor 252 | 253 | Before you can use it, you need to register it with `lua-intf`, take `std::shared_ptr` for example: 254 | ````c++ 255 | namespace LuaIntf 256 | { 257 | LUA_USING_SHARED_PTR_TYPE(std::shared_ptr) 258 | } 259 | ```` 260 | For constructing shared pointer inside Lua `userdata`, you can register the constructor by adding LUA_SP macro and the actual shared pointer type, for example: 261 | ````c++ 262 | LuaBinding(L).beginClass("web") 263 | .addConstructor(LUA_SP(std::shared_ptr), LUA_ARGS(_opt)) 264 | ... 265 | .endClass(); 266 | ```` 267 | 268 | Using custom deleter 269 | -------------------- 270 | 271 | If custom deleter is needed instead of the destructor, you can register the constructor with deleter by adding LUA_DEL macro, for example: 272 | ````c++ 273 | class MyClass 274 | { 275 | public: 276 | MyClass(int, int); 277 | void release(); 278 | }; 279 | 280 | struct MyClassDeleter 281 | { 282 | void operator () (MyClass* p) 283 | { 284 | p->release(); 285 | } 286 | }; 287 | 288 | LuaBinding(L).beginClass("MyClass") 289 | .addConstructor(LUA_DEL(MyClassDeleter), LUA_ARGS(int, int)) 290 | ... 291 | .endClass(); 292 | ```` 293 | 294 | Using STL-style container 295 | ------------------------- 296 | 297 | By default `lua-intf` does not add conversion for container types, however, you can enable support for container type with the following: 298 | 299 | ````c++ 300 | namespace LuaIntf 301 | { 302 | LUA_USING_LIST_TYPE(std::vector) 303 | LUA_USING_MAP_TYPE(std::map) 304 | } 305 | ```` 306 | 307 | For non-template or non-default template container type, you can use: 308 | 309 | ````c++ 310 | class non_template_int_list 311 | { ... }; 312 | 313 | template 314 | class custom_template_list 315 | { ... }; 316 | 317 | namespace LuaIntf 318 | { 319 | LUA_USING_LIST_TYPE_X(non_template_int_list) 320 | 321 | // you need to use LUA_COMMA for , to workaround macro limitation 322 | LUA_USING_LIST_TYPE_X(custom_template_list, 323 | typename T, typename A, typename S) 324 | } 325 | ```` 326 | 327 | Function calling convention 328 | --------------------------- 329 | 330 | C++ function exported to Lua can follow one of the two calling conventions: 331 | 332 | + Normal function, the return value will be the value seen on the Lua side. 333 | 334 | + Lua `lua_CFunction` convention, that the first argument is `lua_State*` and the return type is `int`. And just like `lua_CFunction` you need to manually push the result onto Lua stack, and return the number of results pushed. 335 | 336 | `lua-intf` extends `lua_CFunction` convention by allowing more arguments besides `lua_State*`, the following functions will all follow the `lua_CFunction` convention: 337 | ````c++ 338 | // regular lua_CFunction convention 339 | int func_1(lua_state* L); 340 | 341 | // lua_CFunction convention, but allow arg1, arg2 to map to arguments 342 | int func_2(lua_state* L, const std::string& arg1, int arg2); 343 | 344 | // this is *NOT* lua_CFunction 345 | // the L can be placed anywhere, and it is stub to capture lua_State*, 346 | // and do not contribute to actual Lua arguments 347 | int func_3(const std::string& arg1, lua_state* L); 348 | 349 | class Object 350 | { 351 | public: 352 | // class method can follow lua_CFunction convention too 353 | int func_1(lua_state* L); 354 | 355 | // class lua_CFunction convention, but allow arg1, arg2 to map to arguments 356 | int func_2(lua_state* L, const std::string& arg1, int arg2); 357 | }; 358 | 359 | // the following can also be lua_CFunction convention if it is added as class functions 360 | // note the first argument must be the pointer type of the registered class 361 | int obj_func_1(Object* obj, lua_state* L); 362 | int obj_func_2(Object* obj, lua_state* L, const std::string& arg1, int arg2); 363 | ```` 364 | For every function registration, `lua-intf` also support C++11 `std::function` type, so you can use `std::bind` or lambda expression if needed. You can use lambda expression freely without giving full `std::function` declaration; `std::bind` on the other hand, must be declared: 365 | ````c++ 366 | LuaBinding(L).beginClass("Web") 367 | .addStaticFunction("lambda", [] { 368 | // you can use C++11 lambda expression here too 369 | return "yes"; 370 | }) 371 | .addStaticFunction>("bind", 372 | std::bind(&Web::url, other_web_object)) 373 | .endClass(); 374 | ```` 375 | 376 | If your C++ function is overloaded, pass `&function` is not enough, you have to explicitly cast it to proper type: 377 | ````c++ 378 | static int test(string, int); 379 | static string test(string); 380 | 381 | LuaBinding(L).beginModule("utils") 382 | 383 | // this will bind int test(string, int) 384 | .addFunction("test_1", static_cast(&test)) 385 | 386 | // this will bind string test(string), by using our LUA_FN macro 387 | // LUA_FN(RETURN_TYPE, FUNC_NAME, ARG_TYPES...) 388 | .addFunction("test_2", LUA_FN(string, test, string)) 389 | 390 | .endModule(); 391 | ```` 392 | 393 | Function argument modifiers 394 | --------------------------- 395 | 396 | By default the exported functions expect every argument to be mandatory, if the argument is missing or not compatible with the expected type, the Lua error will be raised. You can change the function passing requirement by adding argument passing modifiers in `LUA_ARGS`, `lua-intf` supports the following modifiers: 397 | 398 | + `_opt`, specify the argument is optional; if the argument is missing, the value is created with default constructor 399 | 400 | + `_def`, specify the argument is optional; if the argument is missing, the default value is used as `DEF_NUM / DEF_DEN` 401 | 402 | + `_out`, specify the argument is for output only; the output value will be pushed after the normal function return value, and in argument order if there is multiple output 403 | 404 | + `_ref`, specify the argument is mandatory and for input/output; the output value will be pushed after the normal function return value, and in argument order if there is multiple output 405 | 406 | + `_ref_opt`, combine `_ref` and `_opt` 407 | 408 | + `_ref_def`, combine `_ref` and `_def` 409 | 410 | + If none of the above modifiers are used, the argument is mandatory and for input only 411 | 412 | All output modifiers require the argument to be reference type, using pointer type for output is not supported. The reason `_def` requires DEF_NUM and DEF_DEN is to workaround C++ limitation. The C++ template does not allow floating point number as non-type argument, in order specify default value for float, you have to specify numerator and denominator pair (the denominator is 1 by default). For example: 413 | 414 | ````c++ 415 | struct MyString 416 | { 417 | std::string indexOf(const std::string& str, int pos); 418 | std::string desc(float number); 419 | ... 420 | }; 421 | 422 | #define _def_float(f) _def 423 | 424 | LuaBinding(L).beginClass("mystring") 425 | 426 | // this will make pos = 1 if it is not specified in Lua side 427 | .addFunction("indexOf", &MyString::indexOf, LUA_ARGS(std::string, _def)) 428 | 429 | // this will make number = 1.333 = (4 / 3) if it is not specified in Lua side 430 | // because C++ does not allow float as non-type template parameter 431 | // you have to use ratio to specify floating numbers 1.333 = (4 / 3) 432 | // LUA_ARGS(_def) will result in error 433 | .addFunction("indexOf", &MyString::desc, LUA_ARGS(_def)) 434 | 435 | // you can define your own macro to make it easier to specify float 436 | // please see _def_float for example 437 | .addFunction("indexOf2", &MyString::desc, LUA_ARGS(_def_float(1.3333f))) 438 | .endClass(); 439 | ```` 440 | 441 | Return multiple results for Lua 442 | ------------------------------- 443 | 444 | It is possible to return multiple results by telling which argument is for output, for example: 445 | ````c++ 446 | static std::string match(const std::string& src, const std::string& pat, int pos, int& found_pos); 447 | 448 | LuaBinding(L).beginModule("utils") 449 | 450 | // this will return (string) (found_pos) 451 | .addFunction("match", &match, LUA_ARGS(std::string, std::string, _def, _out)) 452 | 453 | .endModule(); 454 | ```` 455 | 456 | Yet another way to return multiple results is to use `std::tuple`: 457 | ````c++ 458 | static std::tuple match(const std::string& src, const std::string& pat, int pos); 459 | 460 | LuaBinding(L).beginModule("utils") 461 | 462 | // this will return (string) (found_pos) 463 | .addFunction("match", &match) 464 | 465 | .endModule(); 466 | ```` 467 | 468 | And you can always use `lua_CFunction` to manually push multiple results by yourself. 469 | 470 | Lua for-loop iteration function 471 | ------------------------------- 472 | 473 | `lua-intf` provides a helper class `CppFunctor` to make it easier to implement for-loop iteration function for Lua. To use it, user need to inherit CppFunctor, and override run method and optional destructor. Then call pushToStack to create the functor object on Lua stack. 474 | ````c++ 475 | class MyIterator : public CppFunctor 476 | { 477 | MyIterator(...) 478 | { 479 | ... 480 | } 481 | 482 | virtual ~MyIterator() 483 | { 484 | ... 485 | } 486 | 487 | // the for-loop will call this function for each step until it return 0 488 | virtual int run(lua_State* L) override 489 | { 490 | ... 491 | // return the number of variables for each step of for-loop 492 | // or return 0 to end the for-loop 493 | return 2; 494 | } 495 | } 496 | 497 | int xpairs(lua_State* L) 498 | { 499 | return CppFunctor::make(L, ...); // ... is constructor auguments 500 | } 501 | ```` 502 | To register the for-loop iteration function: 503 | ````c++ 504 | LuaBinding(L).beginModule("utils") 505 | 506 | .addFunction("xpairs", &xpairs) 507 | 508 | .endModule(); 509 | ```` 510 | To use the iteration function in Lua code: 511 | ````lua 512 | for x, y in utils.xpairs(...) do 513 | ... 514 | end 515 | ```` 516 | 517 | Custom type mapping 518 | ------------------- 519 | 520 | It is possible to add primitive type mapping to the `lua-intf`, all you need to do is to add template specialization to `LuaTypeMapping`. You need to: 521 | 522 | + provide `void push(lua_State* L, const Type& v)` 523 | + provide `Type get(lua_State* L, int index)` 524 | + provide `Type opt(lua_State* L, int index, const Type& def)` 525 | 526 | For example, to add `std::wstring` mapping to Lua string: 527 | ````c++ 528 | namespace LuaIntf 529 | { 530 | 531 | template <> 532 | struct LuaTypeMapping 533 | { 534 | static void push(lua_State* L, const std::wstring& str) 535 | { 536 | if (str.empty()) { 537 | lua_pushliteral(L, ""); 538 | } else { 539 | std::wstring_convert> conv; 540 | std::string buf = conv.to_bytes(str); 541 | lua_pushlstring(L, buf.data(), buf.length()); 542 | } 543 | } 544 | 545 | static std::wstring get(lua_State* L, int index) 546 | { 547 | size_t len; 548 | const char* p = luaL_checklstring(L, index, &len); 549 | std::wstring_convert> conv; 550 | return conv.from_bytes(p, p + len); 551 | } 552 | 553 | static std::wstring opt(lua_State* L, int index, const std::wstring& def) 554 | { 555 | return lua_isnoneornil(L, index) ? def : get(L, index); 556 | } 557 | }; 558 | 559 | } // namespace LuaIntf 560 | ```` 561 | After that, you are able to push `std::wstring` onto or get `std::wstring` from Lua stack directly: 562 | ````c++ 563 | std::wstring s = ...; 564 | Lua::push(L, s); 565 | 566 | ... 567 | 568 | s = Lua::pop(L); 569 | ```` 570 | 571 | High level API to access Lua object 572 | ----------------------------------- 573 | 574 | `LuaRef` is designed to provide easy access to Lua object, and in most case you don't have to deal with Lua stack like the low level API. For example: 575 | ````c++ 576 | lua_State* L = ...; 577 | lua_getglobal(L, "module"); 578 | lua_getfield(L, -1, "method"); 579 | lua_pushintteger(L, 1); 580 | lua_pushstring(L, "yes"); 581 | lua_pushboolean(L, true); 582 | lua_call(L, 3, 0); 583 | ```` 584 | The above code can be rewritten as: 585 | ````c++ 586 | LuaRef func(L, "module.method"); 587 | func(1, "yes", true); 588 | ```` 589 | Table access is as simple: 590 | ````c++ 591 | LuaRef table(L, "my_table"); 592 | table["value"] = 15; 593 | int value = table.get("value"); 594 | 595 | for (auto& e : table) { 596 | std::string key = e.key(); 597 | LuaRef value = e.value(); 598 | ... 599 | } 600 | ```` 601 | And you can mix it with the low level API: 602 | ````c++ 603 | lua_State* L = ...; 604 | LuaRef v = ...; 605 | lua_getglobal(L, "my_method"); 606 | Lua::push(L, 1); // the same as lua_pushinteger 607 | Lua::push(L, v); // push v to lua stack 608 | Lua::push(L, true); // the same as lua_pushboolean 609 | lua_call(L, 3, 2); 610 | LuaRef r(L, -2); // map r to lua stack index -2 611 | ```` 612 | You can use the `std::tuple` for multiple return values: 613 | ````c++ 614 | LuaRef func(L, "utils.match"); 615 | std::string found; 616 | int found_pos; 617 | std::tie(found, found_pos) = func.call>("this is test", "test"); 618 | ```` 619 | 620 | Low level API as simple wrapper for Lua C API 621 | --------------------------------------------- 622 | 623 | `LuaState` is a simple wrapper of one-to-one mapping for Lua C API, consider the following code: 624 | ````c++ 625 | lua_State* L = ...; 626 | lua_getglobal(L, "module"); 627 | lua_getfield(L, -1, "method"); 628 | lua_pushintteger(L, 1); 629 | lua_pushstring(L, "yes"); 630 | lua_pushboolean(L, true); 631 | lua_call(L, 3, 0); 632 | ```` 633 | It can be effectively rewritten as: 634 | ````c++ 635 | LuaState lua = L; 636 | lua.getGlobal("module"); 637 | lua.getField(-1, "method"); 638 | lua.push(1); 639 | lua.push("yes"); 640 | lua.push(true); 641 | lua.call(3, 0); 642 | ```` 643 | This low level API is completely optional, and you can still use the C API, or mix the usage. `LuaState` is designed to be a lightweight wrapper, and has very little overhead (if not as fast as the C API), and mostly can be auto-casting to or from `lua_State*`. In the `lua-intf`, `LuaState` and `lua_State*` are inter-changeable, you can pick the coding style you like most. 644 | 645 | `LuaState` does not manage `lua_State*` life-cycle, you may take a look at `LuaContext` class for that purpose. 646 | --------------------------------------------------------------------------------