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:
Daniel P. Berrange 2015-05-13 17:14:08 +01:00 committed by Andreas Färber
parent 2e4450ff43
commit a8e3fbedc8
3 changed files with 150 additions and 0 deletions

View file

@ -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();
}