xref: /qemu/qapi/qapi-visit-core.c (revision 91fa93e5)
1 /*
2  * Core Definitions for QAPI Visitor Classes
3  *
4  * Copyright (C) 2012-2016 Red Hat, Inc.
5  * Copyright IBM, Corp. 2011
6  *
7  * Authors:
8  *  Anthony Liguori   <aliguori@us.ibm.com>
9  *
10  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
11  * See the COPYING.LIB file in the top-level directory.
12  *
13  */
14 
15 #include "qemu/osdep.h"
16 #include "qapi/error.h"
17 #include "qapi/qmp/qerror.h"
18 #include "qapi/visitor.h"
19 #include "qapi/visitor-impl.h"
20 #include "trace.h"
21 
22 void visit_complete(Visitor *v, void *opaque)
23 {
24     assert(v->type != VISITOR_OUTPUT || v->complete);
25     trace_visit_complete(v, opaque);
26     if (v->complete) {
27         v->complete(v, opaque);
28     }
29 }
30 
31 void visit_free(Visitor *v)
32 {
33     trace_visit_free(v);
34     if (v) {
35         v->free(v);
36     }
37 }
38 
39 bool visit_start_struct(Visitor *v, const char *name, void **obj,
40                         size_t size, Error **errp)
41 {
42     bool ok;
43 
44     trace_visit_start_struct(v, name, obj, size);
45     if (obj) {
46         assert(size);
47         assert(!(v->type & VISITOR_OUTPUT) || *obj);
48     }
49     ok = v->start_struct(v, name, obj, size, errp);
50     if (obj && (v->type & VISITOR_INPUT)) {
51         assert(ok != !*obj);
52     }
53     return ok;
54 }
55 
56 bool visit_check_struct(Visitor *v, Error **errp)
57 {
58     trace_visit_check_struct(v);
59     return v->check_struct ? v->check_struct(v, errp) : true;
60 }
61 
62 void visit_end_struct(Visitor *v, void **obj)
63 {
64     trace_visit_end_struct(v, obj);
65     v->end_struct(v, obj);
66 }
67 
68 bool visit_start_list(Visitor *v, const char *name, GenericList **list,
69                       size_t size, Error **errp)
70 {
71     bool ok;
72 
73     assert(!list || size >= sizeof(GenericList));
74     trace_visit_start_list(v, name, list, size);
75     ok = v->start_list(v, name, list, size, errp);
76     if (list && (v->type & VISITOR_INPUT)) {
77         assert(ok || !*list);
78     }
79     return ok;
80 }
81 
82 GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size)
83 {
84     assert(tail && size >= sizeof(GenericList));
85     trace_visit_next_list(v, tail, size);
86     return v->next_list(v, tail, size);
87 }
88 
89 bool visit_check_list(Visitor *v, Error **errp)
90 {
91     trace_visit_check_list(v);
92     return v->check_list ? v->check_list(v, errp) : true;
93 }
94 
95 void visit_end_list(Visitor *v, void **obj)
96 {
97     trace_visit_end_list(v, obj);
98     v->end_list(v, obj);
99 }
100 
101 bool visit_start_alternate(Visitor *v, const char *name,
102                            GenericAlternate **obj, size_t size,
103                            Error **errp)
104 {
105     bool ok;
106 
107     assert(obj && size >= sizeof(GenericAlternate));
108     assert(!(v->type & VISITOR_OUTPUT) || *obj);
109     trace_visit_start_alternate(v, name, obj, size);
110     if (!v->start_alternate) {
111         assert(!(v->type & VISITOR_INPUT));
112         return true;
113     }
114     ok = v->start_alternate(v, name, obj, size, errp);
115     if (v->type & VISITOR_INPUT) {
116         assert(ok != !*obj);
117     }
118     return ok;
119 }
120 
121 void visit_end_alternate(Visitor *v, void **obj)
122 {
123     trace_visit_end_alternate(v, obj);
124     if (v->end_alternate) {
125         v->end_alternate(v, obj);
126     }
127 }
128 
129 bool visit_optional(Visitor *v, const char *name, bool *present)
130 {
131     trace_visit_optional(v, name, present);
132     if (v->optional) {
133         v->optional(v, name, present);
134     }
135     return *present;
136 }
137 
138 bool visit_deprecated(Visitor *v, const char *name)
139 {
140     trace_visit_deprecated(v, name);
141     if (v->deprecated) {
142         return v->deprecated(v, name);
143     }
144     return true;
145 }
146 
147 bool visit_is_input(Visitor *v)
148 {
149     return v->type == VISITOR_INPUT;
150 }
151 
152 bool visit_is_dealloc(Visitor *v)
153 {
154     return v->type == VISITOR_DEALLOC;
155 }
156 
157 bool visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp)
158 {
159     assert(obj);
160     trace_visit_type_int(v, name, obj);
161     return v->type_int64(v, name, obj, errp);
162 }
163 
164 static bool visit_type_uintN(Visitor *v, uint64_t *obj, const char *name,
165                              uint64_t max, const char *type, Error **errp)
166 {
167     uint64_t value = *obj;
168 
169     assert(v->type == VISITOR_INPUT || value <= max);
170 
171     if (!v->type_uint64(v, name, &value, errp)) {
172         return false;
173     }
174     if (value > max) {
175         assert(v->type == VISITOR_INPUT);
176         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
177                    name ? name : "null", type);
178         return false;
179     }
180     *obj = value;
181     return true;
182 }
183 
184 bool visit_type_uint8(Visitor *v, const char *name, uint8_t *obj,
185                       Error **errp)
186 {
187     uint64_t value;
188     bool ok;
189 
190     trace_visit_type_uint8(v, name, obj);
191     value = *obj;
192     ok = visit_type_uintN(v, &value, name, UINT8_MAX, "uint8_t", errp);
193     *obj = value;
194     return ok;
195 }
196 
197 bool visit_type_uint16(Visitor *v, const char *name, uint16_t *obj,
198                        Error **errp)
199 {
200     uint64_t value;
201     bool ok;
202 
203     trace_visit_type_uint16(v, name, obj);
204     value = *obj;
205     ok = visit_type_uintN(v, &value, name, UINT16_MAX, "uint16_t", errp);
206     *obj = value;
207     return ok;
208 }
209 
210 bool visit_type_uint32(Visitor *v, const char *name, uint32_t *obj,
211                        Error **errp)
212 {
213     uint64_t value;
214     bool ok;
215 
216     trace_visit_type_uint32(v, name, obj);
217     value = *obj;
218     ok = visit_type_uintN(v, &value, name, UINT32_MAX, "uint32_t", errp);
219     *obj = value;
220     return ok;
221 }
222 
223 bool visit_type_uint64(Visitor *v, const char *name, uint64_t *obj,
224                        Error **errp)
225 {
226     assert(obj);
227     trace_visit_type_uint64(v, name, obj);
228     return v->type_uint64(v, name, obj, errp);
229 }
230 
231 static bool visit_type_intN(Visitor *v, int64_t *obj, const char *name,
232                             int64_t min, int64_t max, const char *type,
233                             Error **errp)
234 {
235     int64_t value = *obj;
236 
237     assert(v->type == VISITOR_INPUT || (value >= min && value <= max));
238 
239     if (!v->type_int64(v, name, &value, errp)) {
240         return false;
241     }
242     if (value < min || value > max) {
243         assert(v->type == VISITOR_INPUT);
244         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
245                    name ? name : "null", type);
246         return false;
247     }
248     *obj = value;
249     return true;
250 }
251 
252 bool visit_type_int8(Visitor *v, const char *name, int8_t *obj, Error **errp)
253 {
254     int64_t value;
255     bool ok;
256 
257     trace_visit_type_int8(v, name, obj);
258     value = *obj;
259     ok = visit_type_intN(v, &value, name, INT8_MIN, INT8_MAX, "int8_t", errp);
260     *obj = value;
261     return ok;
262 }
263 
264 bool visit_type_int16(Visitor *v, const char *name, int16_t *obj,
265                       Error **errp)
266 {
267     int64_t value;
268     bool ok;
269 
270     trace_visit_type_int16(v, name, obj);
271     value = *obj;
272     ok = visit_type_intN(v, &value, name, INT16_MIN, INT16_MAX, "int16_t",
273                          errp);
274     *obj = value;
275     return ok;
276 }
277 
278 bool visit_type_int32(Visitor *v, const char *name, int32_t *obj,
279                       Error **errp)
280 {
281     int64_t value;
282     bool ok;
283 
284     trace_visit_type_int32(v, name, obj);
285     value = *obj;
286     ok = visit_type_intN(v, &value, name, INT32_MIN, INT32_MAX, "int32_t",
287                         errp);
288     *obj = value;
289     return ok;
290 }
291 
292 bool visit_type_int64(Visitor *v, const char *name, int64_t *obj,
293                       Error **errp)
294 {
295     assert(obj);
296     trace_visit_type_int64(v, name, obj);
297     return v->type_int64(v, name, obj, errp);
298 }
299 
300 bool visit_type_size(Visitor *v, const char *name, uint64_t *obj,
301                      Error **errp)
302 {
303     assert(obj);
304     trace_visit_type_size(v, name, obj);
305     if (v->type_size) {
306         return v->type_size(v, name, obj, errp);
307     }
308     return v->type_uint64(v, name, obj, errp);
309 }
310 
311 bool visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp)
312 {
313     assert(obj);
314     trace_visit_type_bool(v, name, obj);
315     return v->type_bool(v, name, obj, errp);
316 }
317 
318 bool visit_type_str(Visitor *v, const char *name, char **obj, Error **errp)
319 {
320     bool ok;
321 
322     assert(obj);
323     /* TODO: Fix callers to not pass NULL when they mean "", so that we
324      * can enable:
325     assert(!(v->type & VISITOR_OUTPUT) || *obj);
326      */
327     trace_visit_type_str(v, name, obj);
328     ok = v->type_str(v, name, obj, errp);
329     if (v->type & VISITOR_INPUT) {
330         assert(ok != !*obj);
331     }
332     return ok;
333 }
334 
335 bool visit_type_number(Visitor *v, const char *name, double *obj,
336                        Error **errp)
337 {
338     assert(obj);
339     trace_visit_type_number(v, name, obj);
340     return v->type_number(v, name, obj, errp);
341 }
342 
343 bool visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp)
344 {
345     bool ok;
346 
347     assert(obj);
348     assert(v->type != VISITOR_OUTPUT || *obj);
349     trace_visit_type_any(v, name, obj);
350     ok = v->type_any(v, name, obj, errp);
351     if (v->type == VISITOR_INPUT) {
352         assert(ok != !*obj);
353     }
354     return ok;
355 }
356 
357 bool visit_type_null(Visitor *v, const char *name, QNull **obj,
358                      Error **errp)
359 {
360     trace_visit_type_null(v, name, obj);
361     return v->type_null(v, name, obj, errp);
362 }
363 
364 static bool output_type_enum(Visitor *v, const char *name, int *obj,
365                              const QEnumLookup *lookup, Error **errp)
366 {
367     int value = *obj;
368     char *enum_str;
369 
370     enum_str = (char *)qapi_enum_lookup(lookup, value);
371     return visit_type_str(v, name, &enum_str, errp);
372 }
373 
374 static bool input_type_enum(Visitor *v, const char *name, int *obj,
375                             const QEnumLookup *lookup, Error **errp)
376 {
377     int64_t value;
378     char *enum_str;
379 
380     if (!visit_type_str(v, name, &enum_str, errp)) {
381         return false;
382     }
383 
384     value = qapi_enum_parse(lookup, enum_str, -1, NULL);
385     if (value < 0) {
386         error_setg(errp, QERR_INVALID_PARAMETER, enum_str);
387         g_free(enum_str);
388         return false;
389     }
390 
391     g_free(enum_str);
392     *obj = value;
393     return true;
394 }
395 
396 bool visit_type_enum(Visitor *v, const char *name, int *obj,
397                      const QEnumLookup *lookup, Error **errp)
398 {
399     assert(obj && lookup);
400     trace_visit_type_enum(v, name, obj);
401     switch (v->type) {
402     case VISITOR_INPUT:
403         return input_type_enum(v, name, obj, lookup, errp);
404     case VISITOR_OUTPUT:
405         return output_type_enum(v, name, obj, lookup, errp);
406     case VISITOR_CLONE:
407         /* nothing further to do, scalar value was already copied by
408          * g_memdup() during visit_start_*() */
409         return true;
410     case VISITOR_DEALLOC:
411         /* nothing to deallocate for a scalar */
412         return true;
413     default:
414         abort();
415     }
416 }
417