damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

typesafe_cb.h (5019B)


      1 /* CC0 (Public domain) - see LICENSE file for details */
      2 #ifndef CCAN_TYPESAFE_CB_H
      3 #define CCAN_TYPESAFE_CB_H
      4 #include "config.h"
      5 
      6 #if HAVE_TYPEOF && HAVE_BUILTIN_CHOOSE_EXPR && HAVE_BUILTIN_TYPES_COMPATIBLE_P
      7 /**
      8  * typesafe_cb_cast - only cast an expression if it matches a given type
      9  * @desttype: the type to cast to
     10  * @oktype: the type we allow
     11  * @expr: the expression to cast
     12  *
     13  * This macro is used to create functions which allow multiple types.
     14  * The result of this macro is used somewhere that a @desttype type is
     15  * expected: if @expr is exactly of type @oktype, then it will be
     16  * cast to @desttype type, otherwise left alone.
     17  *
     18  * This macro can be used in static initializers.
     19  *
     20  * This is merely useful for warnings: if the compiler does not
     21  * support the primitives required for typesafe_cb_cast(), it becomes an
     22  * unconditional cast, and the @oktype argument is not used.  In
     23  * particular, this means that @oktype can be a type which uses the
     24  * "typeof": it will not be evaluated if typeof is not supported.
     25  *
     26  * Example:
     27  *	// We can take either an unsigned long or a void *.
     28  *	void _set_some_value(void *val);
     29  *	#define set_some_value(e)			\
     30  *		_set_some_value(typesafe_cb_cast(void *, unsigned long, (e)))
     31  */
     32 #define typesafe_cb_cast(desttype, oktype, expr)			\
     33 	__builtin_choose_expr(						\
     34 		__builtin_types_compatible_p(__typeof__(0?(expr):(expr)), \
     35 					     oktype),			\
     36 		(desttype)(expr), (expr))
     37 #else
     38 #define typesafe_cb_cast(desttype, oktype, expr) ((desttype)(expr))
     39 #endif
     40 
     41 /**
     42  * typesafe_cb_cast3 - only cast an expression if it matches given types
     43  * @desttype: the type to cast to
     44  * @ok1: the first type we allow
     45  * @ok2: the second type we allow
     46  * @ok3: the third type we allow
     47  * @expr: the expression to cast
     48  *
     49  * This is a convenient wrapper for multiple typesafe_cb_cast() calls.
     50  * You can chain them inside each other (ie. use typesafe_cb_cast()
     51  * for expr) if you need more than 3 arguments.
     52  *
     53  * Example:
     54  *	// We can take either a long, unsigned long, void * or a const void *.
     55  *	void _set_some_value(void *val);
     56  *	#define set_some_value(expr)					\
     57  *		_set_some_value(typesafe_cb_cast3(void *,,		\
     58  *					    long, unsigned long, const void *,\
     59  *					    (expr)))
     60  */
     61 #define typesafe_cb_cast3(desttype, ok1, ok2, ok3, expr)		\
     62 	typesafe_cb_cast(desttype, ok1,					\
     63 			 typesafe_cb_cast(desttype, ok2,		\
     64 					  typesafe_cb_cast(desttype, ok3, \
     65 							   (expr))))
     66 
     67 /**
     68  * typesafe_cb - cast a callback function if it matches the arg
     69  * @rtype: the return type of the callback function
     70  * @atype: the (pointer) type which the callback function expects.
     71  * @fn: the callback function to cast
     72  * @arg: the (pointer) argument to hand to the callback function.
     73  *
     74  * If a callback function takes a single argument, this macro does
     75  * appropriate casts to a function which takes a single atype argument if the
     76  * callback provided matches the @arg.
     77  *
     78  * It is assumed that @arg is of pointer type: usually @arg is passed
     79  * or assigned to a void * elsewhere anyway.
     80  *
     81  * Example:
     82  *	void _register_callback(void (*fn)(void *arg), void *arg);
     83  *	#define register_callback(fn, arg) \
     84  *		_register_callback(typesafe_cb(void, (fn), void*, (arg)), (arg))
     85  */
     86 #define typesafe_cb(rtype, atype, fn, arg)			\
     87 	typesafe_cb_cast(rtype (*)(atype),			\
     88 			 rtype (*)(__typeof__(arg)),		\
     89 			 (fn))
     90 
     91 /**
     92  * typesafe_cb_preargs - cast a callback function if it matches the arg
     93  * @rtype: the return type of the callback function
     94  * @atype: the (pointer) type which the callback function expects.
     95  * @fn: the callback function to cast
     96  * @arg: the (pointer) argument to hand to the callback function.
     97  *
     98  * This is a version of typesafe_cb() for callbacks that take other arguments
     99  * before the @arg.
    100  *
    101  * Example:
    102  *	void _register_callback(void (*fn)(int, void *arg), void *arg);
    103  *	#define register_callback(fn, arg)				   \
    104  *		_register_callback(typesafe_cb_preargs(void, void *,	   \
    105  *				   (fn), (arg), int),			   \
    106  *				   (arg))
    107  */
    108 #define typesafe_cb_preargs(rtype, atype, fn, arg, ...)			\
    109 	typesafe_cb_cast(rtype (*)(__VA_ARGS__, atype),			\
    110 			 rtype (*)(__VA_ARGS__, __typeof__(arg)),	\
    111 			 (fn))
    112 
    113 /**
    114  * typesafe_cb_postargs - cast a callback function if it matches the arg
    115  * @rtype: the return type of the callback function
    116  * @atype: the (pointer) type which the callback function expects.
    117  * @fn: the callback function to cast
    118  * @arg: the (pointer) argument to hand to the callback function.
    119  *
    120  * This is a version of typesafe_cb() for callbacks that take other arguments
    121  * after the @arg.
    122  *
    123  * Example:
    124  *	void _register_callback(void (*fn)(void *arg, int), void *arg);
    125  *	#define register_callback(fn, arg) \
    126  *		_register_callback(typesafe_cb_postargs(void, (fn), void *, \
    127  *				   (arg), int),				    \
    128  *				   (arg))
    129  */
    130 #define typesafe_cb_postargs(rtype, atype, fn, arg, ...)		\
    131 	typesafe_cb_cast(rtype (*)(atype, __VA_ARGS__),			\
    132 			 rtype (*)(__typeof__(arg), __VA_ARGS__),	\
    133 			 (fn))
    134 #endif /* CCAN_CAST_IF_TYPE_H */