qobject-output-visitor.c 7.6 KB
Newer Older
M
Michael Roth 已提交
1 2 3
/*
 * Core Definitions for QAPI/QMP Command Registry
 *
4
 * Copyright (C) 2012-2016 Red Hat, Inc.
M
Michael Roth 已提交
5 6 7 8 9 10 11 12 13 14
 * Copyright IBM, Corp. 2011
 *
 * Authors:
 *  Anthony Liguori   <aliguori@us.ibm.com>
 *
 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 * See the COPYING.LIB file in the top-level directory.
 *
 */

P
Peter Maydell 已提交
15
#include "qemu/osdep.h"
16
#include "qapi/qobject-output-visitor.h"
17
#include "qapi/visitor-impl.h"
18
#include "qemu/queue.h"
M
Michael Roth 已提交
19
#include "qemu-common.h"
M
Markus Armbruster 已提交
20 21
#include "qapi/qmp/qbool.h"
#include "qapi/qmp/qstring.h"
M
Michael Roth 已提交
22

23
typedef struct QStackEntry {
M
Michael Roth 已提交
24
    QObject *value;
E
Eric Blake 已提交
25
    void *qapi; /* sanity check that caller uses same pointer */
26
    QSLIST_ENTRY(QStackEntry) node;
M
Michael Roth 已提交
27 28
} QStackEntry;

29
struct QObjectOutputVisitor {
M
Michael Roth 已提交
30
    Visitor visitor;
31
    QSLIST_HEAD(, QStackEntry) stack; /* Stack of unfinished containers */
32
    QObject *root; /* Root of the output visit */
33
    QObject **result; /* User's storage location for result */
M
Michael Roth 已提交
34 35
};

36 37 38 39
#define qobject_output_add(qov, name, value) \
    qobject_output_add_obj(qov, name, QOBJECT(value))
#define qobject_output_push(qov, value, qapi) \
    qobject_output_push_obj(qov, QOBJECT(value), qapi)
M
Michael Roth 已提交
40

41
static QObjectOutputVisitor *to_qov(Visitor *v)
M
Michael Roth 已提交
42
{
43
    return container_of(v, QObjectOutputVisitor, visitor);
M
Michael Roth 已提交
44 45
}

46
/* Push @value onto the stack of current QObjects being built */
47 48
static void qobject_output_push_obj(QObjectOutputVisitor *qov, QObject *value,
                                    void *qapi)
M
Michael Roth 已提交
49
{
50
    QStackEntry *e = g_malloc0(sizeof(*e));
M
Michael Roth 已提交
51

52
    assert(qov->root);
53
    assert(value);
M
Michael Roth 已提交
54
    e->value = value;
E
Eric Blake 已提交
55
    e->qapi = qapi;
56
    QSLIST_INSERT_HEAD(&qov->stack, e, node);
M
Michael Roth 已提交
57 58
}

59
/* Pop a value off the stack of QObjects being built, and return it. */
60
static QObject *qobject_output_pop(QObjectOutputVisitor *qov, void *qapi)
M
Michael Roth 已提交
61
{
62
    QStackEntry *e = QSLIST_FIRST(&qov->stack);
M
Michael Roth 已提交
63
    QObject *value;
64 65

    assert(e);
E
Eric Blake 已提交
66
    assert(e->qapi == qapi);
67
    QSLIST_REMOVE_HEAD(&qov->stack, node);
M
Michael Roth 已提交
68
    value = e->value;
69
    assert(value);
70
    g_free(e);
M
Michael Roth 已提交
71 72 73
    return value;
}

74 75 76
/* Add @value to the current QObject being built.
 * If the stack is visiting a dictionary or list, @value is now owned
 * by that container. Otherwise, @value is now the root.  */
77 78
static void qobject_output_add_obj(QObjectOutputVisitor *qov, const char *name,
                                   QObject *value)
