qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

qobject-output-visitor.c (8501B)


      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 }