Hi

On Fri, Aug 7, 2026 at 3:46 PM Markus Armbruster <[email protected]> wrote:
>
> Marc-André Lureau <[email protected]> writes:
>
> > Add object{_class}_property_add_qapi_enum(), and
> > object_{_class}_property_add_qapi() functions. Set the qapi_type pointer
> > on the resulting ObjectProperty.
> >
> > Signed-off-by: Marc-André Lureau <[email protected]>
>
> The patch appars to do two things: general QAPI-aware property add, and
> special enum property add.  Would it make sense to split it?
>

sure

> > ---
> >  include/qom/object.h | 105 +++++++++++++++++++++++++++++++++++++++++
> >  qom/object.c         | 131 
> > +++++++++++++++++++++++++++++++++++++++++++++++++--
> >  2 files changed, 232 insertions(+), 4 deletions(-)
> >
> > diff --git a/include/qom/object.h b/include/qom/object.h
> > index d96a9afe21d..ebfdbff9a94 100644
> > --- a/include/qom/object.h
> > +++ b/include/qom/object.h
> > @@ -1223,6 +1223,15 @@ void object_property_set_default_bool(ObjectProperty 
> > *prop, bool value);
> >   */
> >  void object_property_set_default_str(ObjectProperty *prop, const char 
> > *value);
> >
> > +/**
> > + * object_property_set_default_enum:
> > + * @prop: the property to set
> > + * @value: the value to be written to the property
> > + *
> > + * Set the property default value.
> > + */
> > +void object_property_set_default_enum(ObjectProperty *prop, int value);
> > +
>
> This addition isn't mentioned in the commit message, unlike the others.
> So the patch actually does three things.
>
> Peeking ahead to find users...  there's just one, in PATCH 12.  It
> replaces object_property_set_default_str() there.
>
> >  /**
> >   * object_property_set_default_list:
> >   * @prop: the property to set
> > @@ -1915,6 +1924,102 @@ 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,
> > + *   ));
>
> I'm not sure the macro is a good idea.  Could we use a simple compound
> literal instead?

A plain compound literal has automatic storage.. the macro just eases
this. You can always open code if it helps.

>
> > + *
> > + * 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);
>
> Observation, not pointing out flaws in your work: I still have to write
> a .get and a .set in order to define a property, and most of these are
> 100% stupid.  I wish I could simply specify "read/write this member" and
> be done, like in qdev.
>
> Are there enum properties whose type is *not* a QAPI enum type?  Hmm we
> do have enum-like string properties, e.g. "boot-mode" in
> hw/arm/xilinx_zynq.c, and "riscv-aia" in target/riscv/kvm/kvm-cpu.c.
> Not a fan.
>
> Should only these functions be used to define enum properties going
> forward?  If yes, the _qapi part in their name is redundant (but might
> be desirable for consistency, I don't know).
>
> > +
> > +/**
> > + * object_property_add_qapi:
> > + * @obj: the object to add a property to
> > + * @name: the name of the property
> > + * @qapi_type: QAPI type info descriptor
> > + * @get: the getter or %NULL if the property is write-only.
>
> Either end all your descriptions with punctuation, or none.

fixed

>
> > + * @set: the setter or %NULL if the property is read-only
> > + * @release: called when the property is removed from the object
> > + * @opaque: opaque pointer for get/set/release
> > + *
> > + * Add a property with a QAPI type association. The property type name
> > + * is derived from @qapi_type->name.
> > + *
> > + * Returns: The newly added property on success, or %NULL on failure.
> > + */
> > +ObjectProperty *
> > +object_property_add_qapi(Object *obj, const char *name,
> > +                         const QAPITypeInfo *qapi_type,
> > +                         ObjectPropertyAccessor *get,
> > +                         ObjectPropertyAccessor *set,
> > +                         ObjectPropertyRelease *release,
> > +                         void *opaque);
>
> This is like object_property_add() with char *type replaced by
> QAPITypeInfo *qapi_type.  Good.
>
> Not so good: the argument descriptions in the function comment differ.
> Let's pick the best one, and use it everywhere.

fixed

