xref: /qemu/qapi/qapi-visit-core.c (revision a15fcc3cf69ee3d408f60d6cc316488d2b0249b4)
12345c77cSMichael Roth /*
22345c77cSMichael Roth  * Core Definitions for QAPI Visitor Classes
32345c77cSMichael Roth  *
47c91aabdSEric Blake  * Copyright (C) 2012-2016 Red Hat, Inc.
52345c77cSMichael Roth  * Copyright IBM, Corp. 2011
62345c77cSMichael Roth  *
72345c77cSMichael Roth  * Authors:
82345c77cSMichael Roth  *  Anthony Liguori   <aliguori@us.ibm.com>
92345c77cSMichael Roth  *
102345c77cSMichael Roth  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
112345c77cSMichael Roth  * See the COPYING.LIB file in the top-level directory.
122345c77cSMichael Roth  *
132345c77cSMichael Roth  */
142345c77cSMichael Roth 
15cbf21151SPeter Maydell #include "qemu/osdep.h"
16da34e65cSMarkus Armbruster #include "qapi/error.h"
1779ee7df8SPaolo Bonzini #include "qemu-common.h"
1869dd62dfSKevin Wolf #include "qapi/qmp/qobject.h"
197b1b5d19SPaolo Bonzini #include "qapi/qmp/qerror.h"
207b1b5d19SPaolo Bonzini #include "qapi/visitor.h"
217b1b5d19SPaolo Bonzini #include "qapi/visitor-impl.h"
222345c77cSMichael Roth 
233b098d56SEric Blake void visit_complete(Visitor *v, void *opaque)
243b098d56SEric Blake {
253b098d56SEric Blake     assert(v->type != VISITOR_OUTPUT || v->complete);
263b098d56SEric Blake     if (v->complete) {
273b098d56SEric Blake         v->complete(v, opaque);
283b098d56SEric Blake     }
293b098d56SEric Blake }
303b098d56SEric Blake 
312c0ef9f4SEric Blake void visit_free(Visitor *v)
322c0ef9f4SEric Blake {
332c0ef9f4SEric Blake     if (v) {
342c0ef9f4SEric Blake         v->free(v);
352c0ef9f4SEric Blake     }
362c0ef9f4SEric Blake }
372c0ef9f4SEric Blake 
3851e72bc1SEric Blake void visit_start_struct(Visitor *v, const char *name, void **obj,
39337283dfSEric Blake                         size_t size, Error **errp)
402345c77cSMichael Roth {
41e58d695eSEric Blake     Error *err = NULL;
42e58d695eSEric Blake 
43adfb264cSEric Blake     if (obj) {
44adfb264cSEric Blake         assert(size);
45*a15fcc3cSEric Blake         assert(!(v->type & VISITOR_OUTPUT) || *obj);
46adfb264cSEric Blake     }
47e58d695eSEric Blake     v->start_struct(v, name, obj, size, &err);
48*a15fcc3cSEric Blake     if (obj && (v->type & VISITOR_INPUT)) {
49e58d695eSEric Blake         assert(!err != !*obj);
50e58d695eSEric Blake     }
51e58d695eSEric Blake     error_propagate(errp, err);
522345c77cSMichael Roth }
532345c77cSMichael Roth 
5415c2f669SEric Blake void visit_check_struct(Visitor *v, Error **errp)
552345c77cSMichael Roth {
5615c2f669SEric Blake     if (v->check_struct) {
5715c2f669SEric Blake         v->check_struct(v, errp);
5815c2f669SEric Blake     }
5915c2f669SEric Blake }
6015c2f669SEric Blake 
611158bb2aSEric Blake void visit_end_struct(Visitor *v, void **obj)
6215c2f669SEric Blake {
631158bb2aSEric Blake     v->end_struct(v, obj);
642345c77cSMichael Roth }
652345c77cSMichael Roth 
66d9f62ddeSEric Blake void visit_start_list(Visitor *v, const char *name, GenericList **list,
67d9f62ddeSEric Blake                       size_t size, Error **errp)
682345c77cSMichael Roth {
69d9f62ddeSEric Blake     Error *err = NULL;
70d9f62ddeSEric Blake 
71d9f62ddeSEric Blake     assert(!list || size >= sizeof(GenericList));
72d9f62ddeSEric Blake     v->start_list(v, name, list, size, &err);
73*a15fcc3cSEric Blake     if (list && (v->type & VISITOR_INPUT)) {
74d9f62ddeSEric Blake         assert(!(err && *list));
75d9f62ddeSEric Blake     }
76d9f62ddeSEric Blake     error_propagate(errp, err);
772345c77cSMichael Roth }
782345c77cSMichael Roth 
79d9f62ddeSEric Blake GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size)
802345c77cSMichael Roth {
81d9f62ddeSEric Blake     assert(tail && size >= sizeof(GenericList));
82d9f62ddeSEric Blake     return v->next_list(v, tail, size);
832345c77cSMichael Roth }
842345c77cSMichael Roth 
851158bb2aSEric Blake void visit_end_list(Visitor *v, void **obj)
862345c77cSMichael Roth {
871158bb2aSEric Blake     v->end_list(v, obj);
882345c77cSMichael Roth }
892345c77cSMichael Roth 
90dbf11922SEric Blake void visit_start_alternate(Visitor *v, const char *name,
91dbf11922SEric Blake                            GenericAlternate **obj, size_t size,
92dbf11922SEric Blake                            bool promote_int, Error **errp)
93dbf11922SEric Blake {
94e58d695eSEric Blake     Error *err = NULL;
95e58d695eSEric Blake 
96dbf11922SEric Blake     assert(obj && size >= sizeof(GenericAlternate));
97*a15fcc3cSEric Blake     assert(!(v->type & VISITOR_OUTPUT) || *obj);
98dbf11922SEric Blake     if (v->start_alternate) {
99e58d695eSEric Blake         v->start_alternate(v, name, obj, size, promote_int, &err);
100dbf11922SEric Blake     }
101*a15fcc3cSEric Blake     if (v->type & VISITOR_INPUT) {
102e58d695eSEric Blake         assert(v->start_alternate && !err != !*obj);
103e58d695eSEric Blake     }
104e58d695eSEric Blake     error_propagate(errp, err);
105dbf11922SEric Blake }
106dbf11922SEric Blake 
1071158bb2aSEric Blake void visit_end_alternate(Visitor *v, void **obj)
108dbf11922SEric Blake {
109dbf11922SEric Blake     if (v->end_alternate) {
1101158bb2aSEric Blake         v->end_alternate(v, obj);
111dbf11922SEric Blake     }
112dbf11922SEric Blake }
113dbf11922SEric Blake 
11451e72bc1SEric Blake bool visit_optional(Visitor *v, const char *name, bool *present)
1152345c77cSMichael Roth {
116297a3646SMarkus Armbruster     if (v->optional) {
1170b2a0d6bSEric Blake         v->optional(v, name, present);
1182345c77cSMichael Roth     }
11929637a6eSEric Blake     return *present;
1202345c77cSMichael Roth }
1212345c77cSMichael Roth 
12268ab47e4SEric Blake bool visit_is_input(Visitor *v)
12368ab47e4SEric Blake {
12468ab47e4SEric Blake     return v->type == VISITOR_INPUT;
12568ab47e4SEric Blake }
12668ab47e4SEric Blake 
12751e72bc1SEric Blake void visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp)
1282345c77cSMichael Roth {
129adfb264cSEric Blake     assert(obj);
1300b2a0d6bSEric Blake     v->type_int64(v, name, obj, errp);
1312345c77cSMichael Roth }
1322345c77cSMichael Roth 
13304e070d2SEric Blake static void visit_type_uintN(Visitor *v, uint64_t *obj, const char *name,
13404e070d2SEric Blake                              uint64_t max, const char *type, Error **errp)
13504e070d2SEric Blake {
13604e070d2SEric Blake     Error *err = NULL;
13704e070d2SEric Blake     uint64_t value = *obj;
13804e070d2SEric Blake 
1390b2a0d6bSEric Blake     v->type_uint64(v, name, &value, &err);
14004e070d2SEric Blake     if (err) {
14104e070d2SEric Blake         error_propagate(errp, err);
14204e070d2SEric Blake     } else if (value > max) {
14304e070d2SEric Blake         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
14404e070d2SEric Blake                    name ? name : "null", type);
14504e070d2SEric Blake     } else {
14604e070d2SEric Blake         *obj = value;
14704e070d2SEric Blake     }
14804e070d2SEric Blake }
14904e070d2SEric Blake 
15051e72bc1SEric Blake void visit_type_uint8(Visitor *v, const char *name, uint8_t *obj,
15151e72bc1SEric Blake                       Error **errp)
1524e27e819SMichael Roth {
15304e070d2SEric Blake     uint64_t value = *obj;
15404e070d2SEric Blake     visit_type_uintN(v, &value, name, UINT8_MAX, "uint8_t", errp);
1554e27e819SMichael Roth     *obj = value;
1564e27e819SMichael Roth }
1574e27e819SMichael Roth 
15851e72bc1SEric Blake void visit_type_uint16(Visitor *v, const char *name, uint16_t *obj,
15904e070d2SEric Blake                        Error **errp)
1604e27e819SMichael Roth {
16104e070d2SEric Blake     uint64_t value = *obj;
16204e070d2SEric Blake     visit_type_uintN(v, &value, name, UINT16_MAX, "uint16_t", errp);
1634e27e819SMichael Roth     *obj = value;
1644e27e819SMichael Roth }
1654e27e819SMichael Roth 
16651e72bc1SEric Blake void visit_type_uint32(Visitor *v, const char *name, uint32_t *obj,
16704e070d2SEric Blake                        Error **errp)
1684e27e819SMichael Roth {
16904e070d2SEric Blake     uint64_t value = *obj;
17004e070d2SEric Blake     visit_type_uintN(v, &value, name, UINT32_MAX, "uint32_t", errp);
1714e27e819SMichael Roth     *obj = value;
1724e27e819SMichael Roth }
1734e27e819SMichael Roth 
17451e72bc1SEric Blake void visit_type_uint64(Visitor *v, const char *name, uint64_t *obj,
17504e070d2SEric Blake                        Error **errp)
1764e27e819SMichael Roth {
177adfb264cSEric Blake     assert(obj);
1780b2a0d6bSEric Blake     v->type_uint64(v, name, obj, errp);
1794e27e819SMichael Roth }
1804e27e819SMichael Roth 
18104e070d2SEric Blake static void visit_type_intN(Visitor *v, int64_t *obj, const char *name,
18204e070d2SEric Blake                             int64_t min, int64_t max, const char *type,
18304e070d2SEric Blake                             Error **errp)
1844e27e819SMichael Roth {
18504e070d2SEric Blake     Error *err = NULL;
18604e070d2SEric Blake     int64_t value = *obj;
187297a3646SMarkus Armbruster 
1880b2a0d6bSEric Blake     v->type_int64(v, name, &value, &err);
18904e070d2SEric Blake     if (err) {
19004e070d2SEric Blake         error_propagate(errp, err);
19104e070d2SEric Blake     } else if (value < min || value > max) {
192c6bd8c70SMarkus Armbruster         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
19304e070d2SEric Blake                    name ? name : "null", type);
19404e070d2SEric Blake     } else {
1954e27e819SMichael Roth         *obj = value;
1964e27e819SMichael Roth     }
1974e27e819SMichael Roth }
1984e27e819SMichael Roth 
19951e72bc1SEric Blake void visit_type_int8(Visitor *v, const char *name, int8_t *obj, Error **errp)
20004e070d2SEric Blake {
20104e070d2SEric Blake     int64_t value = *obj;
20204e070d2SEric Blake     visit_type_intN(v, &value, name, INT8_MIN, INT8_MAX, "int8_t", errp);
20304e070d2SEric Blake     *obj = value;
20404e070d2SEric Blake }
20504e070d2SEric Blake 
20651e72bc1SEric Blake void visit_type_int16(Visitor *v, const char *name, int16_t *obj,
20751e72bc1SEric Blake                       Error **errp)
2084e27e819SMichael Roth {
20904e070d2SEric Blake     int64_t value = *obj;
21004e070d2SEric Blake     visit_type_intN(v, &value, name, INT16_MIN, INT16_MAX, "int16_t", errp);
2114e27e819SMichael Roth     *obj = value;
2124e27e819SMichael Roth }
2134e27e819SMichael Roth 
21451e72bc1SEric Blake void visit_type_int32(Visitor *v, const char *name, int32_t *obj,
21551e72bc1SEric Blake                       Error **errp)
2164e27e819SMichael Roth {
21704e070d2SEric Blake     int64_t value = *obj;
21804e070d2SEric Blake     visit_type_intN(v, &value, name, INT32_MIN, INT32_MAX, "int32_t", errp);
2194e27e819SMichael Roth     *obj = value;
2204e27e819SMichael Roth }
2214e27e819SMichael Roth 
22251e72bc1SEric Blake void visit_type_int64(Visitor *v, const char *name, int64_t *obj,
22351e72bc1SEric Blake                       Error **errp)
2244e27e819SMichael Roth {
225adfb264cSEric Blake     assert(obj);
2260b2a0d6bSEric Blake     v->type_int64(v, name, obj, errp);
2274e27e819SMichael Roth }
2284e27e819SMichael Roth 
22951e72bc1SEric Blake void visit_type_size(Visitor *v, const char *name, uint64_t *obj,
23051e72bc1SEric Blake                      Error **errp)
231092705d4SLaszlo Ersek {
232adfb264cSEric Blake     assert(obj);
233b8877962SVasilis Liaskovitis     if (v->type_size) {
2340b2a0d6bSEric Blake         v->type_size(v, name, obj, errp);
235b8877962SVasilis Liaskovitis     } else {
2360b2a0d6bSEric Blake         v->type_uint64(v, name, obj, errp);
237b8877962SVasilis Liaskovitis     }
238092705d4SLaszlo Ersek }
239092705d4SLaszlo Ersek 
24051e72bc1SEric Blake void visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp)
2412345c77cSMichael Roth {
242adfb264cSEric Blake     assert(obj);
2430b2a0d6bSEric Blake     v->type_bool(v, name, obj, errp);
2442345c77cSMichael Roth }
2452345c77cSMichael Roth 
24651e72bc1SEric Blake void visit_type_str(Visitor *v, const char *name, char **obj, Error **errp)
2472345c77cSMichael Roth {
248e58d695eSEric Blake     Error *err = NULL;
249e58d695eSEric Blake 
250e58d695eSEric Blake     assert(obj);
251adfb264cSEric Blake     /* TODO: Fix callers to not pass NULL when they mean "", so that we
252adfb264cSEric Blake      * can enable:
253*a15fcc3cSEric Blake     assert(!(v->type & VISITOR_OUTPUT) || *obj);
254adfb264cSEric Blake      */
255e58d695eSEric Blake     v->type_str(v, name, obj, &err);
256*a15fcc3cSEric Blake     if (v->type & VISITOR_INPUT) {
257e58d695eSEric Blake         assert(!err != !*obj);
258e58d695eSEric Blake     }
259e58d695eSEric Blake     error_propagate(errp, err);
2602345c77cSMichael Roth }
2612345c77cSMichael Roth 
26251e72bc1SEric Blake void visit_type_number(Visitor *v, const char *name, double *obj,
26351e72bc1SEric Blake                        Error **errp)
2642345c77cSMichael Roth {
265adfb264cSEric Blake     assert(obj);
2660b2a0d6bSEric Blake     v->type_number(v, name, obj, errp);
2672345c77cSMichael Roth }
2680f71a1e0SPaolo Bonzini 
26951e72bc1SEric Blake void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp)
27028770e05SMarkus Armbruster {
271e58d695eSEric Blake     Error *err = NULL;
272e58d695eSEric Blake 
273e58d695eSEric Blake     assert(obj);
274adfb264cSEric Blake     assert(v->type != VISITOR_OUTPUT || *obj);
275e58d695eSEric Blake     v->type_any(v, name, obj, &err);
276e58d695eSEric Blake     if (v->type == VISITOR_INPUT) {
277e58d695eSEric Blake         assert(!err != !*obj);
278e58d695eSEric Blake     }
279e58d695eSEric Blake     error_propagate(errp, err);
28028770e05SMarkus Armbruster }
28128770e05SMarkus Armbruster 
2823bc97fd5SEric Blake void visit_type_null(Visitor *v, const char *name, Error **errp)
2833bc97fd5SEric Blake {
2843bc97fd5SEric Blake     v->type_null(v, name, errp);
2853bc97fd5SEric Blake }
2863bc97fd5SEric Blake 
287983f52d4SEric Blake static void output_type_enum(Visitor *v, const char *name, int *obj,
288337283dfSEric Blake                              const char *const strings[], Error **errp)
2890f71a1e0SPaolo Bonzini {
2900f71a1e0SPaolo Bonzini     int i = 0;
2910f71a1e0SPaolo Bonzini     int value = *obj;
2920f71a1e0SPaolo Bonzini     char *enum_str;
2930f71a1e0SPaolo Bonzini 
2940f71a1e0SPaolo Bonzini     while (strings[i++] != NULL);
2950f71a1e0SPaolo Bonzini     if (value < 0 || value >= i - 1) {
296c6bd8c70SMarkus Armbruster         error_setg(errp, QERR_INVALID_PARAMETER, name ? name : "null");
2970f71a1e0SPaolo Bonzini         return;
2980f71a1e0SPaolo Bonzini     }
2990f71a1e0SPaolo Bonzini 
3000f71a1e0SPaolo Bonzini     enum_str = (char *)strings[value];
30151e72bc1SEric Blake     visit_type_str(v, name, &enum_str, errp);
3020f71a1e0SPaolo Bonzini }
3030f71a1e0SPaolo Bonzini 
304983f52d4SEric Blake static void input_type_enum(Visitor *v, const char *name, int *obj,
305337283dfSEric Blake                             const char *const strings[], Error **errp)
3060f71a1e0SPaolo Bonzini {
307297a3646SMarkus Armbruster     Error *local_err = NULL;
3080f71a1e0SPaolo Bonzini     int64_t value = 0;
3090f71a1e0SPaolo Bonzini     char *enum_str;
3100f71a1e0SPaolo Bonzini 
31151e72bc1SEric Blake     visit_type_str(v, name, &enum_str, &local_err);
312297a3646SMarkus Armbruster     if (local_err) {
313297a3646SMarkus Armbruster         error_propagate(errp, local_err);
3140f71a1e0SPaolo Bonzini         return;
3150f71a1e0SPaolo Bonzini     }
3160f71a1e0SPaolo Bonzini 
3170f71a1e0SPaolo Bonzini     while (strings[value] != NULL) {
3180f71a1e0SPaolo Bonzini         if (strcmp(strings[value], enum_str) == 0) {
3190f71a1e0SPaolo Bonzini             break;
3200f71a1e0SPaolo Bonzini         }
3210f71a1e0SPaolo Bonzini         value++;
3220f71a1e0SPaolo Bonzini     }
3230f71a1e0SPaolo Bonzini 
3240f71a1e0SPaolo Bonzini     if (strings[value] == NULL) {
325c6bd8c70SMarkus Armbruster         error_setg(errp, QERR_INVALID_PARAMETER, enum_str);
3260f71a1e0SPaolo Bonzini         g_free(enum_str);
3270f71a1e0SPaolo Bonzini         return;
3280f71a1e0SPaolo Bonzini     }
3290f71a1e0SPaolo Bonzini 
3300f71a1e0SPaolo Bonzini     g_free(enum_str);
3310f71a1e0SPaolo Bonzini     *obj = value;
3320f71a1e0SPaolo Bonzini }
333983f52d4SEric Blake 
334983f52d4SEric Blake void visit_type_enum(Visitor *v, const char *name, int *obj,
335983f52d4SEric Blake                      const char *const strings[], Error **errp)
336983f52d4SEric Blake {
337adfb264cSEric Blake     assert(obj && strings);
338*a15fcc3cSEric Blake     switch (v->type) {
339*a15fcc3cSEric Blake     case VISITOR_INPUT:
340983f52d4SEric Blake         input_type_enum(v, name, obj, strings, errp);
341*a15fcc3cSEric Blake         break;
342*a15fcc3cSEric Blake     case VISITOR_OUTPUT:
343983f52d4SEric Blake         output_type_enum(v, name, obj, strings, errp);
344*a15fcc3cSEric Blake         break;
345*a15fcc3cSEric Blake     case VISITOR_CLONE:
346*a15fcc3cSEric Blake         /* nothing further to do, scalar value was already copied by
347*a15fcc3cSEric Blake          * g_memdup() during visit_start_*() */
348*a15fcc3cSEric Blake         break;
349*a15fcc3cSEric Blake     case VISITOR_DEALLOC:
350*a15fcc3cSEric Blake         /* nothing to deallocate for a scalar */
351*a15fcc3cSEric Blake         break;
352983f52d4SEric Blake     }
353983f52d4SEric Blake }
354