Signed-off-by: Marc-André Lureau <[email protected]>
---
include/qom/object.h | 64 +++++++++++++++++++++++++++++++++++++
qom/object.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 148 insertions(+), 5 deletions(-)
diff --git a/include/qom/object.h b/include/qom/object.h
index 9684db935d23..a03f4bf8f7cf 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -1990,6 +1990,70 @@ ObjectProperty
*object_class_property_add_enum(ObjectClass *klass,
int (*get)(Object *, Error **),
void (*set)(Object *, int, Error **));
+/**
+ * struct QapiEnumProp - Descriptor for a QOM property backed by a QAPI enum
type
+ *
+ * Binds a QOM object property to a QAPI enum, providing automatic
+ * string<->int conversion through QAPI visitors and optional
+ * default-value initialization during object instance init.
+ *
+ * Use the QAPI_ENUM_PROP() macro to construct instances inline.
+ *
+ * @name: property name exposed on the QOM object
+ * @description: human-readable description (shown in ``-device help``, etc.)
+ * @default_value: initial enum value applied via @set during instance init,
+ * or -1 (the QAPI_ENUM_PROP default) to skip initialization
+ * @qapi_type: pointer to the generated QAPITypeInfo for the enum
+ * (provides the string<->int lookup table)
+ * @get: getter that returns the current enum value as int, or -1 on error
+ * @set: setter that receives the enum value as int; %NULL for read-only props
+ */
+typedef struct QapiEnumProp {
+ const char *name;
+ const char *description;
+ const int default_value;
+ const QAPITypeInfo *qapi_type;
+ int (*get)(Object *, Error **);
+ void (*set)(Object *, int, Error **);
+} QapiEnumProp;
+
+#define QAPI_ENUM_PROP(...) ({ \
+ static const QapiEnumProp _prop = { \
+ .default_value = -1, __VA_ARGS__ \
+ }; \
+ &_prop; })
+
+/**
+ * object_property_add_qapi_enum:
+ * @obj: the object to add a property to
+ * @prop: property descriptor
+ *
+ * Add an enum property with QAPI type association.
+ *
+ * Use the QAPI_ENUM_PROP() macro to construct the property descriptor
+ * inline. If .default_value is not set, the property is not initialized
+ * (default_value is -1). Otherwise, the setter is called with
+ * default_value during object instance init.
+ *
+ * Example::
+ *
+ * object_class_property_add_qapi_enum(oc, QAPI_ENUM_PROP(
+ * .name = "policy",
+ * .description = "Set the NUMA policy",
+ * .default_value = HOST_MEM_POLICY_DEFAULT,
+ * .qapi_type = &HostMemPolicy_type_info,
+ * .get = my_get_policy,
+ * .set = my_set_policy,
+ * ));
+ *
+ * Returns: The newly added property on success, or %NULL on failure.
+ */
+ObjectProperty *
+object_property_add_qapi_enum(Object *obj, const QapiEnumProp *prop);
+
+ObjectProperty *
+object_class_property_add_qapi_enum(ObjectClass *klass, const QapiEnumProp
*prop);
+
/**
* object_property_add_qapi:
* @obj: the object to add a property to
diff --git a/qom/object.c b/qom/object.c
index 1bfb6b933339..f5568b9f9790 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -1206,7 +1206,7 @@ static void object_class_foreach_tramp(gpointer key,
gpointer value,
return;
}
- if (data->implements_type &&
+ if (data->implements_type &&
!object_class_dynamic_cast(k, data->implements_type)) {
return;
}
@@ -1772,7 +1772,6 @@ int object_property_get_enum(Object *obj, const char
*name,
char *str;
int ret;
ObjectProperty *prop = object_property_find_err(obj, name, errp);
- EnumProperty *enumprop;
if (prop == NULL) {
return -1;
@@ -1785,14 +1784,17 @@ int object_property_get_enum(Object *obj, const char
*name,
return -1;
}
- enumprop = prop->opaque;
-
str = object_property_get_str(obj, name, errp);
if (!str) {
return -1;
}
- ret = qapi_enum_parse(enumprop->lookup, str, -1, errp);
+ if (prop->qapi_type) {
+ ret = qapi_enum_parse(prop->qapi_type->lookup, str, -1, errp);
+ } else {
+ EnumProperty *enumprop = prop->opaque;
+ ret = qapi_enum_parse(enumprop->lookup, str, -1, errp);
+ }
g_free(str);
return ret;
@@ -2595,6 +2597,83 @@ object_class_property_add_enum(ObjectClass *klass, const
char *name,
prop);
}
+static void get_qapi_enum(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ const QapiEnumProp *prop = opaque;
+ int value;
+ Error *err = NULL;
+
+ value = prop->get(obj, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ visit_type_enum(v, name, &value, prop->qapi_type->lookup, errp);
+}
+
+static void set_qapi_enum(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ const QapiEnumProp *prop = opaque;
+ int value;
+
+ if (!visit_type_enum(v, name, &value, prop->qapi_type->lookup, errp)) {
+ return;
+ }
+ prop->set(obj, value, errp);
+}
+
+static void init_qapi_enum(Object *obj, ObjectProperty *prop)
+{
+ const QapiEnumProp *e = prop->opaque;
+
+ if (e->set && e->default_value >= 0) {
+ e->set(obj, e->default_value, &error_abort);
+ }
+}
+
+ObjectProperty *
+object_property_add_qapi_enum(Object *obj, const QapiEnumProp *e)
+{
+ ObjectProperty *prop;
+
+ assert(e && e->qapi_type && e->qapi_type->lookup);
+
+ prop = object_property_add_qapi(obj, e->name, e->qapi_type,
+ e->get ? get_qapi_enum : NULL,
+ e->set ? set_qapi_enum : NULL,
+ NULL,
+ (void *)e);
+ prop->description = g_strdup(e->description);
+ if (e->default_value >= 0) {
+ prop->init = init_qapi_enum;
+ }
+
+ return prop;
+}
+
+ObjectProperty *
+object_class_property_add_qapi_enum(ObjectClass *klass, const QapiEnumProp *e)
+{
+ ObjectProperty *prop;
+
+ assert(e && e->qapi_type && e->qapi_type->lookup);
+
+ prop = object_class_property_add_qapi(klass, e->name, e->qapi_type,
+ e->get ? get_qapi_enum : NULL,
+ e->set ? set_qapi_enum : NULL,
+ NULL,
+ (void *)e);
+ prop->description = g_strdup(e->description);
+ if (e->default_value >= 0) {
+ prop->init = init_qapi_enum;
+ }
+
+ return prop;
+}
+
ObjectProperty *
object_property_add_qapi(Object *obj, const char *name,
const QAPITypeInfo *qapi_type,
--
2.55.0.543.g5ebe2ebe4ea8