damus

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

typesafe_cb.h (5496B)


      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 */