xref: /qemu/qapi/qapi-visit-core.c (revision 113e47ae6dc45b08e732dd5fa85abe71b764f5ae)
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"
17*113e47aeSMarkus Armbruster #include "qapi/util.h"
1879ee7df8SPaolo Bonzini #include "qemu-common.h"
1969dd62dfSKevin Wolf #include "qapi/qmp/qobject.h"
207b1b5d19SPaolo Bonzini #include "qapi/qmp/qerror.h"
217b1b5d19SPaolo Bonzini #include "qapi/visitor.h"
227b1b5d19SPaolo Bonzini #include "qapi/visitor-impl.h"
23ebfd93b6SDaniel P. Berrange #include "trace.h"
242345c77cSMichael Roth 
253b098d56SEric Blake void visit_complete(Visitor *v, void *opaque)
263b098d56SEric Blake {
273b098d56SEric Blake     assert(v->type != VISITOR_OUTPUT || v->complete);
28ebfd93b6SDaniel P. Berrange     trace_visit_complete(v, opaque);
293b098d56SEric Blake     if (v->complete) {
303b098d56SEric Blake         v->complete(v, opaque);
313b098d56SEric Blake     }
323b098d56SEric Blake }
333b098d56SEric Blake 
342c0ef9f4SEric Blake void visit_free(Visitor *v)
352c0ef9f4SEric Blake {
36ebfd93b6SDaniel P. Berrange     trace_visit_free(v);
372c0ef9f4SEric Blake     if (v) {
382c0ef9f4SEric Blake         v->free(v);
392c0ef9f4SEric Blake     }
402c0ef9f4SEric Blake }
412c0ef9f4SEric Blake 
4251e72bc1SEric Blake void visit_start_struct(Visitor *v, const char *name, void **obj,
43337283dfSEric Blake                         size_t size, Error **errp)
442345c77cSMichael Roth {
45e58d695eSEric Blake     Error *err = NULL;
46e58d695eSEric Blake 
47ebfd93b6SDaniel P. Berrange     trace_visit_start_struct(v, name, obj, size);
48adfb264cSEric Blake     if (obj) {
49adfb264cSEric Blake         assert(size);
50a15fcc3cSEric Blake         assert(!(v->type & VISITOR_OUTPUT) || *obj);
51adfb264cSEric Blake     }
52e58d695eSEric Blake     v->start_struct(v, name, obj, size, &err);
53a15fcc3cSEric Blake     if (obj && (v->type & VISITOR_INPUT)) {
54e58d695eSEric Blake         assert(!err != !*obj);
55e58d695eSEric Blake     }
56e58d695eSEric Blake     error_propagate(errp, err);
572345c77cSMichael Roth }
582345c77cSMichael Roth 
5915c2f669SEric Blake void visit_check_struct(Visitor *v, Error **errp)
602345c77cSMichael Roth {
61ebfd93b6SDaniel P. Berrange     trace_visit_check_struct(v);
6215c2f669SEric Blake     if (v->check_struct) {
6315c2f669SEric Blake         v->check_struct(v, errp);
6415c2f669SEric Blake     }
6515c2f669SEric Blake }
6615c2f669SEric Blake 
671158bb2aSEric Blake void visit_end_struct(Visitor *v, void **obj)
6815c2f669SEric Blake {
69ebfd93b6SDaniel P. Berrange     trace_visit_end_struct(v, obj);
701158bb2aSEric Blake     v->end_struct(v, obj);
712345c77cSMichael Roth }
722345c77cSMichael Roth 
73d9f62ddeSEric Blake void visit_start_list(Visitor *v, const char *name, GenericList **list,
74d9f62ddeSEric Blake                       size_t size, Error **errp)
752345c77cSMichael Roth {
76d9f62ddeSEric Blake     Error *err = NULL;
77d9f62ddeSEric Blake 
78d9f62ddeSEric Blake     assert(!list || size >= sizeof(GenericList));
79ebfd93b6SDaniel P. Berrange     trace_visit_start_list(v, name, list, size);
80d9f62ddeSEric Blake     v->start_list(v, name, list, size, &err);
81a15fcc3cSEric Blake     if (list && (v->type & VISITOR_INPUT)) {
82d9f62ddeSEric Blake         assert(!(err && *list));
83d9f62ddeSEric Blake     }
84d9f62ddeSEric Blake     error_propagate(errp, err);
852345c77cSMichael Roth }
862345c77cSMichael Roth 
87d9f62ddeSEric Blake GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size)
882345c77cSMichael Roth {
89d9f62ddeSEric Blake     assert(tail && size >= sizeof(GenericList));
90ebfd93b6SDaniel P. Berrange     trace_visit_next_list(v, tail, size);
91d9f62ddeSEric Blake     return v->next_list(v, tail, size);
922345c77cSMichael Roth }
932345c77cSMichael Roth 
94a4a1c70dSMarkus Armbruster void visit_check_list(Visitor *v, Error **errp)
95a4a1c70dSMarkus Armbruster {
96a4a1c70dSMarkus Armbruster     trace_visit_check_list(v);
97a4a1c70dSMarkus Armbruster     if (v->check_list) {
98a4a1c70dSMarkus Armbruster         v->check_list(v, errp);
99a4a1c70dSMarkus Armbruster     }
100a4a1c70dSMarkus Armbruster }
101a4a1c70dSMarkus Armbruster 
1021158bb2aSEric Blake void visit_end_list(Visitor *v, void **obj)
1032345c77cSMichael Roth {
104ebfd93b6SDaniel P. Berrange     trace_visit_end_list(v, obj);
1051158bb2aSEric Blake     v->end_list(v, obj);
1062345c77cSMichael Roth }
1072345c77cSMichael Roth 
108dbf11922SEric Blake void visit_start_alternate(Visitor *v, const char *name,
109dbf11922SEric Blake                            GenericAlternate **obj, size_t size,
11060390d2dSMarc-André Lureau                            Error **errp)
111dbf11922SEric Blake {
112e58d695eSEric Blake     Error *err = NULL;
113e58d695eSEric Blake 
114dbf11922SEric Blake     assert(obj && size >= sizeof(GenericAlternate));
115a15fcc3cSEric Blake     assert(!(v->type & VISITOR_OUTPUT) || *obj);
11660390d2dSMarc-André Lureau     trace_visit_start_alternate(v, name, obj, size);
117dbf11922SEric Blake     if (v->start_alternate) {
11860390d2dSMarc-André Lureau         v->start_alternate(v, name, obj, size, &err);
119dbf11922SEric Blake     }
120a15fcc3cSEric Blake     if (v->type & VISITOR_INPUT) {
121e58d695eSEric Blake         assert(v->start_alternate && !err != !*obj);
122e58d695eSEric Blake     }
123e58d695eSEric Blake     error_propagate(errp, err);
124dbf11922SEric Blake }
125dbf11922SEric Blake 
1261158bb2aSEric Blake void visit_end_alternate(Visitor *v, void **obj)
127dbf11922SEric Blake {
128ebfd93b6SDaniel P. Berrange     trace_visit_end_alternate(v, obj);
129dbf11922SEric Blake     if (v->end_alternate) {
1301158bb2aSEric Blake         v->end_alternate(v, obj);
131dbf11922SEric Blake     }
132dbf11922SEric Blake }
133dbf11922SEric Blake 
13451e72bc1SEric Blake bool visit_optional(Visitor *v, const char *name, bool *present)
1352345c77cSMichael Roth {
136ebfd93b6SDaniel P. Berrange     trace_visit_optional(v, name, present);
137297a3646SMarkus Armbruster     if (v->optional) {
1380b2a0d6bSEric Blake         v->optional(v, name, present);
1392345c77cSMichael Roth     }
14029637a6eSEric Blake     return *present;
1412345c77cSMichael Roth }
1422345c77cSMichael Roth 
14368ab47e4SEric Blake bool visit_is_input(Visitor *v)
14468ab47e4SEric Blake {
14568ab47e4SEric Blake     return v->type == VISITOR_INPUT;
14668ab47e4SEric Blake }
14768ab47e4SEric Blake 
14851e72bc1SEric Blake void visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp)
1492345c77cSMichael Roth {
150adfb264cSEric Blake     assert(obj);
151ebfd93b6SDaniel P. Berrange     trace_visit_type_int(v, name, obj);
1520b2a0d6bSEric Blake     v->type_int64(v, name, obj, errp);
1532345c77cSMichael Roth }
1542345c77cSMichael Roth 
15504e070d2SEric Blake static void visit_type_uintN(Visitor *v, uint64_t *obj, const char *name,
15604e070d2SEric Blake                              uint64_t max, const char *type, Error **errp)
15704e070d2SEric Blake {
15804e070d2SEric Blake     Error *err = NULL;
15904e070d2SEric Blake     uint64_t value = *obj;
16004e070d2SEric Blake 
1610b2a0d6bSEric Blake     v->type_uint64(v, name, &value, &err);
16204e070d2SEric Blake     if (err) {
16304e070d2SEric Blake         error_propagate(errp, err);
16404e070d2SEric Blake     } else if (value > max) {
16504e070d2SEric Blake         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
16604e070d2SEric Blake                    name ? name : "null", type);
16704e070d2SEric Blake     } else {
16804e070d2SEric Blake         *obj = value;
16904e070d2SEric Blake     }
17004e070d2SEric Blake }
17104e070d2SEric Blake 
17251e72bc1SEric Blake void visit_type_uint8(Visitor *v, const char *name, uint8_t *obj,
17351e72bc1SEric Blake                       Error **errp)
1744e27e819SMichael Roth {
175ebfd93b6SDaniel P. Berrange     uint64_t value;
176ebfd93b6SDaniel P. Berrange 
177ebfd93b6SDaniel P. Berrange     trace_visit_type_uint8(v, name, obj);
178ebfd93b6SDaniel P. Berrange     value = *obj;
17904e070d2SEric Blake     visit_type_uintN(v, &value, name, UINT8_MAX, "uint8_t", errp);
1804e27e819SMichael Roth     *obj = value;
1814e27e819SMichael Roth }
1824e27e819SMichael Roth 
18351e72bc1SEric Blake void visit_type_uint16(Visitor *v, const char *name, uint16_t *obj,
18404e070d2SEric Blake                        Error **errp)
1854e27e819SMichael Roth {
186ebfd93b6SDaniel P. Berrange     uint64_t value;
187ebfd93b6SDaniel P. Berrange 
188ebfd93b6SDaniel P. Berrange     trace_visit_type_uint16(v, name, obj);
189ebfd93b6SDaniel P. Berrange     value = *obj;
19004e070d2SEric Blake     visit_type_uintN(v, &value, name, UINT16_MAX, "uint16_t", errp);
1914e27e819SMichael Roth     *obj = value;
1924e27e819SMichael Roth }
1934e27e819SMichael Roth 
19451e72bc1SEric Blake void visit_type_uint32(Visitor *v, const char *name, uint32_t *obj,
19504e070d2SEric Blake                        Error **errp)
1964e27e819SMichael Roth {
197ebfd93b6SDaniel P. Berrange     uint64_t value;
198ebfd93b6SDaniel P. Berrange 
199ebfd93b6SDaniel P. Berrange     trace_visit_type_uint32(v, name, obj);
200ebfd93b6SDaniel P. Berrange     value = *obj;
20104e070d2SEric Blake     visit_type_uintN(v, &value, name, UINT32_MAX, "uint32_t", errp);
2024e27e819SMichael Roth     *obj = value;
2034e27e819SMichael Roth }
2044e27e819SMichael Roth 
20551e72bc1SEric Blake void visit_type_uint64(Visitor *v, const char *name, uint64_t *obj,
20604e070d2SEric Blake                        Error **errp)
2074e27e819SMichael Roth {
208adfb264cSEric Blake     assert(obj);
209ebfd93b6SDaniel P. Berrange     trace_visit_type_uint64(v, name, obj);
2100b2a0d6bSEric Blake     v->type_uint64(v, name, obj, errp);
2114e27e819SMichael Roth }
2124e27e819SMichael Roth 
21304e070d2SEric Blake static void visit_type_intN(Visitor *v, int64_t *obj, const char *name,
21404e070d2SEric Blake                             int64_t min, int64_t max, const char *type,
21504e070d2SEric Blake                             Error **errp)
2164e27e819SMichael Roth {
21704e070d2SEric Blake     Error *err = NULL;
21804e070d2SEric Blake     int64_t value = *obj;
219297a3646SMarkus Armbruster 
2200b2a0d6bSEric Blake     v->type_int64(v, name, &value, &err);
22104e070d2SEric Blake     if (err) {
22204e070d2SEric Blake         error_propagate(errp, err);
22304e070d2SEric Blake     } else if (value < min || value > max) {
224c6bd8c70SMarkus Armbruster         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
22504e070d2SEric Blake                    name ? name : "null", type);
22604e070d2SEric Blake     } else {
2274e27e819SMichael Roth         *obj = value;
2284e27e819SMichael Roth     }
2294e27e819SMichael Roth }
2304e27e819SMichael Roth 
23151e72bc1SEric Blake void visit_type_int8(Visitor *v, const char *name, int8_t *obj, Error **errp)
23204e070d2SEric Blake {
233ebfd93b6SDaniel P. Berrange     int64_t value;
234ebfd93b6SDaniel P. Berrange 
235ebfd93b6SDaniel P. Berrange     trace_visit_type_int8(v, name, obj);
236ebfd93b6SDaniel P. Berrange     value = *obj;
23704e070d2SEric Blake     visit_type_intN(v, &value, name, INT8_MIN, INT8_MAX, "int8_t", errp);
23804e070d2SEric Blake     *obj = value;
23904e070d2SEric Blake }
24004e070d2SEric Blake 
24151e72bc1SEric Blake void visit_type_int16(Visitor *v, const char *name, int16_t *obj,
24251e72bc1SEric Blake                       Error **errp)
2434e27e819SMichael Roth {
244ebfd93b6SDaniel P. Berrange     int64_t value;
245ebfd93b6SDaniel P. Berrange 
246ebfd93b6SDaniel P. Berrange     trace_visit_type_int16(v, name, obj);
247ebfd93b6SDaniel P. Berrange     value = *obj;
24804e070d2SEric Blake     visit_type_intN(v, &value, name, INT16_MIN, INT16_MAX, "int16_t", errp);
2494e27e819SMichael Roth     *obj = value;
2504e27e819SMichael Roth }
2514e27e819SMichael Roth 
25251e72bc1SEric Blake void visit_type_int32(Visitor *v, const char *name, int32_t *obj,
25351e72bc1SEric Blake                       Error **errp)
2544e27e819SMichael Roth {
255ebfd93b6SDaniel P. Berrange     int64_t value;
256ebfd93b6SDaniel P. Berrange 
257ebfd93b6SDaniel P. Berrange     trace_visit_type_int32(v, name, obj);
258ebfd93b6SDaniel P. Berrange     value = *obj;
25904e070d2SEric Blake     visit_type_intN(v, &value, name, INT32_MIN, INT32_MAX, "int32_t", errp);
2604e27e819SMichael Roth     *obj = value;
2614e27e819SMichael Roth }
2624e27e819SMichael Roth 
26351e72bc1SEric Blake void visit_type_int64(Visitor *v, const char *name, int64_t *obj,
26451e72bc1SEric Blake                       Error **errp)
2654e27e819SMichael Roth {
266adfb264cSEric Blake     assert(obj);
267ebfd93b6SDaniel P. Berrange     trace_visit_type_int64(v, name, obj);
2680b2a0d6bSEric Blake     v->type_int64(v, name, obj, errp);
2694e27e819SMichael Roth }
2704e27e819SMichael Roth 
27151e72bc1SEric Blake void visit_type_size(Visitor *v, const char *name, uint64_t *obj,
27251e72bc1SEric Blake                      Error **errp)
273092705d4SLaszlo Ersek {
274adfb264cSEric Blake     assert(obj);
275ebfd93b6SDaniel P. Berrange     trace_visit_type_size(v, name, obj);
276b8877962SVasilis Liaskovitis     if (v->type_size) {
2770b2a0d6bSEric Blake         v->type_size(v, name, obj, errp);
278b8877962SVasilis Liaskovitis     } else {
2790b2a0d6bSEric Blake         v->type_uint64(v, name, obj, errp);
280b8877962SVasilis Liaskovitis     }
281092705d4SLaszlo Ersek }
282092705d4SLaszlo Ersek 
28351e72bc1SEric Blake void visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp)
2842345c77cSMichael Roth {
285adfb264cSEric Blake     assert(obj);
286ebfd93b6SDaniel P. Berrange     trace_visit_type_bool(v, name, obj);
2870b2a0d6bSEric Blake     v->type_bool(v, name, obj, errp);
2882345c77cSMichael Roth }
2892345c77cSMichael Roth 
29051e72bc1SEric Blake void visit_type_str(Visitor *v, const char *name, char **obj, Error **errp)
2912345c77cSMichael Roth {
292e58d695eSEric Blake     Error *err = NULL;
293e58d695eSEric Blake 
294e58d695eSEric Blake     assert(obj);
295adfb264cSEric Blake     /* TODO: Fix callers to not pass NULL when they mean "", so that we
296adfb264cSEric Blake      * can enable:
297a15fcc3cSEric Blake     assert(!(v->type & VISITOR_OUTPUT) || *obj);
298adfb264cSEric Blake      */
299ebfd93b6SDaniel P. Berrange     trace_visit_type_str(v, name, obj);
300e58d695eSEric Blake     v->type_str(v, name, obj, &err);
301a15fcc3cSEric Blake     if (v->type & VISITOR_INPUT) {
302e58d695eSEric Blake         assert(!err != !*obj);
303e58d695eSEric Blake     }
304e58d695eSEric Blake     error_propagate(errp, err);
3052345c77cSMichael Roth }
3062345c77cSMichael Roth 
30751e72bc1SEric Blake void visit_type_number(Visitor *v, const char *name, double *obj,
30851e72bc1SEric Blake                        Error **errp)
3092345c77cSMichael Roth {
310adfb264cSEric Blake     assert(obj);
311ebfd93b6SDaniel P. Berrange     trace_visit_type_number(v, name, obj);
3120b2a0d6bSEric Blake     v->type_number(v, name, obj, errp);
3132345c77cSMichael Roth }
3140f71a1e0SPaolo Bonzini 
31551e72bc1SEric Blake void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp)
31628770e05SMarkus Armbruster {
317e58d695eSEric Blake     Error *err = NULL;
318e58d695eSEric Blake 
319e58d695eSEric Blake     assert(obj);
320adfb264cSEric Blake     assert(v->type != VISITOR_OUTPUT || *obj);
321ebfd93b6SDaniel P. Berrange     trace_visit_type_any(v, name, obj);
322e58d695eSEric Blake     v->type_any(v, name, obj, &err);
323e58d695eSEric Blake     if (v->type == VISITOR_INPUT) {
324e58d695eSEric Blake         assert(!err != !*obj);
325e58d695eSEric Blake     }
326e58d695eSEric Blake     error_propagate(errp, err);
32728770e05SMarkus Armbruster }
32828770e05SMarkus Armbruster 
329d2f95f4dSMarkus Armbruster void visit_type_null(Visitor *v, const char *name, QNull **obj,
330d2f95f4dSMarkus Armbruster                      Error **errp)
3313bc97fd5SEric Blake {
332d2f95f4dSMarkus Armbruster     trace_visit_type_null(v, name, obj);
333d2f95f4dSMarkus Armbruster     v->type_null(v, name, obj, errp);
3343bc97fd5SEric Blake }
3353bc97fd5SEric Blake 
336983f52d4SEric Blake static void output_type_enum(Visitor *v, const char *name, int *obj,
337337283dfSEric Blake                              const char *const strings[], Error **errp)
3380f71a1e0SPaolo Bonzini {
3390f71a1e0SPaolo Bonzini     int i = 0;
3400f71a1e0SPaolo Bonzini     int value = *obj;
3410f71a1e0SPaolo Bonzini     char *enum_str;
3420f71a1e0SPaolo Bonzini 
3430f71a1e0SPaolo Bonzini     while (strings[i++] != NULL);
3440f71a1e0SPaolo Bonzini     if (value < 0 || value >= i - 1) {
345c6bd8c70SMarkus Armbruster         error_setg(errp, QERR_INVALID_PARAMETER, name ? name : "null");
3460f71a1e0SPaolo Bonzini         return;
3470f71a1e0SPaolo Bonzini     }
3480f71a1e0SPaolo Bonzini 
3490f71a1e0SPaolo Bonzini     enum_str = (char *)strings[value];
35051e72bc1SEric Blake     visit_type_str(v, name, &enum_str, errp);
3510f71a1e0SPaolo Bonzini }
3520f71a1e0SPaolo Bonzini 
353983f52d4SEric Blake static void input_type_enum(Visitor *v, const char *name, int *obj,
354337283dfSEric Blake                             const char *const strings[], Error **errp)
3550f71a1e0SPaolo Bonzini {
356297a3646SMarkus Armbruster     Error *local_err = NULL;
357*113e47aeSMarkus Armbruster     int64_t value;
3580f71a1e0SPaolo Bonzini     char *enum_str;
3590f71a1e0SPaolo Bonzini 
36051e72bc1SEric Blake     visit_type_str(v, name, &enum_str, &local_err);
361297a3646SMarkus Armbruster     if (local_err) {
362297a3646SMarkus Armbruster         error_propagate(errp, local_err);
3630f71a1e0SPaolo Bonzini         return;
3640f71a1e0SPaolo Bonzini     }
3650f71a1e0SPaolo Bonzini 
366*113e47aeSMarkus Armbruster     value = qapi_enum_parse(strings, enum_str, -1, NULL);
367*113e47aeSMarkus Armbruster     if (value < 0) {
368c6bd8c70SMarkus Armbruster         error_setg(errp, QERR_INVALID_PARAMETER, enum_str);
3690f71a1e0SPaolo Bonzini         g_free(enum_str);
3700f71a1e0SPaolo Bonzini         return;
3710f71a1e0SPaolo Bonzini     }
3720f71a1e0SPaolo Bonzini 
3730f71a1e0SPaolo Bonzini     g_free(enum_str);
3740f71a1e0SPaolo Bonzini     *obj = value;
3750f71a1e0SPaolo Bonzini }
376983f52d4SEric Blake 
377983f52d4SEric Blake void visit_type_enum(Visitor *v, const char *name, int *obj,
378983f52d4SEric Blake                      const char *const strings[], Error **errp)
379983f52d4SEric Blake {
380adfb264cSEric Blake     assert(obj && strings);
3816514532fSStefan Hajnoczi     trace_visit_type_enum(v, name, obj);
382a15fcc3cSEric Blake     switch (v->type) {
383a15fcc3cSEric Blake     case VISITOR_INPUT:
384983f52d4SEric Blake         input_type_enum(v, name, obj, strings, errp);
385a15fcc3cSEric Blake         break;
386a15fcc3cSEric Blake     case VISITOR_OUTPUT:
387983f52d4SEric Blake         output_type_enum(v, name, obj, strings, errp);
388a15fcc3cSEric Blake         break;
389a15fcc3cSEric Blake     case VISITOR_CLONE:
390a15fcc3cSEric Blake         /* nothing further to do, scalar value was already copied by
391a15fcc3cSEric Blake          * g_memdup() during visit_start_*() */
392a15fcc3cSEric Blake         break;
393a15fcc3cSEric Blake     case VISITOR_DEALLOC:
394a15fcc3cSEric Blake         /* nothing to deallocate for a scalar */
395a15fcc3cSEric Blake         break;
396983f52d4SEric Blake     }
397983f52d4SEric Blake }
398