From cbcf62f3415f0a66fc41cc21ce5e6779f65a821e Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 14 Sep 2021 10:29:53 +1000 Subject: [PATCH] spa: add a macro to check for a callback version spa_interface_call() and friends will quietly do nothing if the version doesn't match so we need an extra macro to know whether we can spa_interface_call() for any given version. This allows us to implement things like: if (spa_interface_callback_version_min(1) spa_interface_call(..., 1, func_v1) else spa_interface_call(..., 0, func_v0) --- spa/include/spa/utils/hook.h | 15 ++++++++++++++ test/test-spa-utils.c | 38 ++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/spa/include/spa/utils/hook.h b/spa/include/spa/utils/hook.h index 2dcca9b9a..1206ce025 100644 --- a/spa/include/spa/utils/hook.h +++ b/spa/include/spa/utils/hook.h @@ -179,6 +179,15 @@ struct spa_interface { _f->method((callbacks)->data, ## __VA_ARGS__); \ }) +/** + * True if the \a callbacks are of version \a vers, false otherwise + */ +#define spa_callback_version_min(callbacks,type,vers) \ +({ \ + const type *_f = (const type *) (callbacks)->funcs; \ + SPA_CALLBACK_VERSION_MIN(_f,vers); \ +}) + /** * Invoke method named \a method in the \a callbacks. * The \a method_type defines the type of the method struct. @@ -193,6 +202,12 @@ struct spa_interface { res; \ }) +/** + * True if the \a iface's \a callbacks are of version \a vers, false otherwise + */ +#define spa_interface_callback_version_min(iface,method_type,vers) \ + spa_callback_version_min(&(iface)->cb, method_type, vers) + /** * Invoke method named \a method in the callbacks on the given interface object. * The \a method_type defines the type of the method struct, not the interface diff --git a/test/test-spa-utils.c b/test/test-spa-utils.c index efac766c1..0a750391d 100644 --- a/test/test-spa-utils.c +++ b/test/test-spa-utils.c @@ -968,6 +968,43 @@ PWTEST(utils_callback_func_is_null) return PWTEST_PASS; } +PWTEST(utils_callback_version) +{ + struct cbtest_methods { + uint32_t version; + void (*func_v0)(void *object, const char *msg); + } methods = { 0, cbtest_func }; + struct cbtest { + struct spa_interface iface; + } cbtest; + struct cbtest_data data; + + /* Interface version doesn't matter for this test */ + cbtest.iface = SPA_INTERFACE_INIT("cbtest type", 0, &methods, &data); + + /* Methods are version 0 */ + methods.version = 0; + pwtest_bool_true(spa_interface_callback_version_min(&cbtest.iface, + struct cbtest_methods, + 0)); + pwtest_bool_false(spa_interface_callback_version_min(&cbtest.iface, + struct cbtest_methods, + 1)); + /* Methods are version 1 */ + methods.version = 1; + pwtest_bool_true(spa_interface_callback_version_min(&cbtest.iface, + struct cbtest_methods, + 0)); + pwtest_bool_true(spa_interface_callback_version_min(&cbtest.iface, + struct cbtest_methods, + 1)); + pwtest_bool_false(spa_interface_callback_version_min(&cbtest.iface, + struct cbtest_methods, + 2)); + + return PWTEST_PASS; +} + PWTEST_SUITE(spa_utils) { pwtest_add(utils_abi_sizes, PWTEST_NOARG); @@ -995,6 +1032,7 @@ PWTEST_SUITE(spa_utils) pwtest_add(utils_ansi, PWTEST_NOARG); pwtest_add(utils_callback, PWTEST_NOARG); pwtest_add(utils_callback_func_is_null, PWTEST_NOARG); + pwtest_add(utils_callback_version, PWTEST_NOARG); return PWTEST_PASS; }