diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt index 52e3874efe9ed7165fc598155ffe57b699d9eabf..9903ac4c19769fd8fa6a936623b5cf540a07fbd6 100644 --- a/docs/devel/qapi-code-gen.txt +++ b/docs/devel/qapi-code-gen.txt @@ -282,6 +282,7 @@ The following types are predefined, and map to C as follows: size uint64_t like uint64_t, except StringInputVisitor accepts size suffixes bool bool JSON true or false + null QNull * JSON null any QObject * any JSON value QType QType JSON string matching enum QType values @@ -536,10 +537,11 @@ can only express a choice between types represented differently in JSON. If a branch is typed as the 'bool' built-in, the alternate accepts true and false; if it is typed as any of the various numeric built-ins, it accepts a JSON number; if it is typed as a 'str' -built-in or named enum type, it accepts a JSON string; and if it is -typed as a complex type (struct or union), it accepts a JSON object. -Two different complex types, for instance, aren't permitted, because -both are represented as a JSON object. +built-in or named enum type, it accepts a JSON string; if it is typed +as the 'null' built-in, it accepts JSON null; and if it is typed as a +complex type (struct or union), it accepts a JSON object. Two +different complex types, for instance, aren't permitted, because both +are represented as a JSON object. The example alternate declaration above allows using both of the following example objects: diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h index 3543b552f4764ea711c291c8ef9682f2afc23759..eab29edd12c4d901c89e30b2911ddcd62f7d4cfa 100644 --- a/include/qapi/qmp/qobject.h +++ b/include/qapi/qmp/qobject.h @@ -93,9 +93,9 @@ static inline QType qobject_type(const QObject *obj) return obj->type; } -typedef struct QNull { +struct QNull { QObject base; -} QNull; +}; extern QNull qnull_; diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 7b0d4e7e05dea214e015853f15e9a68a3db873bd..39bc8351a3bda36a6191e1cbe198f2d15f4fff77 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -89,6 +89,7 @@ typedef struct QEMUSGList QEMUSGList; typedef struct QEMUTimer QEMUTimer; typedef struct QEMUTimerListGroup QEMUTimerListGroup; typedef struct QObject QObject; +typedef struct QNull QNull; typedef struct RAMBlock RAMBlock; typedef struct Range Range; typedef struct SerialState SerialState; diff --git a/scripts/qapi.py b/scripts/qapi.py index 84e2eb441bdeca253107166d9088003ea27c351f..8aa2775f12ed4a89c5dddc661af8121e4ddbecd6 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -20,6 +20,7 @@ import sys from ordereddict import OrderedDict builtin_types = { + 'null': 'QTYPE_QNULL', 'str': 'QTYPE_QSTRING', 'int': 'QTYPE_QNUM', 'number': 'QTYPE_QNUM', @@ -1056,6 +1057,7 @@ class QAPISchemaType(QAPISchemaEntity): def alternate_qtype(self): json2qtype = { + 'null': 'QTYPE_QNULL', 'string': 'QTYPE_QSTRING', 'number': 'QTYPE_QNUM', 'int': 'QTYPE_QNUM', @@ -1515,7 +1517,8 @@ class QAPISchema(object): ('uint64', 'int', 'uint64_t'), ('size', 'int', 'uint64_t'), ('bool', 'boolean', 'bool'), - ('any', 'value', 'QObject' + pointer_suffix)]: + ('any', 'value', 'QObject' + pointer_suffix), + ('null', 'null', 'QNull' + pointer_suffix)]: self._def_builtin_type(*t) self.the_empty_object_type = QAPISchemaObjectType( 'q_empty', None, None, None, [], None) diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index 91ffb2648cb5114051007ae13b9bd1278ff1e5b6..c72dbd805092ebe008e932f20b956b5bc0fbdf4c 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -93,7 +93,8 @@ { 'struct': 'WrapAlternate', 'data': { 'alt': 'UserDefAlternate' } } { 'alternate': 'UserDefAlternate', - 'data': { 'udfu': 'UserDefFlatUnion', 'e': 'EnumOne', 'i': 'int' } } + 'data': { 'udfu': 'UserDefFlatUnion', 'e': 'EnumOne', 'i': 'int', + 'n': 'null' } } { 'struct': 'UserDefC', 'data': { 'string1': 'str', 'string2': 'str' } } diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index b88b8aae6f2592820597a0feb98eda10782f8d9b..3b1e9082d363e049ddc00aebd602c3b49eafd7eb 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -64,6 +64,7 @@ alternate UserDefAlternate case udfu: UserDefFlatUnion case e: EnumOne case i: int + case n: null object UserDefB member intb: int optional=False member a-b: bool optional=True diff --git a/tests/test-qobject-input-visitor.c b/tests/test-qobject-input-visitor.c index f98caf98181b4d9bb26991321b7932220aef3f2a..f4518441d3e4ff043bc80e479639dbbb59a65224 100644 --- a/tests/test-qobject-input-visitor.c +++ b/tests/test-qobject-input-visitor.c @@ -583,6 +583,11 @@ static void test_visitor_in_alternate(TestInputVisitorData *data, g_assert_cmpint(tmp->u.e, ==, ENUM_ONE_VALUE1); qapi_free_UserDefAlternate(tmp); + v = visitor_input_test_init(data, "null"); + visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort); + g_assert_cmpint(tmp->type, ==, QTYPE_QNULL); + qapi_free_UserDefAlternate(tmp); + v = visitor_input_test_init(data, "{'integer':1, 'string':'str', " "'enum1':'value1', 'boolean':true}"); visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort); diff --git a/tests/test-qobject-output-visitor.c b/tests/test-qobject-output-visitor.c index 8f1fcd49cbebff20ae240083d8efb8e84e56870e..7eb162059cc803d8a7ca6c2e3749751847a743fb 100644 --- a/tests/test-qobject-output-visitor.c +++ b/tests/test-qobject-output-visitor.c @@ -422,6 +422,16 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data, qapi_free_UserDefAlternate(tmp); + visitor_reset(data); + tmp = g_new0(UserDefAlternate, 1); + tmp->type = QTYPE_QNULL; + tmp->u.n = qnull(); + + visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort); + g_assert_cmpint(qobject_type(visitor_get(data)), ==, QTYPE_QNULL); + + qapi_free_UserDefAlternate(tmp); + visitor_reset(data); tmp = g_new0(UserDefAlternate, 1); tmp->type = QTYPE_QDICT;