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