qapi: Convert QType into QAPI built-in enum type

What's more meta than using qapi to define qapi? :)

Convert QType into a full-fledged[*] builtin qapi enum type, so
that a subsequent patch can then use it as the discriminator
type of qapi alternate types.  Fortunately, the judicious use of
'prefix' in the qapi definition avoids churn to the spelling of
the enum constants.

To avoid circular definitions, we have to flip the order of
inclusion between "qobject.h" vs. "qapi-types.h".  Back in commit
28770e0, we had the latter include the former, so that we could
use 'QObject *' for our implementation of 'any'.  But that usage
also works with only a forward declaration, whereas the
definition of QObject requires QType to be a complete type.

[*] The type has to be builtin, rather than declared in
qapi/common.json, because we want to use it for alternates even
when common.json is not included. But since it is the first
builtin enum type, we have to add special cases to qapi-types
and qapi-visit to only emit definitions once, even when two
qapi files are being compiled into the same binary (the way we
already handled builtin list types like 'intList').  We may
need to revisit how multiple qapi files share common types,
but that's a project for another day.

Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1449033659-25497-4-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
This commit is contained in:
Eric Blake 2015-12-01 22:20:47 -07:00 committed by Markus Armbruster
parent 1310a3d3bd
commit 7264f5c50c
20 changed files with 62 additions and 24 deletions

View File

@ -160,6 +160,7 @@ The following types are predefined, and map to C as follows:
accepts size suffixes
bool bool JSON true or false
any QObject * any JSON value
QType QType JSON string matching enum QType values
=== Includes ===

View File

