qom: Add an object_property_add_enum() helper function
A QOM property can be parsed as enum using the visit_type_enum() helper function, but this forces callers to use the more complex generic object_property_add() method when registering it. It also requires that users of that object have access to the string map when they want to read the property value. This patch introduces a specialized object_property_add_enum() method which simplifies the use of enum properties, so the setters/getters directly get passed the int value. typedef enum { MYDEV_TYPE_FROG, MYDEV_TYPE_ALLIGATOR, MYDEV_TYPE_PLATYPUS, MYDEV_TYPE_LAST } MyDevType; Then provide a table of enum <-> string mappings static const char *const mydevtypemap[MYDEV_TYPE_LAST + 1] = { [MYDEV_TYPE_FROG] = "frog", [MYDEV_TYPE_ALLIGATOR] = "alligator", [MYDEV_TYPE_PLATYPUS] = "platypus", [MYDEV_TYPE_LAST] = NULL, }; Assuming an object struct of typedef struct { Object parent_obj; MyDevType devtype; ...other fields... } MyDev; The property can then be registered as follows: static int mydev_prop_get_devtype(Object *obj, Error **errp G_GNUC_UNUSED) { MyDev *dev = MYDEV(obj); return dev->devtype; } static void mydev_prop_set_devtype(Object *obj, int value, Error **errp G_GNUC_UNUSED) { MyDev *dev = MYDEV(obj); dev->devtype = value; } object_property_add_enum(obj, "devtype", mydevtypemap, "MyDevType", mydev_prop_get_devtype, mydev_prop_set_devtype, NULL); Note there is no need to check the range of 'value' in the setter, because the string->enum conversion code will have already done that and reported an error as required. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Signed-off-by: Andreas Färber <afaerber@suse.de>
This commit is contained in:
parent
2e4450ff43
commit
a8e3fbedc8
@ -1343,6 +1343,25 @@ void object_property_add_bool(Object *obj, const char *name,
|
||||
void (*set)(Object *, bool, Error **),
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* object_property_add_enum:
|
||||
* @obj: the object to add a property to
|
||||
* @name: the name of the property
|
||||
* @typename: the name of the enum data type
|
||||
* @get: the getter or %NULL if the property is write-only.
|
||||
* @set: the setter or %NULL if the property is read-only
|
||||
* @errp: if an error occurs, a pointer to an area to store the error
|
||||
*
|
||||
* Add an enum property using getters/setters. This function will add a
|
||||
* property of type '@typename'.
|
||||
*/
|
||||
void object_property_add_enum(Object *obj, const char *name,
|
||||
const char *typename,
|
||||
const char * const *strings,
|
||||
int (*get)(Object *, Error **),
|
||||
void (*set)(Object *, int, Error **),
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* object_property_add_tm:
|
||||
* @obj: the object to add a property to
|
||||
|
58
qom/object.c
58
qom/object.c
@ -1069,6 +1069,12 @@ int64_t object_property_get_int(Object *obj, const char *name,
|
||||
return retval;
|
||||
}
|
||||
|
||||
typedef struct EnumProperty {
|
||||
const char * const *strings;
|
||||
int (*get)(Object *, Error **);
|
||||
void (*set)(Object *, int, Error **);
|
||||
} EnumProperty;
|
||||
|
||||
int object_property_get_enum(Object *obj, const char *name,
|
||||
const char * const strings[], Error **errp)
|
||||
{
|
||||
@ -1673,6 +1679,58 @@ void object_property_add_bool(Object *obj, const char *name,
|
||||
}
|
||||
}
|
||||
|
||||
static void property_get_enum(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
EnumProperty *prop = opaque;
|
||||
int value;
|
||||
|
||||
value = prop->get(obj, errp);
|
||||
visit_type_enum(v, &value, prop->strings, NULL, name, errp);
|
||||
}
|
||||
|
||||
static void property_set_enum(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
EnumProperty *prop = opaque;
|
||||
int value;
|
||||
|
||||
visit_type_enum(v, &value, prop->strings, NULL, name, errp);
|
||||
prop->set(obj, value, errp);
|
||||
}
|
||||
|
||||
static void property_release_enum(Object *obj, const char *name,
|
||||
void *opaque)
|
||||
{
|
||||
EnumProperty *prop = opaque;
|
||||
g_free(prop);
|
||||
}
|
||||
|
||||
void object_property_add_enum(Object *obj, const char *name,
|
||||
const char *typename,
|
||||
const char * const *strings,
|
||||
int (*get)(Object *, Error **),
|
||||
void (*set)(Object *, int, Error **),
|
||||
Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
EnumProperty *prop = g_malloc(sizeof(*prop));
|
||||
|
||||
prop->strings = strings;
|
||||
prop->get = get;
|
||||
prop->set = set;
|
||||
|
||||
object_property_add(obj, name, typename,
|
||||
get ? property_get_enum : NULL,
|
||||
set ? property_set_enum : NULL,
|
||||
property_release_enum,
|
||||
prop, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
g_free(prop);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct TMProperty {
|
||||
void (*get)(Object *, struct tm *, Error **);
|
||||
} TMProperty;
|
||||
|
@ -32,10 +32,28 @@ typedef struct DummyObjectClass DummyObjectClass;
|
||||
#define DUMMY_OBJECT(obj) \
|
||||
OBJECT_CHECK(DummyObject, (obj), TYPE_DUMMY)
|
||||
|
||||
typedef enum DummyAnimal DummyAnimal;
|
||||
|
||||
enum DummyAnimal {
|
||||
DUMMY_FROG,
|
||||
DUMMY_ALLIGATOR,
|
||||
DUMMY_PLATYPUS,
|
||||
|
||||
DUMMY_LAST,
|
||||
};
|
||||
|
||||
static const char *const dummy_animal_map[DUMMY_LAST + 1] = {
|
||||
[DUMMY_FROG] = "frog",
|
||||
[DUMMY_ALLIGATOR] = "alligator",
|
||||
[DUMMY_PLATYPUS] = "platypus",
|
||||
[DUMMY_LAST] = NULL,
|
||||
};
|
||||
|
||||
struct DummyObject {
|
||||
Object parent_obj;
|
||||
|
||||
bool bv;
|
||||
DummyAnimal av;
|
||||
char *sv;
|
||||
};
|
||||
|
||||
@ -62,6 +80,24 @@ static bool dummy_get_bv(Object *obj,
|
||||
}
|
||||
|
||||
|
||||
static void dummy_set_av(Object *obj,
|
||||
int value,
|
||||
Error **errp)
|
||||
{
|
||||
DummyObject *dobj = DUMMY_OBJECT(obj);
|
||||
|
||||
dobj->av = value;
|
||||
}
|
||||
|
||||
static int dummy_get_av(Object *obj,
|
||||
Error **errp)
|
||||
{
|
||||
DummyObject *dobj = DUMMY_OBJECT(obj);
|
||||
|
||||
return dobj->av;
|
||||
}
|
||||
|
||||
|
||||
static void dummy_set_sv(Object *obj,
|
||||
const char *value,
|
||||
Error **errp)
|
||||
@ -91,6 +127,12 @@ static void dummy_init(Object *obj)
|
||||
dummy_get_sv,
|
||||
dummy_set_sv,
|
||||
NULL);
|
||||
object_property_add_enum(obj, "av",
|
||||
"DummyAnimal",
|
||||
dummy_animal_map,
|
||||
dummy_get_av,
|
||||
dummy_set_av,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void dummy_finalize(Object *obj)
|
||||
@ -121,11 +163,13 @@ static void test_dummy_createv(void)
|
||||
&err,
|
||||
"bv", "yes",
|
||||
"sv", "Hiss hiss hiss",
|
||||
"av", "platypus",
|
||||
NULL));
|
||||
|
||||
g_assert(err == NULL);
|
||||
g_assert_cmpstr(dobj->sv, ==, "Hiss hiss hiss");
|
||||
g_assert(dobj->bv == true);
|
||||
g_assert(dobj->av == DUMMY_PLATYPUS);
|
||||
|
||||
g_assert(object_resolve_path_component(parent, "dummy0")
|
||||
== OBJECT(dobj));
|
||||
@ -160,11 +204,13 @@ static void test_dummy_createlist(void)
|
||||
parent,
|
||||
"bv", "yes",
|
||||
"sv", "Hiss hiss hiss",
|
||||
"av", "platypus",
|
||||
NULL));
|
||||
|
||||
g_assert(err == NULL);
|
||||
g_assert_cmpstr(dobj->sv, ==, "Hiss hiss hiss");
|
||||
g_assert(dobj->bv == true);
|
||||
g_assert(dobj->av == DUMMY_PLATYPUS);
|
||||
|
||||
g_assert(object_resolve_path_component(parent, "dummy0")
|
||||
== OBJECT(dobj));
|
||||
@ -172,6 +218,32 @@ static void test_dummy_createlist(void)
|
||||
object_unparent(OBJECT(dobj));
|
||||
}
|
||||
|
||||
static void test_dummy_badenum(void)
|
||||
{
|
||||
Error *err = NULL;
|
||||
Object *parent = object_get_objects_root();
|
||||
Object *dobj =
|
||||
object_new_with_props(TYPE_DUMMY,
|
||||
parent,
|
||||
"dummy0",
|
||||
&err,
|
||||
"bv", "yes",
|
||||
"sv", "Hiss hiss hiss",
|
||||
"av", "yeti",
|
||||
NULL);
|
||||
|
||||
g_assert(dobj == NULL);
|
||||
g_assert(err != NULL);
|
||||
g_assert_cmpstr(error_get_pretty(err), ==,
|
||||
"Invalid parameter 'yeti'");
|
||||
|
||||
g_assert(object_resolve_path_component(parent, "dummy0")
|
||||
== NULL);
|
||||
|
||||
error_free(err);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
@ -181,6 +253,7 @@ int main(int argc, char **argv)
|
||||
|
||||
g_test_add_func("/qom/proplist/createlist", test_dummy_createlist);
|
||||
g_test_add_func("/qom/proplist/createv", test_dummy_createv);
|
||||
g_test_add_func("/qom/proplist/badenum", test_dummy_badenum);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user