]> git.ozlabs.org Git - ccan/blob - ccan/typesafe_cb/typesafe_cb.h
Upload now works, with a bit of hackery.
[ccan] / ccan / typesafe_cb / typesafe_cb.h
1 #ifndef CCAN_CAST_IF_TYPE_H
2 #define CCAN_CAST_IF_TYPE_H
3 #include "config.h"
4
5 #if HAVE_TYPEOF && HAVE_BUILTIN_CHOOSE_EXPR && HAVE_BUILTIN_TYPES_COMPATIBLE_P
6 /**
7  * cast_if_type - only cast an expression if it is of a given type
8  * @expr: the expression to cast
9  * @oktype: the type we allow
10  * @desttype: the type to cast to
11  *
12  * This macro is used to create functions which allow multiple types.
13  * The result of this macro is used somewhere that a @desttype type is
14  * expected: if @expr was of type @oktype, it will be cast to
15  * @desttype type.  As a result, if @expr is any type other than
16  * @oktype or @desttype, a compiler warning will be issued.
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 cast_if_type(), 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
24  * the "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(expr)                    \
30  *              _set_some_value(cast_if_type((expr), unsigned long, void *))
31  */
32 #define cast_if_type(expr, oktype, desttype)                            \
33 __builtin_choose_expr(__builtin_types_compatible_p(typeof(1?(expr):0), oktype), \
34                         (desttype)(expr), (expr))
35 #else
36 #define cast_if_type(expr, oktype, desttype) ((desttype)(expr))
37 #endif
38
39 /**
40  * typesafe_cb - cast a callback function if it matches the arg
41  * @rettype: the return type of the callback function
42  * @fn: the callback function to cast
43  * @arg: the (pointer) argument to hand to the callback function.
44  *
45  * If a callback function takes a single argument, this macro does
46  * appropriate casts to a function which takes a single void * argument if the
47  * callback provided matches the @arg (or a const or volatile version).
48  *
49  * It is assumed that @arg is of pointer type: usually @arg is passed
50  * or assigned to a void * elsewhere anyway.
51  *
52  * Example:
53  *      void _register_callback(void (*fn)(void *arg), void *arg);
54  *      #define register_callback(fn, arg) \
55  *              _register_callback(typesafe_cb(void, (fn), (arg)), (arg))
56  */
57 #define typesafe_cb(rettype, fn, arg)                                   \
58         cast_if_type(cast_if_type(cast_if_type((fn),                    \
59                                                rettype (*)(const typeof(arg)), \
60                                                rettype (*)(void *)),    \
61                                   rettype (*)(volatile typeof(arg)),    \
62                                   rettype (*)(void *)),                 \
63                      rettype (*)(typeof(arg)),                          \
64                      rettype (*)(void *))
65
66 /**
67  * typesafe_cb_preargs - cast a callback function if it matches the arg
68  * @rettype: the return type of the callback function
69  * @fn: the callback function to cast
70  * @arg: the (pointer) argument to hand to the callback function.
71  *
72  * This is a version of typesafe_cb() for callbacks that take other arguments
73  * before the @arg.
74  *
75  * Example:
76  *      void _register_callback(void (*fn)(int, void *arg), void *arg);
77  *      #define register_callback(fn, arg) \
78  *              _register_callback(typesafe_cb_preargs(void, (fn), (arg), int),\
79  *                                 (arg))
80  */
81 #define typesafe_cb_preargs(rettype, fn, arg, ...)                      \
82         cast_if_type(cast_if_type(cast_if_type((fn),                    \
83                                                rettype (*)(__VA_ARGS__, \
84                                                            const typeof(arg)), \
85                                                rettype (*)(__VA_ARGS__, \
86                                                            void *)),    \
87                                   rettype (*)(__VA_ARGS__,              \
88                                               volatile typeof(arg)),    \
89                                   rettype (*)(__VA_ARGS__, void *)),    \
90                      rettype (*)(__VA_ARGS__, typeof(arg)),             \
91                      rettype (*)(__VA_ARGS__, void *))
92
93 /**
94  * typesafe_cb_postargs - cast a callback function if it matches the arg
95  * @rettype: the return type of the callback function
96  * @fn: the callback function to cast
97  * @arg: the (pointer) argument to hand to the callback function.
98  *
99  * This is a version of typesafe_cb() for callbacks that take other arguments
100  * after the @arg.
101  *
102  * Example:
103  *      void _register_callback(void (*fn)(void *arg, int), void *arg);
104  *      #define register_callback(fn, arg) \
105  *              _register_callback(typesafe_cb_preargs(void, (fn), (arg), int),\
106  *                                 (arg))
107  */
108 #define typesafe_cb_postargs(rettype, fn, arg, ...)                     \
109         cast_if_type(cast_if_type(cast_if_type((fn),                    \
110                                                rettype (*)(const typeof(arg), \
111                                                            __VA_ARGS__), \
112                                                rettype (*)(void *,      \
113                                                            __VA_ARGS__)), \
114                                   rettype (*)(volatile typeof(arg),     \
115                                               __VA_ARGS__),             \
116                                   rettype (*)(void *, __VA_ARGS__)),    \
117                      rettype (*)(typeof(arg), __VA_ARGS__),             \
118                      rettype (*)(void *, __VA_ARGS__))
119
120 #endif /* CCAN_CAST_IF_TYPE_H */