@ -34,23 +34,12 @@
#include <stddef.h>
#include <assert.h>
#include "qapi-types.h"
typedef enum {
QTYPE_NONE, /* sentinel value, no QObject has this type code */
QTYPE_QNULL,
QTYPE_QINT,
QTYPE_QSTRING,
QTYPE_QDICT,
QTYPE_QLIST,
QTYPE_QFLOAT,
QTYPE_QBOOL,
QTYPE_MAX,
} QType;
typedef struct QObject {
struct QObject {
QType type;
size_t refcnt;
} QObject;
};
/* Get the 'base' part of an object */
#define QOBJECT(obj) (&(obj)->base)
@ -66,7 +55,7 @@ typedef struct QObject {
/* Initialize an object to default values */
static inline void qobject_init(QObject *obj, QType type)
{
assert(QTYPE_NONE < type && type < QTYPE_MAX);
assert(QTYPE_NONE < type && type < QTYPE__MAX);
obj->refcnt = 1;
obj->type = type;
}
@ -102,7 +91,7 @@ static inline void qobject_decref(QObject *obj)
*/
static inline QType qobject_type(const QObject *obj)
{
assert(QTYPE_NONE < obj->type && obj->type < QTYPE_MAX);
assert(QTYPE_NONE < obj->type && obj->type < QTYPE__MAX);
return obj->type;
}

View File

@ -80,6 +80,7 @@ typedef struct QEMUSGList QEMUSGList;
typedef struct QEMUSizedBuffer QEMUSizedBuffer;
typedef struct QEMUTimer QEMUTimer;
typedef struct QEMUTimerListGroup QEMUTimerListGroup;
typedef struct QObject QObject;
typedef struct RAMBlock RAMBlock;
typedef struct Range Range;
typedef struct SerialState SerialState;

View File

@ -15,7 +15,7 @@
#include "qapi/qmp/qlist.h"
#include "qapi/qmp/qstring.h"
static void (*qdestroy[QTYPE_MAX])(QObject *) = {
static void (*qdestroy[QTYPE__MAX])(QObject *) = {
[QTYPE_NONE] = NULL, /* No such object exists */
[QTYPE_QNULL] = NULL, /* qnull_ is indestructible */
[QTYPE_QINT] = qint_destroy_obj,
@ -29,6 +29,6 @@ static void (*qdestroy[QTYPE_MAX])(QObject *) = {
void qobject_destroy(QObject *obj)
{
assert(!obj->refcnt);
assert(QTYPE_QNULL < obj->type && obj->type < QTYPE_MAX);
assert(QTYPE_QNULL < obj->type && obj->type < QTYPE__MAX);
qdestroy[obj->type](obj);
}

View File

@ -112,7 +112,7 @@ def gen_alternate_qtypes_decl(name):
def gen_alternate_qtypes(name, variants):
ret = mcgen('''
const int %(c_name)s_qtypes[QTYPE_MAX] = {
const int %(c_name)s_qtypes[QTYPE__MAX] = {
''',
c_name=c_name(name))
@ -233,8 +233,15 @@ def _gen_type_cleanup(self, name):
self.defn += gen_type_cleanup(name)
def visit_enum_type(self, name, info, values, prefix):
self._fwdecl += gen_enum(name, values, prefix)
self._fwdefn += gen_enum_lookup(name, values, prefix)
# Special case for our lone builtin enum type
# TODO use something cleaner than existence of info
if not info:
self._btin += gen_enum(name, values, prefix)
if do_builtins:
self.defn += gen_enum_lookup(name, values, prefix)
else:
self._fwdecl += gen_enum(name, values, prefix)
self._fwdefn += gen_enum_lookup(name, values, prefix)
def visit_array_type(self, name, info, element_type):
if isinstance(element_type, QAPISchemaBuiltinType):
@ -316,10 +323,11 @@ def visit_alternate_type(self, name, info, variants):
''',
prefix=prefix))
# To avoid circular headers, use only typedefs.h here, not qobject.h
fdecl.write(mcgen('''
#include <stdbool.h>
#include <stdint.h>
#include "qapi/qmp/qobject.h"
#include "qemu/typedefs.h"
'''))
schema = QAPISchema(input_file)

View File

@ -347,8 +347,15 @@ def visit_needed(self, entity):
isinstance(entity, QAPISchemaObjectType))
def visit_enum_type(self, name, info, values, prefix):
self.decl += gen_visit_decl(name, scalar=True)
self.defn += gen_visit_enum(name)
# Special case for our lone builtin enum type
# TODO use something cleaner than existence of info
if not info:
self._btin += gen_visit_decl(name, scalar=True)
if do_builtins:
self.defn += gen_visit_enum(name)
else:
self.decl += gen_visit_decl(name, scalar=True)
self.defn += gen_visit_enum(name)
def visit_array_type(self, name, info, element_type):
decl = gen_visit_decl(name)

View File

@ -34,6 +34,7 @@
'uint64': 'QTYPE_QINT',
'size': 'QTYPE_QINT',
'any': None, # any QType possible, actually
'QType': 'QTYPE_QSTRING',
}
# Whitelist of commands allowed to return a non-dictionary
@ -1244,6 +1245,11 @@ def _def_predefineds(self):
self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
[], None)
self._def_entity(self.the_empty_object_type)
self._def_entity(QAPISchemaEnumType('QType', None,
['none', 'qnull', 'qint',
'qstring', 'qdict', 'qlist',
'qfloat', 'qbool'],
'QTYPE'))
def _make_implicit_enum_type(self, name, info, values):
name = name + 'Kind' # Use namespace reserved by add_name()

View File

@ -2,3 +2,5 @@ object :empty
alternate Alt
case i: int
enum AltKind ['i']
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
prefix QTYPE

View File

@ -1,2 +1,4 @@
object :empty
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
prefix QTYPE
enum Status ['good', 'bad', 'ugly']

View File

@ -1 +1,3 @@
object :empty
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
prefix QTYPE

View File

@ -1,2 +1,4 @@
object :empty
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
prefix QTYPE
event oops None

View File

@ -2,6 +2,8 @@ object :empty
object Base
member type: Empty optional=False
enum Empty []
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
prefix QTYPE
object Union
base Base
tag type

View File

@ -1,5 +1,7 @@
object :empty
object :obj-fooA-arg
member bar1: str optional=False
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
prefix QTYPE
command fooA :obj-fooA-arg -> None
gen=True success_response=True

View File

@ -1,2 +1,4 @@
object :empty
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
prefix QTYPE
enum Status ['good', 'bad', 'ugly']

View File

@ -1,2 +1,4 @@
object :empty
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
prefix QTYPE
enum Status ['good', 'bad', 'ugly']

View File

@ -1,2 +1,4 @@
object :empty
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
prefix QTYPE
enum Status ['good', 'bad', 'ugly']

View File

@ -1,4 +1,6 @@
object :empty
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
prefix QTYPE
command eins None -> None
gen=True success_response=True
command zwei None -> None

View File

@ -101,6 +101,8 @@ object NestedEnumsOne
member enum4: EnumOne optional=True
enum QEnumTwo ['value1', 'value2']
prefix QENUM_TWO
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
prefix QTYPE
object TestStruct
member integer: int optional=False
member boolean: bool optional=False

View File

@ -1,6 +1,8 @@
object :empty
object :obj-int-wrapper
member data: int optional=False
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
prefix QTYPE
object TestUnion
member type: TestUnionKind optional=False
case data: :obj-int-wrapper

View File

@ -1,4 +1,6 @@
object :empty
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
prefix QTYPE
object Union
member type: UnionKind optional=False
enum UnionKind []