From: "Daniel P. Berrange" <berrange@redhat.com>
To: qemu-devel@nongnu.org
Cc: "Paolo Bonzini" <pbonzini@redhat.com>,
"Andreas Färber" <afaerber@suse.de>
Subject: [Qemu-devel] [PATCH v3 6/7] qom: add a object_property_add_enum helper method
Date: Fri, 1 May 2015 11:30:05 +0100 [thread overview]
Message-ID: <1430476206-26034-7-git-send-email-berrange@redhat.com> (raw)
In-Reply-To: <1430476206-26034-1-git-send-email-berrange@redhat.com>
A QOM property can be parsed as enum using the visit_type_enum()
helper method, 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;
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->endpoint = 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>
---
include/qom/object.h | 19 ++++++++++++
qom/object.c | 58 ++++++++++++++++++++++++++++++++++++
tests/check-qom-proplist.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 151 insertions(+)
diff --git a/include/qom/object.h b/include/qom/object.h
index bf76f7a..f6a2a9d 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -1271,6 +1271,25 @@ void object_property_add_bool(Object *obj, const char *name,
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 a enum property using getters/setters. This function will add a
+ * property of type 'enum'.
+ */
+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
* @name: the name of the property
diff --git a/qom/object.c b/qom/object.c
index 077a5fe..ba0e4b8 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -1609,6 +1609,64 @@ void object_property_add_bool(Object *obj, const char *name,
}
}
+typedef struct EnumProperty {
+ const char * const *strings;
+ int (*get)(Object *, Error **);
+ void (*set)(Object *, int, Error **);
+} EnumProperty;
+
+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_malloc0(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;
diff --git a/tests/check-qom-proplist.c b/tests/check-qom-proplist.c
index 9f16cdb..de142e3 100644
--- a/tests/check-qom-proplist.c
+++ b/tests/check-qom-proplist.c
@@ -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 dummyanimalmap[DUMMY_LAST + 1] = {
+ [DUMMY_FROG] = "frog",
+ [DUMMY_ALLIGATOR] = "alligator",
+ [DUMMY_PLATYPUS] = "platypus",
+ [DUMMY_LAST] = NULL,
+};
+
struct DummyObject {
Object parent;
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",
+ dummyanimalmap,
+ dummy_get_av,
+ dummy_set_av,
+ NULL);
}
static void dummy_finalize(Object *obj)
@@ -122,12 +164,14 @@ static void test_dummy_createv(void)
&err,
"bv", "yes",
"sv", "Hiss hiss hiss",
+ "av", "platypus",
NULL));
g_assert(dobj != NULL);
g_assert(err == NULL);
g_assert(g_str_equal(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));
@@ -163,12 +207,14 @@ static void test_dummy_createlist(void)
parent,
"bv", "yes",
"sv", "Hiss hiss hiss",
+ "av", "platypus",
NULL));
g_assert(dobj != NULL);
g_assert(err == NULL);
g_assert(g_str_equal(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));
@@ -176,6 +222,33 @@ static void test_dummy_createlist(void)
object_unparent(OBJECT(dobj));
}
+static void test_dummy_badenum(void)
+{
+ Error *err = NULL;
+ Object *parent = container_get(object_get_root(),
+ "/objects");
+ DummyObject *dobj = DUMMY_OBJECT(
+ object_new_propv(TYPE_DUMMY,
+ parent,
+ "dummy0",
+ &err,
+ "bv", "yes",
+ "sv", "Hiss hiss hiss",
+ "av", "yeti",
+ NULL));
+
+ g_assert(dobj == NULL);
+ g_assert(err != NULL);
+ g_assert(g_str_equal(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);
@@ -185,6 +258,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();
}
--
2.1.0
next prev parent reply other threads:[~2015-05-01 10:30 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-05-01 10:29 [Qemu-devel] [PATCH v3 0/7] qom: misc fixes & enhancements to support TLS work Daniel P. Berrange
2015-05-01 10:30 ` [Qemu-devel] [PATCH v3 1/7] qom: fix typename of 'policy' enum property in hostmem obj Daniel P. Berrange
2015-05-08 14:28 ` Andreas Färber
2015-05-01 10:30 ` [Qemu-devel] [PATCH v3 2/7] qom: document user creatable object types in help text Daniel P. Berrange
2015-05-08 14:31 ` Andreas Färber
2015-05-01 10:30 ` [Qemu-devel] [PATCH v3 3/7] qom: create objects in two phases Daniel P. Berrange
2015-05-08 14:37 ` Andreas Färber
2015-05-08 14:40 ` Paolo Bonzini
2015-05-12 16:55 ` Daniel P. Berrange
2015-05-01 10:30 ` [Qemu-devel] [PATCH v3 4/7] qom: add object_new_propv / object_new_proplist constructors Daniel P. Berrange
2015-05-08 17:10 ` Andreas Färber
2015-05-08 17:18 ` Paolo Bonzini
2015-05-08 17:22 ` Andreas Färber
2015-05-08 20:16 ` Eric Blake
2015-05-12 16:49 ` Daniel P. Berrange
2015-05-01 10:30 ` [Qemu-devel] [PATCH v3 5/7] qom: make enum string tables const-correct Daniel P. Berrange
2015-05-08 17:19 ` Andreas Färber
2015-05-01 10:30 ` Daniel P. Berrange [this message]
2015-05-08 17:45 ` [Qemu-devel] [PATCH v3 6/7] qom: add a object_property_add_enum helper method Andreas Färber
2015-05-12 16:53 ` Daniel P. Berrange
2015-05-01 10:30 ` [Qemu-devel] [PATCH v3 7/7] qom: don't pass string table to object_get_enum method Daniel P. Berrange
2015-05-08 17:54 ` Andreas Färber
2015-05-12 16:54 ` Daniel P. Berrange
2015-05-05 10:33 ` [Qemu-devel] [PATCH v3 0/7] qom: misc fixes & enhancements to support TLS work Paolo Bonzini
2015-05-05 15:37 ` Andreas Färber
2015-05-08 12:31 ` Paolo Bonzini
2015-05-08 12:34 ` Andreas Färber
2015-05-08 14:20 ` Paolo Bonzini
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1430476206-26034-7-git-send-email-berrange@redhat.com \
--to=berrange@redhat.com \
--cc=afaerber@suse.de \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.