M
Michael Roth 已提交
79
{
80
    QStackEntry *e = QSLIST_FIRST(&qov->stack);
81
    QObject *cur = e ? e->value : NULL;
M
Michael Roth 已提交
82

83
    if (!cur) {
E
Eric Blake 已提交
84 85
        /* Don't allow reuse of visitor on more than one root */
        assert(!qov->root);
86 87 88 89 90 91 92 93
        qov->root = value;
    } else {
        switch (qobject_type(cur)) {
        case QTYPE_QDICT:
            assert(name);
            qdict_put_obj(qobject_to_qdict(cur), name, value);
            break;
        case QTYPE_QLIST:
E
Eric Blake 已提交
94
            assert(!name);
95 96 97 98 99
            qlist_append_obj(qobject_to_qlist(cur), value);
            break;
        default:
            g_assert_not_reached();
        }
M
Michael Roth 已提交
100 101 102
    }
}

103 104
static void qobject_output_start_struct(Visitor *v, const char *name,
                                        void **obj, size_t unused, Error **errp)
M
Michael Roth 已提交
105
{
106
    QObjectOutputVisitor *qov = to_qov(v);
M
Michael Roth 已提交
107 108
    QDict *dict = qdict_new();

109 110
    qobject_output_add(qov, name, dict);
    qobject_output_push(qov, dict, obj);
M
Michael Roth 已提交
111 112
}

113
static void qobject_output_end_struct(Visitor *v, void **obj)
M
Michael Roth 已提交
114
{
115 116
    QObjectOutputVisitor *qov = to_qov(v);
    QObject *value = qobject_output_pop(qov, obj);
E
Eric Blake 已提交
117
    assert(qobject_type(value) == QTYPE_QDICT);
M
Michael Roth 已提交
118 119
}

120 121 122
static void qobject_output_start_list(Visitor *v, const char *name,
                                      GenericList **listp, size_t size,
                                      Error **errp)
M
Michael Roth 已提交
123
{
124
    QObjectOutputVisitor *qov = to_qov(v);
M
Michael Roth 已提交
125 126
    QList *list = qlist_new();

127 128
    qobject_output_add(qov, name, list);
    qobject_output_push(qov, list, listp);
M
Michael Roth 已提交
129 130
}

131 132
static GenericList *qobject_output_next_list(Visitor *v, GenericList *tail,
                                             size_t size)
M
Michael Roth 已提交
133
{
134
    return tail->next;
M
Michael Roth 已提交
135 136
}

137
static void qobject_output_end_list(Visitor *v, void **obj)
M
Michael Roth 已提交
138
{
139 140
    QObjectOutputVisitor *qov = to_qov(v);
    QObject *value = qobject_output_pop(qov, obj);
E
Eric Blake 已提交
141
    assert(qobject_type(value) == QTYPE_QLIST);
M
Michael Roth 已提交
142 143
}

144 145
static void qobject_output_type_int64(Visitor *v, const char *name,
                                      int64_t *obj, Error **errp)
M
Michael Roth 已提交
146
{
147
    QObjectOutputVisitor *qov = to_qov(v);
148
    qobject_output_add(qov, name, qnum_from_int(*obj));
M
Michael Roth 已提交
149 150
}

151 152
static void qobject_output_type_uint64(Visitor *v, const char *name,
                                       uint64_t *obj, Error **errp)
153
{
154
    QObjectOutputVisitor *qov = to_qov(v);
155
    qobject_output_add(qov, name, qnum_from_uint(*obj));
156 157
}

158 159
static void qobject_output_type_bool(Visitor *v, const char *name, bool *obj,
                                     Error **errp)
M
Michael Roth 已提交
160
{
161 162
    QObjectOutputVisitor *qov = to_qov(v);
    qobject_output_add(qov, name, qbool_from_bool(*obj));
M
Michael Roth 已提交
163 164
}

165 166
static void qobject_output_type_str(Visitor *v, const char *name, char **obj,
                                    Error **errp)
