]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-lua: Add DLUA_WRAP_C_DATA macro to more easily expose C structures to lua
authorJosef 'Jeff' Sipek <jeff.sipek@open-xchange.com>
Thu, 25 Feb 2021 15:22:24 +0000 (10:22 -0500)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Fri, 19 Mar 2021 13:13:10 +0000 (15:13 +0200)
src/lib-lua/Makefile.am
src/lib-lua/dlua-wrapper.h [new file with mode: 0644]

index c2c4e5ac1e4bd4fb8144a490bb7c60e4c1aaa836..99a64636bced9ea6612912ad4bd9cb61656b20ab 100644 (file)
@@ -19,7 +19,8 @@ libdovecot_lua_la_LDFLAGS = -export-dynamic
 headers = \
        dlua-compat.h \
        dlua-script.h \
-       dlua-script-private.h
+       dlua-script-private.h \
+       dlua-wrapper.h
 
 pkginc_libdir=$(pkgincludedir)
 pkginc_lib_HEADERS = $(headers)
diff --git a/src/lib-lua/dlua-wrapper.h b/src/lib-lua/dlua-wrapper.h
new file mode 100644 (file)
index 0000000..a86c6b2
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2020 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef DLUA_WRAPPER_H
+#define DLUA_WRAPPER_H
+
+#define DLUA_WRAP_C_DATA(typename, type, putref, extra_fxns_arg)       \
+struct lua_wrapper_##typename {                                                \
+       type *ptr;                                                      \
+       bool ro;                                                        \
+};                                                                     \
+                                                                       \
+static inline type *xlua_##typename##_getptr(lua_State *state, int idx,        \
+                                        bool *ro_r)                    \
+{                                                                      \
+       struct lua_wrapper_##typename *wrapper;                         \
+                                                                       \
+       wrapper = luaL_checkudata(state, idx, #type);                   \
+                                                                       \
+       if (ro_r != NULL)                                               \
+               *ro_r = wrapper->ro;                                    \
+                                                                       \
+       return wrapper->ptr;                                            \
+}                                                                      \
+                                                                       \
+static int xlua_wrapper_##typename##_gc(lua_State *state)              \
+{                                                                      \
+       putref(xlua_##typename##_getptr(state, -1, NULL));              \
+                                                                       \
+       return 0;                                                       \
+}                                                                      \
+                                                                       \
+static const luaL_Reg provided_##typename##_fxns[] = {                 \
+       { "__gc", xlua_wrapper_##typename##_gc },                       \
+       { NULL, NULL },                                                 \
+};                                                                     \
+                                                                       \
+/* push [-0,+1,e] */                                                   \
+static void xlua_push##typename(lua_State *state, type *ptr, bool ro)  \
+{                                                                      \
+       struct lua_wrapper_##typename *wrapper;                         \
+                                                                       \
+       if (ptr == NULL) {                                              \
+               lua_pushnil(state);                                     \
+               return;                                                 \
+       }                                                               \
+                                                                       \
+       wrapper = lua_newuserdata(state, sizeof(struct lua_wrapper_##typename)); \
+       i_assert(wrapper != NULL);                                      \
+                                                                       \
+       wrapper->ptr = (ptr);                                           \
+       wrapper->ro = ro;                                               \
+                                                                       \
+       /* get the current metatable */                                 \
+       luaL_getmetatable(state, #type);                                \
+       if (lua_type(state, -1) != LUA_TTABLE) {                        \
+               /* initialize a new metatable */                        \
+               luaL_Reg *extra_fxns = (extra_fxns_arg);                \
+               lua_CFunction index;                                    \
+                                                                       \
+               lua_pop(state, 1);                                      \
+               luaL_newmetatable(state, #type);                        \
+               luaL_setfuncs(state, provided_##typename##_fxns, 0);    \
+                                                                       \
+               index = NULL;                                           \
+               if (extra_fxns != NULL) {                               \
+                       unsigned i;                                     \
+                                                                       \
+                       luaL_setfuncs(state, extra_fxns, 0);            \
+                                                                       \
+                       for (i = 0; extra_fxns[i].name != NULL; i++) {  \
+                               if (strcmp(extra_fxns[i].name,          \
+                                          "__index") == 0) {           \
+                                       index = extra_fxns[i].func;     \
+                                       break;                          \
+                               }                                       \
+                       }                                               \
+               }                                                       \
+                                                                       \
+               if (index == NULL) {                                    \
+                       /* set __index == metatable */                  \
+                       lua_pushliteral(state, "__index");              \
+                       lua_pushvalue(state, -2); /* dup the table */   \
+                       lua_settable(state, -3);                        \
+               }                                                       \
+       }                                                               \
+                                                                       \
+       /* set the metatable */                                         \
+       lua_setmetatable(state, -2);                                    \
+}
+
+#endif