]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-lua: Document the DLUA_WRAP_C_DATA macro
authorJosef 'Jeff' Sipek <jeff.sipek@open-xchange.com>
Wed, 24 Mar 2021 15:01:34 +0000 (11:01 -0400)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Tue, 30 Mar 2021 08:04:02 +0000 (08:04 +0000)
src/lib-lua/dlua-wrapper.h

index a86c6b255be055b18a26646b22920e814dff5d06..4444edc02a7cbc4fdf7a841930f6d32f7b2bf5ac 100644 (file)
 #ifndef DLUA_WRAPPER_H
 #define DLUA_WRAPPER_H
 
+/*
+ * The following macro generates everything necessary to wrap a C structure
+ * and easily push it onto Lua stacks as well as check that a value on the
+ * stack is of this type.
+ *
+ * To generate the necessary API, simply use the macro in your .c file.  The
+ * arguments consist of:
+ *
+ *   <typename> = the name for the structure to use in generated symbols
+ *   <type> = the exposed structure's C type
+ *   <putref> = the function to remove a reference from the C structure,
+ *       called from the automatically generated __gc metamethod
+ *   <extra_fxns_arg> = a C array of luaL_Reg structs passed to luaL_setfuncs
+ *       to add Lua methods to the type
+ *
+ * For example, to expose struct timespec with a tostring method, one would
+ * use the following in a .c file:
+ *
+ *   // struct timespec isn't refcounted
+ *   static inline void timespec_putref(struct timespec *ts)
+ *   {
+ *   }
+ *
+ *   static int timespec_tostring(lua_State *L);
+ *
+ *   static const luaL_Reg timespec_fxns[] = {
+ *           { "__tostring", timespec_tostring },
+ *           { NULL, NULL },
+ *   };
+ *
+ *   DLUA_WRAP_C_DATA(timespec, struct timespec, timespec_putref, timespec_fxns)
+ *
+ *   static int timespec_tostring(lua_State *L)
+ *   {
+ *           struct timespec *ts;
+ *
+ *           ts = xlua_timespec_getptr(L, -1, NULL);
+ *
+ *           lua_pushfstring(L, "%d.%09ld", ts->tv_sec, ts->tv_nsec);
+ *
+ *           return 1;
+ *   }
+ *
+ *
+ * The two functions making up the exposed structure API are:
+ *
+ *   static void xlua_push<typename>(lua_State *, <type> *, bool);
+ *   static inline <type> *xlua_<typename>_getptr(lua_State *, int, bool *);
+ *
+ * The first pushes the supplied pointer onto the Lua stack, while the
+ * second returns the previously pushed C pointer (or generates a Lua error
+ * if there is a type mismatch).
+ *
+ * The push function tracks the passed in bool argument alongside the C
+ * pointer itself.  The getptr function fills in the bool pointer (if not
+ * NULL) with the pushed bool value.  While this bool isn't used directly by
+ * the generated code and therefore it can be used for anything, the
+ * intention is to allow the API consumers to mark certain pointers as
+ * "read-only" to prevent Lua scripts from attempting to mutate them.  This
+ * allows one to push const pointers while "notifying" the methods that
+ * mutation of any of the members is undefined behavior.
+ *
+ * Also note that the functions are static.  That is, they are intended to
+ * only be used in the file where they are generated since they are somewhat
+ * low-level functions.  If some public form of a push/get function is
+ * desired, it is up to the API consumer to write wrappers around these and
+ * expose them to the rest of the codebase.
+ *
+ * Revisiting the struct timespec example above, the generated API would
+ * be:
+ *
+ *   static void xlua_pushtimespec(lua_State *, struct timespec *, bool);
+ *   static inline struct timespec *xlua_timespec_getptr(lua_State *, int,
+ *                                                       bool *);
+ */
 #define DLUA_WRAP_C_DATA(typename, type, putref, extra_fxns_arg)       \
 struct lua_wrapper_##typename {                                                \
        type *ptr;                                                      \