From: Josef 'Jeff' Sipek Date: Wed, 24 Mar 2021 15:01:34 +0000 (-0400) Subject: lib-lua: Document the DLUA_WRAP_C_DATA macro X-Git-Tag: 2.3.15~128 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4ccc5f9571fbad93d39d16788f30cf94d2a543d5;p=thirdparty%2Fdovecot%2Fcore.git lib-lua: Document the DLUA_WRAP_C_DATA macro --- diff --git a/src/lib-lua/dlua-wrapper.h b/src/lib-lua/dlua-wrapper.h index a86c6b255b..4444edc02a 100644 --- a/src/lib-lua/dlua-wrapper.h +++ b/src/lib-lua/dlua-wrapper.h @@ -23,6 +23,81 @@ #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: + * + * = the name for the structure to use in generated symbols + * = the exposed structure's C type + * = the function to remove a reference from the C structure, + * called from the automatically generated __gc metamethod + * = 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(lua_State *, *, bool); + * static inline *xlua__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; \