>
> > +
> > +ObjectProperty *
> > +object_class_property_add_qapi(ObjectClass *klass,
> > +                               const char *name,
> > +                               const QAPITypeInfo *qapi_type,
> > +                               ObjectPropertyAccessor *get,
> > +                               ObjectPropertyAccessor *set,
> > +                               ObjectPropertyRelease *release,
> > +                               void *opaque);
>
> Likewise, except there's no function comment.  Can't fault your patch
> for that; the existing class property functions lack comments, too.  I
> do fault the code before your series, though: we have pairs of functions
> where we want people to use one, and document only the other.  Perhaps
> we could figure out how to transmit mild electric shocks via the
> keyboard to further deter the use of the better one?
>
> Do we want people to use QAPI-aware functions like these to define
> properties whenever possible?  I figure we do.  What about telling
> people in the comments?
>
> Function to add properties always come in pairs, one for properties tied
> to the class, and one for properties tied to the object.  Most users of
> the latter should use the former instead.  Questions for the QOM
> maintainers:
>
> 1. Is it time to stop requiring the latter?
>    object_property_add_qapi_enum() remains unused at the end of the
>    series...
>
> 2. Should the preferred one at least have a shorter name than the other
>    one?

There is certainly room for future improvements, I don't try to
address everything at once :)

>
> > +
> >  /**
> >   * object_property_add_tm:
> >   * @obj: the object to add a property to
>
> Just skimming the remainder for now.
>
> > diff --git a/qom/object.c b/qom/object.c
> > index a085e78557f..e5e2f09a0a2 100644
> > --- a/qom/object.c
> > +++ b/qom/object.c
> > @@ -24,6 +24,7 @@
> >  #include "qapi/forward-visitor.h"
> >  #include "qapi/qapi-builtin-visit.h"
> >  #include "qobject/qdict.h"
> > +#include "qapi/qapi-type-info.h"
> >  #include "qobject/qjson.h"
> >  #include "qemu/id.h"
> >  #include "qapi/qmp/qerror.h"
> > @@ -1717,6 +1718,15 @@ void object_property_set_default_str(ObjectProperty 
> > *prop, const char *value)
> >      object_property_set_default(prop, QOBJECT(qstring_from_str(value)));
> >  }
> >
> > +void object_property_set_default_enum(ObjectProperty *prop, int value)
> > +{
> > +    assert(prop && prop->qapi_type && prop->qapi_type->lookup);
> > +
> > +    object_property_set_default(prop, QOBJECT(qstring_from_str(
> > +        qapi_enum_lookup(prop->qapi_type->lookup, value)
> > +    )));
> > +}
> > +
> >  void object_property_set_default_list(ObjectProperty *prop)
> >  {
> >      object_property_set_default(prop, QOBJECT(qlist_new()));
> > @@ -1775,7 +1785,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;
> > @@ -1788,14 +1797,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;
> > @@ -2598,6 +2610,117 @@ 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(obj, e->name, e->qapi_type->name,
> > +                               e->get ? get_qapi_enum : NULL,
> > +                               e->set ? set_qapi_enum : NULL,
> > +                               NULL,
> > +                               (void *)e);
> > +    prop->qapi_type = e->qapi_type;
>
> Shouldn't this wrap around object_property_add_qapi()?

ok

>
> > +    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(klass, e->name, e->qapi_type->name,
> > +                                     e->get ? get_qapi_enum : NULL,
> > +                                     e->set ? set_qapi_enum : NULL,
> > +                                     NULL,
> > +                                     (void *)e);
> > +    prop->qapi_type = e->qapi_type;
>
> Shouldn't this wrap around object_class_property_add_qapi()?
>
> > +    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,
> > +                         ObjectPropertyAccessor *get,
> > +                         ObjectPropertyAccessor *set,
> > +                         ObjectPropertyRelease *release,
> > +                         void *opaque)
> > +{
> > +    ObjectProperty *prop;
> > +
> > +    prop = object_property_add(obj, name, qapi_type->name,
> > +                               get, set, release, opaque);
> > +    prop->qapi_type = qapi_type;
> > +    return prop;
> > +}
> > +
> > +ObjectProperty *
> > +object_class_property_add_qapi(ObjectClass *klass, const char *name,
> > +                               const QAPITypeInfo *qapi_type,
> > +                               ObjectPropertyAccessor *get,
> > +                               ObjectPropertyAccessor *set,
> > +                               ObjectPropertyRelease *release,
> > +                               void *opaque)
> > +{
> > +    ObjectProperty *prop;
> > +
> > +    prop = object_class_property_add(klass, name, qapi_type->name,
> > +                                     get, set, release, opaque);
> > +    prop->qapi_type = qapi_type;
> > +    return prop;
> > +}
> > +
> >  typedef struct TMProperty {
> >      void (*get)(Object *, struct tm *, Error **);
> >  } TMProperty;
>


Reply via email to