Revision 69dd62df
b/docs/qapi-code-gen.txt | ||
---|---|---|
125 | 125 |
"lazy-refcounts": true } |
126 | 126 |
|
127 | 127 |
|
128 |
A special type of unions are anonymous unions. They don't form a dictionary in |
|
129 |
the wire format but allow the direct use of different types in their place. As |
|
130 |
they aren't structured, they don't have any explicit discriminator but use |
|
131 |
the (QObject) data type of their value as an implicit discriminator. This means |
|
132 |
that they are restricted to using only one discriminator value per QObject |
|
133 |
type. For example, you cannot have two different complex types in an anonymous |
|
134 |
union, or two different integer types. |
|
135 |
|
|
136 |
Anonymous unions are declared using an empty dictionary as their discriminator. |
|
137 |
The discriminator values never appear on the wire, they are only used in the |
|
138 |
generated C code. Anonymous unions cannot have a base type. |
|
139 |
|
|
140 |
{ 'union': 'BlockRef', |
|
141 |
'discriminator': {}, |
|
142 |
'data': { 'definition': 'BlockdevOptions', |
|
143 |
'reference': 'str' } } |
|
144 |
|
|
145 |
This example allows using both of the following example objects: |
|
146 |
|
|
147 |
{ "file": "my_existing_block_device_id" } |
|
148 |
{ "file": { "driver": "file", |
|
149 |
"readonly": false, |
|
150 |
'filename': "/tmp/mydisk.qcow2" } } |
|
151 |
|
|
152 |
|
|
128 | 153 |
=== Commands === |
129 | 154 |
|
130 | 155 |
Commands are defined by using a list containing three members. The first |
b/include/qapi/qmp/qobject.h | ||
---|---|---|
44 | 44 |
QTYPE_QFLOAT, |
45 | 45 |
QTYPE_QBOOL, |
46 | 46 |
QTYPE_QERROR, |
47 |
QTYPE_MAX, |
|
47 | 48 |
} qtype_code; |
48 | 49 |
|
49 | 50 |
struct QObject; |
b/include/qapi/visitor-impl.h | ||
---|---|---|
32 | 32 |
|
33 | 33 |
void (*type_enum)(Visitor *v, int *obj, const char *strings[], |
34 | 34 |
const char *kind, const char *name, Error **errp); |
35 |
void (*get_next_type)(Visitor *v, int *kind, const int *qobjects, |
|
36 |
const char *name, Error **errp); |
|
35 | 37 |
|
36 | 38 |
void (*type_int)(Visitor *v, int64_t *obj, const char *name, Error **errp); |
37 | 39 |
void (*type_bool)(Visitor *v, bool *obj, const char *name, Error **errp); |
b/include/qapi/visitor.h | ||
---|---|---|
13 | 13 |
#ifndef QAPI_VISITOR_CORE_H |
14 | 14 |
#define QAPI_VISITOR_CORE_H |
15 | 15 |
|
16 |
#include "qapi/qmp/qobject.h" |
|
16 | 17 |
#include "qapi/error.h" |
17 | 18 |
#include <stdlib.h> |
18 | 19 |
|
... | ... | |
42 | 43 |
void visit_start_optional(Visitor *v, bool *present, const char *name, |
43 | 44 |
Error **errp); |
44 | 45 |
void visit_end_optional(Visitor *v, Error **errp); |
46 |
void visit_get_next_type(Visitor *v, int *obj, const int *qtypes, |
|
47 |
const char *name, Error **errp); |
|
45 | 48 |
void visit_type_enum(Visitor *v, int *obj, const char *strings[], |
46 | 49 |
const char *kind, const char *name, Error **errp); |
47 | 50 |
void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp); |
b/qapi/qapi-visit-core.c | ||
---|---|---|
12 | 12 |
*/ |
13 | 13 |
|
14 | 14 |
#include "qemu-common.h" |
15 |
#include "qapi/qmp/qobject.h" |
|
15 | 16 |
#include "qapi/qmp/qerror.h" |
16 | 17 |
#include "qapi/visitor.h" |
17 | 18 |
#include "qapi/visitor-impl.h" |
... | ... | |
98 | 99 |
} |
99 | 100 |
} |
100 | 101 |
|
102 |
void visit_get_next_type(Visitor *v, int *obj, const int *qtypes, |
|
103 |
const char *name, Error **errp) |
|
104 |
{ |
|
105 |
if (!error_is_set(errp) && v->get_next_type) { |
|
106 |
v->get_next_type(v, obj, qtypes, name, errp); |
|
107 |
} |
|
108 |
} |
|
109 |
|
|
101 | 110 |
void visit_type_enum(Visitor *v, int *obj, const char *strings[], |
102 | 111 |
const char *kind, const char *name, Error **errp) |
103 | 112 |
{ |
b/qapi/qmp-input-visitor.c | ||
---|---|---|
208 | 208 |
qmp_input_pop(qiv, errp); |
209 | 209 |
} |
210 | 210 |
|
211 |
static void qmp_input_get_next_type(Visitor *v, int *kind, const int *qobjects, |
|
212 |
const char *name, Error **errp) |
|
213 |
{ |
|
214 |
QmpInputVisitor *qiv = to_qiv(v); |
|
215 |
QObject *qobj = qmp_input_get_object(qiv, name, false); |
|
216 |
|
|
217 |
if (!qobj) { |
|
218 |
error_set(errp, QERR_MISSING_PARAMETER, name ? name : "null"); |
|
219 |
return; |
|
220 |
} |
|
221 |
*kind = qobjects[qobject_type(qobj)]; |
|
222 |
} |
|
223 |
|
|
211 | 224 |
static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name, |
212 | 225 |
Error **errp) |
213 | 226 |
{ |
... | ... | |
317 | 330 |
v->visitor.type_str = qmp_input_type_str; |
318 | 331 |
v->visitor.type_number = qmp_input_type_number; |
319 | 332 |
v->visitor.start_optional = qmp_input_start_optional; |
333 |
v->visitor.get_next_type = qmp_input_get_next_type; |
|
320 | 334 |
|
321 | 335 |
qmp_input_push(v, obj, NULL); |
322 | 336 |
qobject_incref(obj); |
b/qobject/qjson.c | ||
---|---|---|
260 | 260 |
/* XXX: should QError be emitted? */ |
261 | 261 |
case QTYPE_NONE: |
262 | 262 |
break; |
263 |
case QTYPE_MAX: |
|
264 |
abort(); |
|
263 | 265 |
} |
264 | 266 |
} |
265 | 267 |
|
b/scripts/qapi-types.py | ||
---|---|---|
150 | 150 |
|
151 | 151 |
return lookup_decl + enum_decl |
152 | 152 |
|
153 |
def generate_anon_union_qtypes(expr): |
|
154 |
|
|
155 |
name = expr['union'] |
|
156 |
members = expr['data'] |
|
157 |
|
|
158 |
ret = mcgen(''' |
|
159 |
const int %(name)s_qtypes[QTYPE_MAX] = { |
|
160 |
''', |
|
161 |
name=name) |
|
162 |
|
|
163 |
for key in members: |
|
164 |
qapi_type = members[key] |
|
165 |
if builtin_type_qtypes.has_key(qapi_type): |
|
166 |
qtype = builtin_type_qtypes[qapi_type] |
|
167 |
elif find_struct(qapi_type): |
|
168 |
qtype = "QTYPE_QDICT" |
|
169 |
elif find_union(qapi_type): |
|
170 |
qtype = "QTYPE_QDICT" |
|
171 |
else: |
|
172 |
assert False, "Invalid anonymous union member" |
|
173 |
|
|
174 |
ret += mcgen(''' |
|
175 |
[ %(qtype)s ] = %(abbrev)s_KIND_%(enum)s, |
|
176 |
''', |
|
177 |
qtype = qtype, |
|
178 |
abbrev = de_camel_case(name).upper(), |
|
179 |
enum = c_fun(de_camel_case(key),False).upper()) |
|
180 |
|
|
181 |
ret += mcgen(''' |
|
182 |
}; |
|
183 |
''') |
|
184 |
return ret |
|
185 |
|
|
186 |
|
|
153 | 187 |
def generate_union(expr): |
154 | 188 |
|
155 | 189 |
name = expr['union'] |
... | ... | |
190 | 224 |
ret += mcgen(''' |
191 | 225 |
}; |
192 | 226 |
''') |
227 |
if discriminator == {}: |
|
228 |
ret += mcgen(''' |
|
229 |
extern const int %(name)s_qtypes[]; |
|
230 |
''', |
|
231 |
name=name) |
|
232 |
|
|
193 | 233 |
|
194 | 234 |
return ret |
195 | 235 |
|
... | ... | |
342 | 382 |
ret += generate_fwd_struct(expr['union'], expr['data']) + "\n" |
343 | 383 |
ret += generate_enum('%sKind' % expr['union'], expr['data'].keys()) |
344 | 384 |
fdef.write(generate_enum_lookup('%sKind' % expr['union'], expr['data'].keys())) |
385 |
if expr.get('discriminator') == {}: |
|
386 |
fdef.write(generate_anon_union_qtypes(expr)) |
|
345 | 387 |
else: |
346 | 388 |
continue |
347 | 389 |
fdecl.write(ret) |
b/scripts/qapi-visit.py | ||
---|---|---|
176 | 176 |
''', |
177 | 177 |
name=name) |
178 | 178 |
|
179 |
def generate_visit_anon_union(name, members): |
|
180 |
ret = mcgen(''' |
|
181 |
|
|
182 |
void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp) |
|
183 |
{ |
|
184 |
Error *err = NULL; |
|
185 |
|
|
186 |
if (!error_is_set(errp)) { |
|
187 |
visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err); |
|
188 |
visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err); |
|
189 |
switch ((*obj)->kind) { |
|
190 |
''', |
|
191 |
name=name) |
|
192 |
|
|
193 |
for key in members: |
|
194 |
assert (members[key] in builtin_types |
|
195 |
or find_struct(members[key]) |
|
196 |
or find_union(members[key])), "Invalid anonymous union member" |
|
197 |
|
|
198 |
ret += mcgen(''' |
|
199 |
case %(abbrev)s_KIND_%(enum)s: |
|
200 |
visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err); |
|
201 |
break; |
|
202 |
''', |
|
203 |
abbrev = de_camel_case(name).upper(), |
|
204 |
enum = c_fun(de_camel_case(key),False).upper(), |
|
205 |
c_type = type_name(members[key]), |
|
206 |
c_name = c_fun(key)) |
|
207 |
|
|
208 |
ret += mcgen(''' |
|
209 |
default: |
|
210 |
abort(); |
|
211 |
} |
|
212 |
error_propagate(errp, err); |
|
213 |
err = NULL; |
|
214 |
visit_end_implicit_struct(m, &err); |
|
215 |
} |
|
216 |
} |
|
217 |
''') |
|
218 |
|
|
219 |
return ret |
|
220 |
|
|
221 |
|
|
179 | 222 |
def generate_visit_union(expr): |
180 | 223 |
|
181 | 224 |
name = expr['union'] |
... | ... | |
184 | 227 |
base = expr.get('base') |
185 | 228 |
discriminator = expr.get('discriminator') |
186 | 229 |
|
230 |
if discriminator == {}: |
|
231 |
assert not base |
|
232 |
return generate_visit_anon_union(name, members) |
|
233 |
|
|
187 | 234 |
ret = generate_visit_enum('%sKind' % name, members.keys()) |
188 | 235 |
|
189 | 236 |
if base: |
b/scripts/qapi.py | ||
---|---|---|
17 | 17 |
'uint8', 'uint16', 'uint32', 'uint64' |
18 | 18 |
] |
19 | 19 |
|
20 |
builtin_type_qtypes = { |
|
21 |
'str': 'QTYPE_QSTRING', |
|
22 |
'int': 'QTYPE_QINT', |
|
23 |
'number': 'QTYPE_QFLOAT', |
|
24 |
'bool': 'QTYPE_QBOOL', |
|
25 |
'int8': 'QTYPE_QINT', |
|
26 |
'int16': 'QTYPE_QINT', |
|
27 |
'int32': 'QTYPE_QINT', |
|
28 |
'int64': 'QTYPE_QINT', |
|
29 |
'uint8': 'QTYPE_QINT', |
|
30 |
'uint16': 'QTYPE_QINT', |
|
31 |
'uint32': 'QTYPE_QINT', |
|
32 |
'uint64': 'QTYPE_QINT', |
|
33 |
} |
|
34 |
|
|
20 | 35 |
def tokenize(data): |
21 | 36 |
while len(data): |
22 | 37 |
ch = data[0] |
Also available in: Unified diff