xref: /qemu/qapi/qobject-output-visitor.c (revision 57df0dff)
1b3db211fSDaniel P. Berrange /*
2b3db211fSDaniel P. Berrange  * Core Definitions for QAPI/QMP Command Registry
3b3db211fSDaniel P. Berrange  *
4b3db211fSDaniel P. Berrange  * Copyright (C) 2012-2016 Red Hat, Inc.
5b3db211fSDaniel P. Berrange  * Copyright IBM, Corp. 2011
6b3db211fSDaniel P. Berrange  *
7b3db211fSDaniel P. Berrange  * Authors:
8b3db211fSDaniel P. Berrange  *  Anthony Liguori   <aliguori@us.ibm.com>
9b3db211fSDaniel P. Berrange  *
10b3db211fSDaniel P. Berrange  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
11b3db211fSDaniel P. Berrange  * See the COPYING.LIB file in the top-level directory.
12b3db211fSDaniel P. Berrange  *
13b3db211fSDaniel P. Berrange  */
14b3db211fSDaniel P. Berrange 
15b3db211fSDaniel P. Berrange #include "qemu/osdep.h"
16a1307285SMarkus Armbruster #include "qapi/compat-policy.h"
17b3db211fSDaniel P. Berrange #include "qapi/qobject-output-visitor.h"
18b3db211fSDaniel P. Berrange #include "qapi/visitor-impl.h"
19b3db211fSDaniel P. Berrange #include "qemu/queue.h"
206b673957SMarkus Armbruster #include "qapi/qmp/qbool.h"
21452fcdbcSMarkus Armbruster #include "qapi/qmp/qdict.h"
2247e6b297SMarkus Armbruster #include "qapi/qmp/qlist.h"
2315280c36SMarkus Armbruster #include "qapi/qmp/qnull.h"
2415280c36SMarkus Armbruster #include "qapi/qmp/qnum.h"
256b673957SMarkus Armbruster #include "qapi/qmp/qstring.h"
26b3db211fSDaniel P. Berrange 
277d5e199aSDaniel P. Berrange typedef struct QStackEntry {
28b3db211fSDaniel P. Berrange     QObject *value;
29b3db211fSDaniel P. Berrange     void *qapi; /* sanity check that caller uses same pointer */
30b3db211fSDaniel P. Berrange     QSLIST_ENTRY(QStackEntry) node;
31b3db211fSDaniel P. Berrange } QStackEntry;
32b3db211fSDaniel P. Berrange 
337d5e199aSDaniel P. Berrange struct QObjectOutputVisitor {
34b3db211fSDaniel P. Berrange     Visitor visitor;
3591fa93e5SMarkus Armbruster 
36b3db211fSDaniel P. Berrange     QSLIST_HEAD(, QStackEntry) stack; /* Stack of unfinished containers */
37b3db211fSDaniel P. Berrange     QObject *root; /* Root of the output visit */
38b3db211fSDaniel P. Berrange     QObject **result; /* User's storage location for result */
39b3db211fSDaniel P. Berrange };
40b3db211fSDaniel P. Berrange 
417d5e199aSDaniel P. Berrange #define qobject_output_add(qov, name, value) \
427d5e199aSDaniel P. Berrange     qobject_output_add_obj(qov, name, QOBJECT(value))
437d5e199aSDaniel P. Berrange #define qobject_output_push(qov, value, qapi) \
447d5e199aSDaniel P. Berrange     qobject_output_push_obj(qov, QOBJECT(value), qapi)
45b3db211fSDaniel P. Berrange 
to_qov(Visitor * v)467d5e199aSDaniel P. Berrange static QObjectOutputVisitor *to_qov(Visitor *v)
47b3db211fSDaniel P. Berrange {
487d5e199aSDaniel P. Berrange     return container_of(v, QObjectOutputVisitor, visitor);
49b3db211fSDaniel P. Berrange }
50b3db211fSDaniel P. Berrange 
51b3db211fSDaniel P. Berrange /* Push @value onto the stack of current QObjects being built */
qobject_output_push_obj(QObjectOutputVisitor * qov,QObject * value,void * qapi)527d5e199aSDaniel P. Berrange static void qobject_output_push_obj(QObjectOutputVisitor *qov, QObject *value,
53b3db211fSDaniel P. Berrange                                     void *qapi)
54b3db211fSDaniel P. Berrange {
55b3db211fSDaniel P. Berrange     QStackEntry *e = g_malloc0(sizeof(*e));
56b3db211fSDaniel P. Berrange 
57b3db211fSDaniel P. Berrange     assert(qov->root);
58b3db211fSDaniel P. Berrange     assert(value);
59b3db211fSDaniel P. Berrange     e->value = value;
60b3db211fSDaniel P. Berrange     e->qapi = qapi;
61b3db211fSDaniel P. Berrange     QSLIST_INSERT_HEAD(&qov->stack, e, node);
62b3db211fSDaniel P. Berrange }
63b3db211fSDaniel P. Berrange 
64b3db211fSDaniel P. Berrange /* Pop a value off the stack of QObjects being built, and return it. */
qobject_output_pop(QObjectOutputVisitor * qov,void * qapi)657d5e199aSDaniel P. Berrange static QObject *qobject_output_pop(QObjectOutputVisitor *qov, void *qapi)
66b3db211fSDaniel P. Berrange {
67b3db211fSDaniel P. Berrange     QStackEntry *e = QSLIST_FIRST(&qov->stack);
68b3db211fSDaniel P. Berrange     QObject *value;
69b3db211fSDaniel P. Berrange 
70b3db211fSDaniel P. Berrange     assert(e);
71b3db211fSDaniel P. Berrange     assert(e->qapi == qapi);
72b3db211fSDaniel P. Berrange     QSLIST_REMOVE_HEAD(&qov->stack, node);
73b3db211fSDaniel P. Berrange     value = e->value;
74b3db211fSDaniel P. Berrange     assert(value);
75b3db211fSDaniel P. Berrange     g_free(e);
76b3db211fSDaniel P. Berrange     return value;
77b3db211fSDaniel P. Berrange }
78b3db211fSDaniel P. Berrange 
79b3db211fSDaniel P. Berrange /* Add @value to the current QObject being built.
80b3db211fSDaniel P. Berrange  * If the stack is visiting a dictionary or list, @value is now owned
81b3db211fSDaniel P. Berrange  * by that container. Otherwise, @value is now the root.  */
qobject_output_add_obj(QObjectOutputVisitor * qov,const char * name,QObject * value)827d5e199aSDaniel P. Berrange static void qobject_output_add_obj(QObjectOutputVisitor *qov, const char *name,
83b3db211fSDaniel P. Berrange                                    QObject *value)
84b3db211fSDaniel P. Berrange {
85b3db211fSDaniel P. Berrange     QStackEntry *e = QSLIST_FIRST(&qov->stack);
86b3db211fSDaniel P. Berrange     QObject *cur = e ? e->value : NULL;
87b3db211fSDaniel P. Berrange 
88b3db211fSDaniel P. Berrange     if (!cur) {
89b3db211fSDaniel P. Berrange         /* Don't allow reuse of visitor on more than one root */
90b3db211fSDaniel P. Berrange         assert(!qov->root);
91b3db211fSDaniel P. Berrange         qov->root = value;
92b3db211fSDaniel P. Berrange     } else {
93b3db211fSDaniel P. Berrange         switch (qobject_type(cur)) {
94b3db211fSDaniel P. Berrange         case QTYPE_QDICT:
95b3db211fSDaniel P. Berrange             assert(name);
967dc847ebSMax Reitz             qdict_put_obj(qobject_to(QDict, cur), name, value);
97b3db211fSDaniel P. Berrange             break;
98b3db211fSDaniel P. Berrange         case QTYPE_QLIST:
99b3db211fSDaniel P. Berrange             assert(!name);
1007dc847ebSMax Reitz             qlist_append_obj(qobject_to(QList, cur), value);
101b3db211fSDaniel P. Berrange             break;
102b3db211fSDaniel P. Berrange         default:
103b3db211fSDaniel P. Berrange             g_assert_not_reached();
104b3db211fSDaniel P. Berrange         }
105b3db211fSDaniel P. Berrange     }
106b3db211fSDaniel P. Berrange }
107b3db211fSDaniel P. Berrange 
qobject_output_start_struct(Visitor * v,const char * name,void ** obj,size_t unused,Error ** errp)108012d4c96SMarkus Armbruster static bool qobject_output_start_struct(Visitor *v, const char *name,
1097d5e199aSDaniel P. Berrange                                         void **obj, size_t unused, Error **errp)
110b3db211fSDaniel P. Berrange {
1117d5e199aSDaniel P. Berrange     QObjectOutputVisitor *qov = to_qov(v);
112b3db211fSDaniel P. Berrange     QDict *dict = qdict_new();
113b3db211fSDaniel P. Berrange 
1147d5e199aSDaniel P. Berrange     qobject_output_add(qov, name, dict);
1157d5e199aSDaniel P. Berrange     qobject_output_push(qov, dict, obj);
116012d4c96SMarkus Armbruster     return true;
117b3db211fSDaniel P. Berrange }
118b3db211fSDaniel P. Berrange 
qobject_output_end_struct(Visitor * v,void ** obj)1197d5e199aSDaniel P. Berrange static void qobject_output_end_struct(Visitor *v, void **obj)
120b3db211fSDaniel P. Berrange {
1217d5e199aSDaniel P. Berrange     QObjectOutputVisitor *qov = to_qov(v);
1227d5e199aSDaniel P. Berrange     QObject *value = qobject_output_pop(qov, obj);
123b3db211fSDaniel P. Berrange     assert(qobject_type(value) == QTYPE_QDICT);
124b3db211fSDaniel P. Berrange }
125b3db211fSDaniel P. Berrange 
qobject_output_start_list(Visitor * v,const char * name,GenericList ** listp,size_t size,Error ** errp)126012d4c96SMarkus Armbruster static bool qobject_output_start_list(Visitor *v, const char *name,
127b3db211fSDaniel P. Berrange                                       GenericList **listp, size_t size,
128b3db211fSDaniel P. Berrange                                       Error **errp)
129b3db211fSDaniel P. Berrange {
1307d5e199aSDaniel P. Berrange     QObjectOutputVisitor *qov = to_qov(v);
131b3db211fSDaniel P. Berrange     QList *list = qlist_new();
132b3db211fSDaniel P. Berrange 
1337d5e199aSDaniel P. Berrange     qobject_output_add(qov, name, list);
1347d5e199aSDaniel P. Berrange     qobject_output_push(qov, list, listp);
135012d4c96SMarkus Armbruster     return true;
136b3db211fSDaniel P. Berrange }
137b3db211fSDaniel P. Berrange 
qobject_output_next_list(Visitor * v,GenericList * tail,size_t size)1387d5e199aSDaniel P. Berrange static GenericList *qobject_output_next_list(Visitor *v, GenericList *tail,
139b3db211fSDaniel P. Berrange                                              size_t size)
140b3db211fSDaniel P. Berrange {
141b3db211fSDaniel P. Berrange     return tail->next;
142b3db211fSDaniel P. Berrange }
143b3db211fSDaniel P. Berrange 
qobject_output_end_list(Visitor * v,void ** obj)1447d5e199aSDaniel P. Berrange static void qobject_output_end_list(Visitor *v, void **obj)
145b3db211fSDaniel P. Berrange {
1467d5e199aSDaniel P. Berrange     QObjectOutputVisitor *qov = to_qov(v);
1477d5e199aSDaniel P. Berrange     QObject *value = qobject_output_pop(qov, obj);
148b3db211fSDaniel P. Berrange     assert(qobject_type(value) == QTYPE_QLIST);
149b3db211fSDaniel P. Berrange }
150b3db211fSDaniel P. Berrange 
qobject_output_type_int64(Visitor * v,const char * name,int64_t * obj,Error ** errp)151012d4c96SMarkus Armbruster static bool qobject_output_type_int64(Visitor *v, const char *name,
1527d5e199aSDaniel P. Berrange                                       int64_t *obj, Error **errp)
153b3db211fSDaniel P. Berrange {
1547d5e199aSDaniel P. Berrange     QObjectOutputVisitor *qov = to_qov(v);
15501b2ffceSMarc-André Lureau     qobject_output_add(qov, name, qnum_from_int(*obj));
156012d4c96SMarkus Armbruster     return true;
157b3db211fSDaniel P. Berrange }
158b3db211fSDaniel P. Berrange 
qobject_output_type_uint64(Visitor * v,const char * name,uint64_t * obj,Error ** errp)159012d4c96SMarkus Armbruster static bool qobject_output_type_uint64(Visitor *v, const char *name,
1607d5e199aSDaniel P. Berrange                                        uint64_t *obj, Error **errp)
161b3db211fSDaniel P. Berrange {
1627d5e199aSDaniel P. Berrange     QObjectOutputVisitor *qov = to_qov(v);
1635923f85fSMarc-André Lureau     qobject_output_add(qov, name, qnum_from_uint(*obj));
164012d4c96SMarkus Armbruster     return true;
165b3db211fSDaniel P. Berrange }
166b3db211fSDaniel P. Berrange 
qobject_output_type_bool(Visitor * v,const char * name,bool * obj,Error ** errp)167012d4c96SMarkus Armbruster static bool qobject_output_type_bool(Visitor *v, const char *name, bool *obj,
168b3db211fSDaniel P. Berrange                                      Error **errp)
169b3db211fSDaniel P. Berrange {
1707d5e199aSDaniel P. Berrange     QObjectOutputVisitor *qov = to_qov(v);
1717d5e199aSDaniel P. Berrange     qobject_output_add(qov, name, qbool_from_bool(*obj));
172012d4c96SMarkus Armbruster     return true;
173b3db211fSDaniel P. Berrange }
174b3db211fSDaniel P. Berrange 
qobject_output_type_str(Visitor * v,const char * name,char ** obj,Error ** errp)175012d4c96SMarkus Armbruster static bool qobject_output_type_str(Visitor *v, const char *name, char **obj,
176b3db211fSDaniel P. Berrange                                     Error **errp)
177b3db211fSDaniel P. Berrange {
1787d5e199aSDaniel P. Berrange     QObjectOutputVisitor *qov = to_qov(v);
179b3db211fSDaniel P. Berrange     if (*obj) {
1807d5e199aSDaniel P. Berrange         qobject_output_add(qov, name, qstring_from_str(*obj));
181b3db211fSDaniel P. Berrange     } else {
1827d5e199aSDaniel P. Berrange         qobject_output_add(qov, name, qstring_from_str(""));
183b3db211fSDaniel P. Berrange     }
184012d4c96SMarkus Armbruster     return true;
185b3db211fSDaniel P. Berrange }
186b3db211fSDaniel P. Berrange 
qobject_output_type_number(Visitor * v,const char * name,double * obj,Error ** errp)187012d4c96SMarkus Armbruster static bool qobject_output_type_number(Visitor *v, const char *name,
1887d5e199aSDaniel P. Berrange                                        double *obj, Error **errp)
189b3db211fSDaniel P. Berrange {
1907d5e199aSDaniel P. Berrange     QObjectOutputVisitor *qov = to_qov(v);
19101b2ffceSMarc-André Lureau     qobject_output_add(qov, name, qnum_from_double(*obj));
192012d4c96SMarkus Armbruster     return true;
193b3db211fSDaniel P. Berrange }
194b3db211fSDaniel P. Berrange 
qobject_output_type_any(Visitor * v,const char * name,QObject ** obj,Error ** errp)195012d4c96SMarkus Armbruster static bool qobject_output_type_any(Visitor *v, const char *name,
1967d5e199aSDaniel P. Berrange                                     QObject **obj, Error **errp)
197b3db211fSDaniel P. Berrange {
1987d5e199aSDaniel P. Berrange     QObjectOutputVisitor *qov = to_qov(v);
199f5a74a5aSMarc-André Lureau 
200f5a74a5aSMarc-André Lureau     qobject_output_add_obj(qov, name, qobject_ref(*obj));
201012d4c96SMarkus Armbruster     return true;
202b3db211fSDaniel P. Berrange }
203b3db211fSDaniel P. Berrange 
qobject_output_type_null(Visitor * v,const char * name,QNull ** obj,Error ** errp)204012d4c96SMarkus Armbruster static bool qobject_output_type_null(Visitor *v, const char *name,
205d2f95f4dSMarkus Armbruster                                      QNull **obj, Error **errp)
206b3db211fSDaniel P. Berrange {
2077d5e199aSDaniel P. Berrange     QObjectOutputVisitor *qov = to_qov(v);
208006ca09fSMarkus Armbruster     qobject_output_add(qov, name, qnull());
209012d4c96SMarkus Armbruster     return true;
210b3db211fSDaniel P. Berrange }
211b3db211fSDaniel P. Berrange 
qobject_output_policy_skip(Visitor * v,const char * name,unsigned special_features)212a1307285SMarkus Armbruster static bool qobject_output_policy_skip(Visitor *v, const char *name,
213a1307285SMarkus Armbruster                                        unsigned special_features)
21491fa93e5SMarkus Armbruster {
215*57df0dffSMarkus Armbruster     CompatPolicy *pol = &v->compat_policy;
216*57df0dffSMarkus Armbruster 
217*57df0dffSMarkus Armbruster     return ((special_features & 1u << QAPI_DEPRECATED)
218*57df0dffSMarkus Armbruster             && pol->deprecated_output == COMPAT_POLICY_OUTPUT_HIDE)
219*57df0dffSMarkus Armbruster         || ((special_features & 1u << QAPI_UNSTABLE)
220*57df0dffSMarkus Armbruster             && pol->unstable_output == COMPAT_POLICY_OUTPUT_HIDE);
22191fa93e5SMarkus Armbruster }
22291fa93e5SMarkus Armbruster 
223b3db211fSDaniel P. Berrange /* Finish building, and return the root object.
224b3db211fSDaniel P. Berrange  * The root object is never null. The caller becomes the object's
225cb3e7f08SMarc-André Lureau  * owner, and should use qobject_unref() when done with it.  */
qobject_output_complete(Visitor * v,void * opaque)2267d5e199aSDaniel P. Berrange static void qobject_output_complete(Visitor *v, void *opaque)
227b3db211fSDaniel P. Berrange {
2287d5e199aSDaniel P. Berrange     QObjectOutputVisitor *qov = to_qov(v);
229b3db211fSDaniel P. Berrange 
230b3db211fSDaniel P. Berrange     /* A visit must have occurred, with each start paired with end.  */
231b3db211fSDaniel P. Berrange     assert(qov->root && QSLIST_EMPTY(&qov->stack));
232b3db211fSDaniel P. Berrange     assert(opaque == qov->result);
233b3db211fSDaniel P. Berrange 
234f5a74a5aSMarc-André Lureau     *qov->result = qobject_ref(qov->root);
235b3db211fSDaniel P. Berrange     qov->result = NULL;
236b3db211fSDaniel P. Berrange }
237b3db211fSDaniel P. Berrange 
qobject_output_free(Visitor * v)2387d5e199aSDaniel P. Berrange static void qobject_output_free(Visitor *v)
239b3db211fSDaniel P. Berrange {
2407d5e199aSDaniel P. Berrange     QObjectOutputVisitor *qov = to_qov(v);
241b3db211fSDaniel P. Berrange     QStackEntry *e;
242b3db211fSDaniel P. Berrange 
243b3db211fSDaniel P. Berrange     while (!QSLIST_EMPTY(&qov->stack)) {
244b3db211fSDaniel P. Berrange         e = QSLIST_FIRST(&qov->stack);
245b3db211fSDaniel P. Berrange         QSLIST_REMOVE_HEAD(&qov->stack, node);
246b3db211fSDaniel P. Berrange         g_free(e);
247b3db211fSDaniel P. Berrange     }
248b3db211fSDaniel P. Berrange 
249cb3e7f08SMarc-André Lureau     qobject_unref(qov->root);
250b3db211fSDaniel P. Berrange     g_free(qov);
251b3db211fSDaniel P. Berrange }
252b3db211fSDaniel P. Berrange 
qobject_output_visitor_new(QObject ** result)2537d5e199aSDaniel P. Berrange Visitor *qobject_output_visitor_new(QObject **result)
254b3db211fSDaniel P. Berrange {
2557d5e199aSDaniel P. Berrange     QObjectOutputVisitor *v;
256b3db211fSDaniel P. Berrange 
257b3db211fSDaniel P. Berrange     v = g_malloc0(sizeof(*v));
258b3db211fSDaniel P. Berrange 
259b3db211fSDaniel P. Berrange     v->visitor.type = VISITOR_OUTPUT;
2607d5e199aSDaniel P. Berrange     v->visitor.start_struct = qobject_output_start_struct;
2617d5e199aSDaniel P. Berrange     v->visitor.end_struct = qobject_output_end_struct;
2627d5e199aSDaniel P. Berrange     v->visitor.start_list = qobject_output_start_list;
2637d5e199aSDaniel P. Berrange     v->visitor.next_list = qobject_output_next_list;
2647d5e199aSDaniel P. Berrange     v->visitor.end_list = qobject_output_end_list;
2657d5e199aSDaniel P. Berrange     v->visitor.type_int64 = qobject_output_type_int64;
2667d5e199aSDaniel P. Berrange     v->visitor.type_uint64 = qobject_output_type_uint64;
2677d5e199aSDaniel P. Berrange     v->visitor.type_bool = qobject_output_type_bool;
2687d5e199aSDaniel P. Berrange     v->visitor.type_str = qobject_output_type_str;
2697d5e199aSDaniel P. Berrange     v->visitor.type_number = qobject_output_type_number;
2707d5e199aSDaniel P. Berrange     v->visitor.type_any = qobject_output_type_any;
2717d5e199aSDaniel P. Berrange     v->visitor.type_null = qobject_output_type_null;
272a1307285SMarkus Armbruster     v->visitor.policy_skip = qobject_output_policy_skip;
2737d5e199aSDaniel P. Berrange     v->visitor.complete = qobject_output_complete;
2747d5e199aSDaniel P. Berrange     v->visitor.free = qobject_output_free;
275b3db211fSDaniel P. Berrange 
276b3db211fSDaniel P. Berrange     *result = NULL;
277b3db211fSDaniel P. Berrange     v->result = result;
278b3db211fSDaniel P. Berrange 
279b3db211fSDaniel P. Berrange     return &v->visitor;
280b3db211fSDaniel P. Berrange }
281