M
Michael Roth 已提交
167
{
168
    QObjectOutputVisitor *qov = to_qov(v);
M
Michael Roth 已提交
169
    if (*obj) {
170
        qobject_output_add(qov, name, qstring_from_str(*obj));
M
Michael Roth 已提交
171
    } else {
172
        qobject_output_add(qov, name, qstring_from_str(""));
M
Michael Roth 已提交
173 174 175
    }
}

176 177
static void qobject_output_type_number(Visitor *v, const char *name,
                                       double *obj, Error **errp)
M
Michael Roth 已提交
178
{
179
    QObjectOutputVisitor *qov = to_qov(v);
180
    qobject_output_add(qov, name, qnum_from_double(*obj));
M
Michael Roth 已提交
181 182
}

183 184
static void qobject_output_type_any(Visitor *v, const char *name,
                                    QObject **obj, Error **errp)
185
{
186
    QObjectOutputVisitor *qov = to_qov(v);
187
    qobject_incref(*obj);
188
    qobject_output_add_obj(qov, name, *obj);
189 190
}

191 192
static void qobject_output_type_null(Visitor *v, const char *name,
                                     QNull **obj, Error **errp)
E
Eric Blake 已提交
193
{
194
    QObjectOutputVisitor *qov = to_qov(v);
195
    qobject_output_add(qov, name, qnull());
E
Eric Blake 已提交
196 197
}

E
Eric Blake 已提交
198 199 200
/* Finish building, and return the root object.
 * The root object is never null. The caller becomes the object's
 * owner, and should use qobject_decref() when done with it.  */
201
static void qobject_output_complete(Visitor *v, void *opaque)
M
Michael Roth 已提交
202
{
203
    QObjectOutputVisitor *qov = to_qov(v);
204

E
Eric Blake 已提交
205
    /* A visit must have occurred, with each start paired with end.  */
206
    assert(qov->root && QSLIST_EMPTY(&qov->stack));
207
    assert(opaque == qov->result);
E
Eric Blake 已提交
208 209

    qobject_incref(qov->root);
210 211
    *qov->result = qov->root;
    qov->result = NULL;
M
Michael Roth 已提交
212 213
}

214
static void qobject_output_free(Visitor *v)
E
Eric Blake 已提交
215
{
216
    QObjectOutputVisitor *qov = to_qov(v);
217
    QStackEntry *e;
M
Michael Roth 已提交
218

219 220 221
    while (!QSLIST_EMPTY(&qov->stack)) {
        e = QSLIST_FIRST(&qov->stack);
        QSLIST_REMOVE_HEAD(&qov->stack, node);
222
        g_free(e);
M
Michael Roth 已提交
223 224
    }

225 226
    qobject_decref(qov->root);
    g_free(qov);
M
Michael Roth 已提交
227 228
}

229
Visitor *qobject_output_visitor_new(QObject **result)
M
Michael Roth 已提交
230
{
231
    QObjectOutputVisitor *v;
M
Michael Roth 已提交
232

233
    v = g_malloc0(sizeof(*v));
M
Michael Roth 已提交
234

235
    v->visitor.type = VISITOR_OUTPUT;
236 237 238 239 240 241 242 243 244 245 246 247 248 249
    v->visitor.start_struct = qobject_output_start_struct;
    v->visitor.end_struct = qobject_output_end_struct;
    v->visitor.start_list = qobject_output_start_list;
    v->visitor.next_list = qobject_output_next_list;
    v->visitor.end_list = qobject_output_end_list;
    v->visitor.type_int64 = qobject_output_type_int64;
    v->visitor.type_uint64 = qobject_output_type_uint64;
    v->visitor.type_bool = qobject_output_type_bool;
    v->visitor.type_str = qobject_output_type_str;
    v->visitor.type_number = qobject_output_type_number;
    v->visitor.type_any = qobject_output_type_any;
    v->visitor.type_null = qobject_output_type_null;
    v->visitor.complete = qobject_output_complete;
    v->visitor.free = qobject_output_free;
M
Michael Roth 已提交
250

251 252
    *result = NULL;
    v->result = result;
M
Michael Roth 已提交
253

254
    return &v->visitor;
M
Michael Roth 已提交
255
}