summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2020-11-04 15:47:33 -0800
committerVito Caputo <vcaputo@pengaru.com>2020-11-04 15:47:33 -0800
commit18d2918a02028bf649607bb9959b926d10f184f6 (patch)
tree1aeea75d16a17ed14649f9f47b18e5605f3b6044
parent31dea83f4e5f3e57c3fc05d8ad01a58dc844c2c7 (diff)
thunk: introduce public variant of THUNK_DEFINE
This is necessarily split in two: THUNK_DEFINE() THUNK_DECLARE() use is identical to the original THUNK_DEFINE (now THUNK_DEFINE_STATIC), and you supply the same input to both DEFINE and DECLARE. The THUNK_DECLARE() should go in the public header, which you also include in the implementing .c file, not just from consumers. The THUNK_DEFINE() goes in the implementing .c file, same as before. Use this variant when you wish to instantiate via THUNK() from external listings, just include the THUNK_DECLARE()-containing .h.
-rw-r--r--thunk.h50
1 files changed, 50 insertions, 0 deletions
diff --git a/thunk.h b/thunk.h
index ef868ab..d2ec683 100644
--- a/thunk.h
+++ b/thunk.h
@@ -418,6 +418,56 @@ struct thunk_t {
\
static int _THUNK_GEN_PROTO(_name, __VA_ARGS__)
+
+/* this is the public variant which is split across declare & define */
+/* put the declaration in the .h, the define in the .c, be sure to include the
+ * .h from the implementing .c - not just the consumers.
+ */
+#define THUNK_DECLARE(_name, ...) \
+ int _THUNK_GEN_PROTO(_name, __VA_ARGS__); \
+ typedef struct __thunk_environment_##_name { \
+ /* struct for encapsulating the calling environment */ \
+ thunk_t __thunk; \
+ _THUNK_GEN_STRUCT (__VA_ARGS__); \
+ } __thunk_environment_##_name; \
+ \
+ int __thunk_dispatch_##_name(thunk_t *thunk); \
+ thunk_t * _THUNK_GEN_PROTO(__thunk_instantiate_##_name, __VA_ARGS__);
+
+
+#define THUNK_DEFINE(_name, ...) \
+ int __thunk_dispatch_##_name(thunk_t *thunk) { \
+ /* dispatch thunk from associated environment */ \
+ __thunk_environment_##_name *env; \
+ int r; \
+ \
+ /* XXX: the embedded __thunk is always at the start, otherwise \
+ * container_of() could be used... */ \
+ env = (__thunk_environment_##_name *)thunk; \
+ assert(env); \
+ \
+ r = _THUNK_GEN_DISPATCH(_name, env, __VA_ARGS__); \
+ free(env); \
+ \
+ return r; \
+ } \
+ \
+ thunk_t * _THUNK_GEN_PROTO(__thunk_instantiate_##_name, __VA_ARGS__) { \
+ /* allocate and populate environment, return it */ \
+ __thunk_environment_##_name *env; \
+ \
+ env = malloc(sizeof(*env)); \
+ assert(env); \
+ \
+ _THUNK_GEN_INITIALIZE(env, __VA_ARGS__); \
+ env->__thunk.dispatch = __thunk_dispatch_##_name; \
+ \
+ return &env->__thunk; \
+ } \
+ \
+ int _THUNK_GEN_PROTO(_name, __VA_ARGS__)
+
+
/* Call the appropriate instantiate function which returns an embedded thunk_t,
* this is how you prepare the thunks established via THUNK_DEFINE(). */
#define _THUNK(_call) \
© All Rights Reserved