From 1a56b1e2ab5e9d6d89386ca953b4afb419e15abe Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Sat, 24 Feb 2018 16:40:28 +0100 Subject: [PATCH] qapi: Add qobject_to() This is a dynamic casting macro that, given a QObject type, returns an object as that type or NULL if the object is of a different type (or NULL itself). The macro uses lower-case letters because: 1. There does not seem to be a hard rule on whether qemu macros have to be upper-cased, 2. The current situation in qapi/qmp is inconsistent (compare e.g. QINCREF() vs. qdict_put()), 3. qobject_to() will evaluate its @obj parameter only once, thus it is generally not important to the caller whether it is a macro or not, 4. I prefer it aesthetically. The macro parameter order is chosen with typename first for consistency with other QAPI macros like QAPI_CLONE(), as well as for legibility (read it as "qobject to" type "applied to" obj). Signed-off-by: Max Reitz Message-Id: <20180224154033.29559-3-mreitz@redhat.com> Reviewed-by: Eric Blake Reviewed-by: Alberto Garcia [eblake: swap parameter order to list type first, avoid clang ubsan warning on QOBJECT(NULL) and container_of(NULL,type,base)] Signed-off-by: Eric Blake --- include/qapi/qmp/qobject.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h index 012439a2e3..e022707578 100644 --- a/include/qapi/qmp/qobject.h +++ b/include/qapi/qmp/qobject.h @@ -50,6 +50,21 @@ struct QObject { #define QDECREF(obj) \ qobject_decref(obj ? QOBJECT(obj) : NULL) +/* Required for qobject_to() */ +#define QTYPE_CAST_TO_QNull QTYPE_QNULL +#define QTYPE_CAST_TO_QNum QTYPE_QNUM +#define QTYPE_CAST_TO_QString QTYPE_QSTRING +#define QTYPE_CAST_TO_QDict QTYPE_QDICT +#define QTYPE_CAST_TO_QList QTYPE_QLIST +#define QTYPE_CAST_TO_QBool QTYPE_QBOOL + +QEMU_BUILD_BUG_MSG(QTYPE__MAX != 7, + "The QTYPE_CAST_TO_* list needs to be extended"); + +#define qobject_to(type, obj) ({ \ + QObject *_tmp = qobject_check_type(obj, glue(QTYPE_CAST_TO_, type)); \ + _tmp ? container_of(_tmp, type, base) : (type *)NULL; }) + /* Initialize an object to default values */ static inline void qobject_init(QObject *obj, QType type) { @@ -102,4 +117,18 @@ static inline QType qobject_type(const QObject *obj) return obj->type; } +/** + * qobject_check_type(): Helper function for the qobject_to() macro. + * Return @obj, but only if @obj is not NULL and @type is equal to + * @obj's type. Return NULL otherwise. + */ +static inline QObject *qobject_check_type(const QObject *obj, QType type) +{ + if (obj && qobject_type(obj) == type) { + return (QObject *)obj; + } else { + return NULL; + } +} + #endif /* QOBJECT_H */