[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v14 09/19] qapi: permit auto-creating single element
From: |
Daniel P. Berrange |
Subject: |
[Qemu-devel] [PATCH v14 09/19] qapi: permit auto-creating single element lists |
Date: |
Tue, 27 Sep 2016 14:13:11 +0100 |
When converting QemuOpts to a QObject, there is no information
about compound types available, so when visiting a list, the
corresponding QObject is not guaranteed to be a QList. We
therefore need to be able to auto-create a single element QList
from whatever type we find.
This mode should only be enabled if you have compatibility
requirements for
-arg foo=hello,foo=world
to be treated as equivalent to the preferred syntax:
-arg foo.0=hello,foo.1=world
Signed-off-by: Daniel P. Berrange <address@hidden>
---
include/qapi/qobject-input-visitor.h | 16 ++++++-
qapi/qobject-input-visitor.c | 23 ++++++++--
tests/test-qobject-input-visitor.c | 88 +++++++++++++++++++++++++++++++-----
3 files changed, 111 insertions(+), 16 deletions(-)
diff --git a/include/qapi/qobject-input-visitor.h
b/include/qapi/qobject-input-visitor.h
index 5022297..fb52457 100644
--- a/include/qapi/qobject-input-visitor.h
+++ b/include/qapi/qobject-input-visitor.h
@@ -42,6 +42,19 @@ Visitor *qobject_input_visitor_new(QObject *obj, bool
strict);
* represented as strings. i.e. if visiting a boolean, the value should
* be a QString whose contents represent a valid boolean.
*
+ * If @autocreate_list is true, then as an alternative to a normal QList,
+ * list values can be stored as a QString or QDict instead, which will
+ * be interpreted as representing single element lists. This should only
+ * by used if compatibility is required with the OptsVisitor which allowed
+ * repeated keys, without list indexes, to represent lists. e.g. set this
+ * to true if you have compatibility requirements for
+ *
+ * -arg foo=hello,foo=world
+ *
+ * to be treated as equivalent to the preferred syntax:
+ *
+ * -arg foo.0=hello,foo.1=world
+ *
* The visitor always operates in strict mode, requiring all dict keys
* to be consumed during visitation. An error will be reported if this
* does not happen.
@@ -49,6 +62,7 @@ Visitor *qobject_input_visitor_new(QObject *obj, bool strict);
* The returned input visitor should be released by calling
* visit_free() when no longer required.
*/
-Visitor *qobject_input_visitor_new_autocast(QObject *obj);
+Visitor *qobject_input_visitor_new_autocast(QObject *obj,
+ bool autocreate_list);
#endif
diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c
index cf41df6..e8afd1e 100644
--- a/qapi/qobject-input-visitor.c
+++ b/qapi/qobject-input-visitor.c
@@ -48,6 +48,10 @@ struct QObjectInputVisitor
/* True to reject parse in visit_end_struct() if unvisited keys remain. */
bool strict;
+
+ /* Whether we can auto-create single element lists when
+ * encountering a non-QList type */
+ bool autocreate_list;
};
static QObjectInputVisitor *to_qiv(Visitor *v)
@@ -108,6 +112,7 @@ static const QListEntry
*qobject_input_push(QObjectInputVisitor *qiv,
assert(obj);
tos->obj = obj;
tos->qapi = qapi;
+ qobject_incref(obj);
if (qiv->strict && qobject_type(obj) == QTYPE_QDICT) {
h = g_hash_table_new(g_str_hash, g_str_equal);
@@ -147,6 +152,7 @@ static void qobject_input_stack_object_free(StackObject
*tos)
if (tos->h) {
g_hash_table_unref(tos->h);
}
+ qobject_decref(tos->obj);
g_free(tos);
}
@@ -197,7 +203,7 @@ static void qobject_input_start_list(Visitor *v, const char
*name,
QObject *qobj = qobject_input_get_object(qiv, name, true);
const QListEntry *entry;
- if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
+ if (!qobj || (!qiv->autocreate_list && qobject_type(qobj) != QTYPE_QLIST))
{
if (list) {
*list = NULL;
}
@@ -206,7 +212,16 @@ static void qobject_input_start_list(Visitor *v, const
char *name,
return;
}
- entry = qobject_input_push(qiv, qobj, list, errp);
+ if (qobject_type(qobj) != QTYPE_QLIST) {
+ QList *tmplist = qlist_new();
+ qlist_append_obj(tmplist, qobj);
+ qobject_incref(qobj);
+ entry = qobject_input_push(qiv, QOBJECT(tmplist), list, errp);
+ QDECREF(tmplist);
+ } else {
+ entry = qobject_input_push(qiv, qobj, list, errp);
+ }
+
if (list) {
if (entry) {
*list = g_malloc0(size);
@@ -514,7 +529,8 @@ Visitor *qobject_input_visitor_new(QObject *obj, bool
strict)
return &v->visitor;
}
-Visitor *qobject_input_visitor_new_autocast(QObject *obj)
+Visitor *qobject_input_visitor_new_autocast(QObject *obj,
+ bool autocreate_list)
{
QObjectInputVisitor *v;
@@ -539,6 +555,7 @@ Visitor *qobject_input_visitor_new_autocast(QObject *obj)
v->visitor.optional = qobject_input_optional;
v->visitor.free = qobject_input_free;
v->strict = true;
+ v->autocreate_list = autocreate_list;
v->root = obj;
qobject_incref(obj);
diff --git a/tests/test-qobject-input-visitor.c
b/tests/test-qobject-input-visitor.c
index d5b8044..c227565 100644
--- a/tests/test-qobject-input-visitor.c
+++ b/tests/test-qobject-input-visitor.c
@@ -42,6 +42,7 @@ static void visitor_input_teardown(TestInputVisitorData *data,
functions (and not in main()). */
static Visitor *visitor_input_test_init_internal(TestInputVisitorData *data,
bool strict, bool autocast,
+ bool autocreate_list,
const char *json_string,
va_list *ap)
{
@@ -52,17 +53,20 @@ static Visitor
*visitor_input_test_init_internal(TestInputVisitorData *data,
if (autocast) {
assert(strict);
- data->qiv = qobject_input_visitor_new_autocast(data->obj);
+ data->qiv = qobject_input_visitor_new_autocast(data->obj,
+ autocreate_list);
} else {
+ assert(!autocreate_list);
data->qiv = qobject_input_visitor_new(data->obj, strict);
}
g_assert(data->qiv);
return data->qiv;
}
-static GCC_FMT_ATTR(4, 5)
+static GCC_FMT_ATTR(5, 6)
Visitor *visitor_input_test_init_full(TestInputVisitorData *data,
bool strict, bool autocast,
+ bool autocreate_list,
const char *json_string, ...)
{
Visitor *v;
@@ -70,6 +74,7 @@ Visitor *visitor_input_test_init_full(TestInputVisitorData
*data,
va_start(ap, json_string);
v = visitor_input_test_init_internal(data, strict, autocast,
+ autocreate_list,
json_string, &ap);
va_end(ap);
return v;
@@ -83,7 +88,7 @@ Visitor *visitor_input_test_init(TestInputVisitorData *data,
va_list ap;
va_start(ap, json_string);
- v = visitor_input_test_init_internal(data, true, false,
+ v = visitor_input_test_init_internal(data, true, false, false,
json_string, &ap);
va_end(ap);
return v;
@@ -99,7 +104,7 @@ Visitor *visitor_input_test_init(TestInputVisitorData *data,
static Visitor *visitor_input_test_init_raw(TestInputVisitorData *data,
const char *json_string)
{
- return visitor_input_test_init_internal(data, true, false,
+ return visitor_input_test_init_internal(data, true, false, false,
json_string, NULL);
}
@@ -139,7 +144,7 @@ static void
test_visitor_in_int_autocast(TestInputVisitorData *data,
Error *err = NULL;
Visitor *v;
- v = visitor_input_test_init_full(data, true, true,
+ v = visitor_input_test_init_full(data, true, true, false,
"%" PRId64, value);
visit_type_int(v, NULL, &res, &err);
error_free_or_abort(&err);
@@ -151,7 +156,7 @@ static void
test_visitor_in_int_str_autocast(TestInputVisitorData *data,
int64_t res = 0, value = -42;
Visitor *v;
- v = visitor_input_test_init_full(data, true, true,
+ v = visitor_input_test_init_full(data, true, true, false,
"\"-42\"");
visit_type_int(v, NULL, &res, &error_abort);
@@ -190,7 +195,7 @@ static void
test_visitor_in_bool_autocast(TestInputVisitorData *data,
Error *err = NULL;
Visitor *v;
- v = visitor_input_test_init_full(data, true, true, "true");
+ v = visitor_input_test_init_full(data, true, true, false, "true");
visit_type_bool(v, NULL, &res, &err);
error_free_or_abort(&err);
@@ -202,7 +207,7 @@ static void
test_visitor_in_bool_str_autocast(TestInputVisitorData *data,
bool res = false;
Visitor *v;
- v = visitor_input_test_init_full(data, true, true, "\"yes\"");
+ v = visitor_input_test_init_full(data, true, true, false, "\"yes\"");
visit_type_bool(v, NULL, &res, &error_abort);
g_assert_cmpint(res, ==, true);
@@ -240,7 +245,7 @@ static void
test_visitor_in_number_autocast(TestInputVisitorData *data,
Error *err = NULL;
Visitor *v;
- v = visitor_input_test_init_full(data, true, true, "%f", value);
+ v = visitor_input_test_init_full(data, true, true, false, "%f", value);
visit_type_number(v, NULL, &res, &err);
error_free_or_abort(&err);
@@ -252,7 +257,7 @@ static void
test_visitor_in_number_str_autocast(TestInputVisitorData *data,
double res = 0, value = 3.14;
Visitor *v;
- v = visitor_input_test_init_full(data, true, true, "\"3.14\"");
+ v = visitor_input_test_init_full(data, true, true, false, "\"3.14\"");
visit_type_number(v, NULL, &res, &error_abort);
g_assert_cmpfloat(res, ==, value);
@@ -277,7 +282,7 @@ static void
test_visitor_in_size_str_autocast(TestInputVisitorData *data,
uint64_t res, value = 500 * 1024 * 1024;
Visitor *v;
- v = visitor_input_test_init_full(data, true, true, "\"500M\"");
+ v = visitor_input_test_init_full(data, true, true, false, "\"500M\"");
visit_type_size(v, NULL, &res, &error_abort);
g_assert_cmpfloat(res, ==, value);
@@ -396,6 +401,59 @@ static void test_visitor_in_list(TestInputVisitorData
*data,
g_assert(!head);
}
+static void test_visitor_in_list_autocreate_none(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefOneList *head = NULL;
+ Visitor *v;
+ Error *err = NULL;
+
+ v = visitor_input_test_init_full(data, true, true, false,
+ "{ 'string': 'string0', 'integer': 42 }");
+
+ visit_type_UserDefOneList(v, NULL, &head, &err);
+ error_free_or_abort(&err);
+ g_assert(head == NULL);
+}
+
+static void test_visitor_in_list_autocreate_dict(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefOneList *head = NULL;
+ Visitor *v;
+
+ v = visitor_input_test_init_full(data, true, true, true,
+ "{ 'string': 'string0', 'integer': '42'
}");
+
+ visit_type_UserDefOneList(v, NULL, &head, &error_abort);
+ g_assert(head != NULL);
+
+ g_assert_cmpstr(head->value->string, ==, "string0");
+ g_assert_cmpint(head->value->integer, ==, 42);
+ g_assert(head->next == NULL);
+
+ qapi_free_UserDefOneList(head);
+ head = NULL;
+}
+
+static void test_visitor_in_list_autocreate_int(TestInputVisitorData *data,
+ const void *unused)
+{
+ uint32List *head = NULL;
+ Visitor *v;
+
+ /* Verify that we auto-create a single element list from the int */
+ v = visitor_input_test_init_full(data, true, true, true, "'42'");
+
+ visit_type_uint32List(v, NULL, &head, &error_abort);
+ g_assert(head != NULL);
+
+ g_assert_cmpint(head->value, ==, 42);
+
+ qapi_free_uint32List(head);
+ head = NULL;
+}
+
static void test_visitor_in_any(TestInputVisitorData *data,
const void *unused)
{
@@ -452,7 +510,7 @@ static void test_visitor_in_null(TestInputVisitorData *data,
* when input is not null.
*/
- v = visitor_input_test_init_full(data, false, false,
+ v = visitor_input_test_init_full(data, false, false, false,
"{ 'a': null, 'b': '' }");
visit_start_struct(v, NULL, NULL, 0, &error_abort);
visit_type_null(v, "a", &error_abort);
@@ -1040,6 +1098,12 @@ int main(int argc, char **argv)
NULL, test_visitor_in_struct_nested);
input_visitor_test_add("/visitor/input/list",
NULL, test_visitor_in_list);
+ input_visitor_test_add("/visitor/input/list-autocreate-noautocast",
+ NULL, test_visitor_in_list_autocreate_none);
+ input_visitor_test_add("/visitor/input/list-autocreate-autocast",
+ NULL, test_visitor_in_list_autocreate_dict);
+ input_visitor_test_add("/visitor/input/list-autocreate-int",
+ NULL, test_visitor_in_list_autocreate_int);
input_visitor_test_add("/visitor/input/any",
NULL, test_visitor_in_any);
input_visitor_test_add("/visitor/input/null",
--
2.7.4
- Re: [Qemu-devel] [PATCH v14 03/19] option: allow qemu_opts_to_qdict to merge repeated options, (continued)
- [Qemu-devel] [PATCH v14 09/19] qapi: permit auto-creating single element lists,
Daniel P. Berrange <=
- [Qemu-devel] [PATCH v14 08/19] qapi: permit scalar type conversions in QObjectInputVisitor, Daniel P. Berrange, 2016/09/27
- [Qemu-devel] [PATCH v14 05/19] qapi: rename QmpInputVisitor to QObjectInputVisitor, Daniel P. Berrange, 2016/09/27
- [Qemu-devel] [PATCH v14 10/19] qapi: permit auto-creating nested structs, Daniel P. Berrange, 2016/09/27
- [Qemu-devel] [PATCH v14 06/19] qapi: rename QmpOutputVisitor to QObjectOutputVisitor, Daniel P. Berrange, 2016/09/27
- [Qemu-devel] [PATCH v14 11/19] qapi: add integer range support for QObjectInputVisitor, Daniel P. Berrange, 2016/09/27
- [Qemu-devel] [PATCH v14 14/19] hmp: support non-scalar properties with object_add, Daniel P. Berrange, 2016/09/27
- [Qemu-devel] [PATCH v14 13/19] qom: support non-scalar properties with -object, Daniel P. Berrange, 2016/09/27
- [Qemu-devel] [PATCH v14 12/19] qapi: allow QObjectInputVisitor to be created with QemuOpts, Daniel P. Berrange, 2016/09/27
- [Qemu-devel] [PATCH v14 16/19] block: convert crypto driver to use QObjectInputVisitor, Daniel P. Berrange, 2016/09/27
- [Qemu-devel] [PATCH v14 17/19] acpi: convert to QObjectInputVisitor for -acpi parsing, Daniel P. Berrange, 2016/09/27