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