xref: /qemu/qapi/qobject-output-visitor.c (revision b21e2380)
1 /*
2  * Core Definitions for QAPI/QMP Command Registry
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/compat-policy.h"
17 #include "qapi/qobject-output-visitor.h"
18 #include "qapi/visitor-impl.h"
19 #include "qemu/queue.h"
20 #include "qapi/qmp/qbool.h"
21 #include "qapi/qmp/qdict.h"
22 #include "qapi/qmp/qlist.h"
23 #include "qapi/qmp/qnull.h"
24 #include "qapi/qmp/qnum.h"
25 #include "qapi/qmp/qstring.h"
26 
27 typedef struct QStackEntry {
28     QObject *value;
29     void *qapi; /* sanity check that caller uses same pointer */
30     QSLIST_ENTRY(QStackEntry) node;
31 } QStackEntry;
32 
33 struct QObjectOutputVisitor {
34     Visitor visitor;
35 
36     QSLIST_HEAD(, QStackEntry) stack; /* Stack of unfinished containers */
37     QObject *root; /* Root of the output visit */
38     QObject **result; /* User's storage location for result */
39 };
40 
41 #define qobject_output_add(qov, name, value) \
42     qobject_output_add_obj(qov, name, QOBJECT(value))
43 #define qobject_output_push(qov, value, qapi) \
44     qobject_output_push_obj(qov, QOBJECT(value), qapi)
45 
46 static QObjectOutputVisitor *to_qov(Visitor *v)
47 {
48     return container_of(v, QObjectOutputVisitor, visitor);
49 }
50 
51 /* Push @value onto the stack of current QObjects being built */
52 static void qobject_output_push_obj(QObjectOutputVisitor *qov, QObject *value,
53                                     void *qapi)
54 {
55     QStackEntry *e = g_malloc0(sizeof(*e));
56 
57     assert(qov->root);
58     assert(value);
59     e->value = value;
60     e->qapi = qapi;
61     QSLIST_INSERT_HEAD(&qov->stack, e, node);
62 }
63 
64 /* Pop a value off the stack of QObjects being built, and return it. */
65 static QObject *qobject_output_pop(QObjectOutputVisitor *qov, void *qapi)
66 {
67     QStackEntry *e = QSLIST_FIRST(&qov->stack);
68     QObject *value;
69 
70     assert(e);
71     assert(e->qapi == qapi);
72     QSLIST_REMOVE_HEAD(&qov->stack, node);
73     value = e->value;
74     assert(value);
75     g_free(e);
76     return value;
77 }
78 
79 /* Add @value to the current QObject being built.
80  * If the stack is visiting a dictionary or list, @value is now owned
81  * by that container. Otherwise, @value is now the root.  */
82 static void qobject_output_add_obj(QObjectOutputVisitor *qov, const char *name,
83                                    QObject *value)
84 {
85     QStackEntry *e = QSLIST_FIRST(&qov->stack);
86     QObject *cur = e ? e->value : NULL;
87 
88     if (!cur) {
89         /* Don't allow reuse of visitor on more than one root */
90         assert(!qov->root);
91         qov->root = value;
92     } else {
93         switch (qobject_type(cur)) {
94         case QTYPE_QDICT:
95             assert(name);
96             qdict_put_obj(qobject_to(QDict, cur), name, value);
97             break;
98         case QTYPE_QLIST:
99             assert(!name);
100             qlist_append_obj(qobject_to(QList, cur), value);
101             break;
102         default:
103             g_assert_not_reached();
104         }
105     }
106 }
107 
108 static bool qobject_output_start_struct(Visitor *v, const char *name,
109                                         void **obj, size_t unused, Error **errp)
110 {
111     QObjectOutputVisitor *qov = to_qov(v);
112     QDict *dict = qdict_new();
113 
114     qobject_output_add(qov, name, dict);
115     qobject_output_push(qov, dict, obj);
116     return true;
117 }
118 
119 static void qobject_output_end_struct(Visitor *v, void **obj)
120 {
121     QObjectOutputVisitor *qov = to_qov(v);
122     QObject *value = qobject_output_pop(qov, obj);
123     assert(qobject_type(value) == QTYPE_QDICT);
124 }
125 
126 static bool qobject_output_start_list(Visitor *v, const char *name,
127                                       GenericList **listp, size_t size,
128                                       Error **errp)
129 {
130     QObjectOutputVisitor *qov = to_qov(v);
131     QList *list = qlist_new();
132 
133     qobject_output_add(qov, name, list);
134     qobject_output_push(qov, list, listp);
135     return true;
136 }
137 
138 static GenericList *qobject_output_next_list(Visitor *v, GenericList *tail,
139                                              size_t size)
140 {
141     return tail->next;
142 }
143 
144 static void qobject_output_end_list(Visitor *v, void **obj)
145 {
146     QObjectOutputVisitor *qov = to_qov(v);
147     QObject *value = qobject_output_pop(qov, obj);
148     assert(qobject_type(value) == QTYPE_QLIST);
149 }
150 
151 static bool qobject_output_type_int64(Visitor *v, const char *name,
152                                       int64_t *obj, Error **errp)
153 {
154     QObjectOutputVisitor *qov = to_qov(v);
155     qobject_output_add(qov, name, qnum_from_int(*obj));
156     return true;
157 }
158 
159 static bool qobject_output_type_uint64(Visitor *v, const char *name,
160                                        uint64_t *obj, Error **errp)
161 {
162     QObjectOutputVisitor *qov = to_qov(v);
163     qobject_output_add(qov, name, qnum_from_uint(*obj));
164     return true;
165 }
166 
167 static bool qobject_output_type_bool(Visitor *v, const char *name, bool *obj,
168                                      Error **errp)
169 {
170     QObjectOutputVisitor *qov = to_qov(v);
171     qobject_output_add(qov, name, qbool_from_bool(*obj));
172     return true;
173 }
174 
175 static bool qobject_output_type_str(Visitor *v, const char *name, char **obj,
176                                     Error **errp)
177 {
178     QObjectOutputVisitor *qov = to_qov(v);
179     if (*obj) {
180         qobject_output_add(qov, name, qstring_from_str(*obj));
181     } else {
182         qobject_output_add(qov, name, qstring_from_str(""));
183     }
184     return true;
185 }
186 
187 static bool qobject_output_type_number(Visitor *v, const char *name,
188                                        double *obj, Error **errp)
189 {
190     QObjectOutputVisitor *qov = to_qov(v);
191     qobject_output_add(qov, name, qnum_from_double(*obj));
192     return true;
193 }
194 
195 static bool qobject_output_type_any(Visitor *v, const char *name,
196                                     QObject **obj, Error **errp)
197 {
198     QObjectOutputVisitor *qov = to_qov(v);
199 
200     qobject_output_add_obj(qov, name, qobject_ref(*obj));
201     return true;
202 }
203 
204 static bool qobject_output_type_null(Visitor *v, const char *name,
205                                      QNull **obj, Error **errp)
206 {
207     QObjectOutputVisitor *qov = to_qov(v);
208     qobject_output_add(qov, name, qnull());
209     return true;
210 }
211 
212 static bool qobject_output_policy_skip(Visitor *v, const char *name,
213                                        unsigned special_features)
214 {
215     CompatPolicy *pol = &v->compat_policy;
216 
217     return ((special_features & 1u << QAPI_DEPRECATED)
218             && pol->deprecated_output == COMPAT_POLICY_OUTPUT_HIDE)
219         || ((special_features & 1u << QAPI_UNSTABLE)
220             && pol->unstable_output == COMPAT_POLICY_OUTPUT_HIDE);
221 }
222 
223 /* Finish building, and return the root object.
224  * The root object is never null. The caller becomes the object's
225  * owner, and should use qobject_unref() when done with it.  */
226 static void qobject_output_complete(Visitor *v, void *opaque)
227 {
228     QObjectOutputVisitor *qov = to_qov(v);
229 
230     /* A visit must have occurred, with each start paired with end.  */
231     assert(qov->root && QSLIST_EMPTY(&qov->stack));
232     assert(opaque == qov->result);
233 
234     *qov->result = qobject_ref(qov->root);
235     qov->result = NULL;
236 }
237 
238 static void qobject_output_free(Visitor *v)
239 {
240     QObjectOutputVisitor *qov = to_qov(v);
241     QStackEntry *e;
242 
243     while (!QSLIST_EMPTY(&qov->stack)) {
244         e = QSLIST_FIRST(&qov->stack);
245         QSLIST_REMOVE_HEAD(&qov->stack, node);
246         g_free(e);
247     }
248 
249     qobject_unref(qov->root);
250     g_free(qov);
251 }
252 
253 Visitor *qobject_output_visitor_new(QObject **result)
254 {
255     QObjectOutputVisitor *v;
256 
257     v = g_malloc0(sizeof(*v));
258 
259     v->visitor.type = VISITOR_OUTPUT;
260     v->visitor.start_struct = qobject_output_start_struct;
261     v->visitor.end_struct = qobject_output_end_struct;
262     v->visitor.start_list = qobject_output_start_list;
263     v->visitor.next_list = qobject_output_next_list;
264     v->visitor.end_list = qobject_output_end_list;
265     v->visitor.type_int64 = qobject_output_type_int64;
266     v->visitor.type_uint64 = qobject_output_type_uint64;
267     v->visitor.type_bool = qobject_output_type_bool;
268     v->visitor.type_str = qobject_output_type_str;
269     v->visitor.type_number = qobject_output_type_number;
270     v->visitor.type_any = qobject_output_type_any;
271     v->visitor.type_null = qobject_output_type_null;
272     v->visitor.policy_skip = qobject_output_policy_skip;
273     v->visitor.complete = qobject_output_complete;
274     v->visitor.free = qobject_output_free;
275 
276     *result = NULL;
277     v->result = result;
278 
279     return &v->visitor;
280 }
281