qemu/qapi/qapi-forward-visitor.c
<<
>>
Prefs
   1/*
   2 * Forward Visitor
   3 *
   4 * Copyright (C) 2021 Red Hat, Inc.
   5 *
   6 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
   7 * See the COPYING.LIB file in the top-level directory.
   8 *
   9 */
  10
  11#include "qemu/osdep.h"
  12#include "qapi/compat-policy.h"
  13#include "qapi/error.h"
  14#include "qapi/forward-visitor.h"
  15#include "qapi/visitor-impl.h"
  16#include "qemu/queue.h"
  17#include "qapi/qmp/qjson.h"
  18#include "qapi/qmp/qbool.h"
  19#include "qapi/qmp/qdict.h"
  20#include "qapi/qmp/qerror.h"
  21#include "qapi/qmp/qlist.h"
  22#include "qapi/qmp/qnull.h"
  23#include "qapi/qmp/qnum.h"
  24#include "qapi/qmp/qstring.h"
  25#include "qemu/cutils.h"
  26
  27struct ForwardFieldVisitor {
  28    Visitor visitor;
  29
  30    Visitor *target;
  31    char *from;
  32    char *to;
  33
  34    int depth;
  35};
  36
  37static ForwardFieldVisitor *to_ffv(Visitor *v)
  38{
  39    return container_of(v, ForwardFieldVisitor, visitor);
  40}
  41
  42static bool forward_field_translate_name(ForwardFieldVisitor *v, const char **name,
  43                                         Error **errp)
  44{
  45    if (v->depth) {
  46        return true;
  47    }
  48    if (g_str_equal(*name, v->from)) {
  49        *name = v->to;
  50        return true;
  51    }
  52    error_setg(errp, QERR_MISSING_PARAMETER, *name);
  53    return false;
  54}
  55
  56static bool forward_field_check_struct(Visitor *v, Error **errp)
  57{
  58    ForwardFieldVisitor *ffv = to_ffv(v);
  59
  60    return visit_check_struct(ffv->target, errp);
  61}
  62
  63static bool forward_field_start_struct(Visitor *v, const char *name, void **obj,
  64                                       size_t size, Error **errp)
  65{
  66    ForwardFieldVisitor *ffv = to_ffv(v);
  67
  68    if (!forward_field_translate_name(ffv, &name, errp)) {
  69        return false;
  70    }
  71    if (!visit_start_struct(ffv->target, name, obj, size, errp)) {
  72        return false;
  73    }
  74    ffv->depth++;
  75    return true;
  76}
  77
  78static void forward_field_end_struct(Visitor *v, void **obj)
  79{
  80    ForwardFieldVisitor *ffv = to_ffv(v);
  81
  82    assert(ffv->depth);
  83    ffv->depth--;
  84    visit_end_struct(ffv->target, obj);
  85}
  86
  87static bool forward_field_start_list(Visitor *v, const char *name,
  88                                     GenericList **list, size_t size,
  89                                     Error **errp)
  90{
  91    ForwardFieldVisitor *ffv = to_ffv(v);
  92
  93    if (!forward_field_translate_name(ffv, &name, errp)) {
  94        return false;
  95    }
  96    ffv->depth++;
  97    return visit_start_list(ffv->target, name, list, size, errp);
  98}
  99
 100static GenericList *forward_field_next_list(Visitor *v, GenericList *tail,
 101                                            size_t size)
 102{
 103    ForwardFieldVisitor *ffv = to_ffv(v);
 104
 105    assert(ffv->depth);
 106    return visit_next_list(ffv->target, tail, size);
 107}
 108
 109static bool forward_field_check_list(Visitor *v, Error **errp)
 110{
 111    ForwardFieldVisitor *ffv = to_ffv(v);
 112
 113    assert(ffv->depth);
 114    return visit_check_list(ffv->target, errp);
 115}
 116
 117static void forward_field_end_list(Visitor *v, void **obj)
 118{
 119    ForwardFieldVisitor *ffv = to_ffv(v);
 120
 121    assert(ffv->depth);
 122    ffv->depth--;
 123    visit_end_list(ffv->target, obj);
 124}
 125
 126static bool forward_field_start_alternate(Visitor *v, const char *name,
 127                                          GenericAlternate **obj, size_t size,
 128                                          Error **errp)
 129{
 130    ForwardFieldVisitor *ffv = to_ffv(v);
 131
 132    if (!forward_field_translate_name(ffv, &name, errp)) {
 133        return false;
 134    }
 135    /*
 136     * The name passed to start_alternate is used also in the visit_type_* calls
 137     * that retrieve the alternate's content; so, do not increase depth here.
 138     */
 139    return visit_start_alternate(ffv->target, name, obj, size, errp);
 140}
 141
 142static void forward_field_end_alternate(Visitor *v, void **obj)
 143{
 144    ForwardFieldVisitor *ffv = to_ffv(v);
 145
 146    visit_end_alternate(ffv->target, obj);
 147}
 148
 149static bool forward_field_type_int64(Visitor *v, const char *name, int64_t *obj,
 150                                     Error **errp)
 151{
 152    ForwardFieldVisitor *ffv = to_ffv(v);
 153
 154    if (!forward_field_translate_name(ffv, &name, errp)) {
 155        return false;
 156    }
 157    return visit_type_int64(ffv->target, name, obj, errp);
 158}
 159
 160static bool forward_field_type_uint64(Visitor *v, const char *name,
 161                                      uint64_t *obj, Error **errp)
 162{
 163    ForwardFieldVisitor *ffv = to_ffv(v);
 164
 165    if (!forward_field_translate_name(ffv, &name, errp)) {
 166        return false;
 167    }
 168    return visit_type_uint64(ffv->target, name, obj, errp);
 169}
 170
 171static bool forward_field_type_bool(Visitor *v, const char *name, bool *obj,
 172                                    Error **errp)
 173{
 174    ForwardFieldVisitor *ffv = to_ffv(v);
 175
 176    if (!forward_field_translate_name(ffv, &name, errp)) {
 177        return false;
 178    }
 179    return visit_type_bool(ffv->target, name, obj, errp);
 180}
 181
 182static bool forward_field_type_str(Visitor *v, const char *name, char **obj,
 183                                   Error **errp)
 184{
 185    ForwardFieldVisitor *ffv = to_ffv(v);
 186
 187    if (!forward_field_translate_name(ffv, &name, errp)) {
 188        return false;
 189    }
 190    return visit_type_str(ffv->target, name, obj, errp);
 191}
 192
 193static bool forward_field_type_size(Visitor *v, const char *name, uint64_t *obj,
 194                                    Error **errp)
 195{
 196    ForwardFieldVisitor *ffv = to_ffv(v);
 197
 198    if (!forward_field_translate_name(ffv, &name, errp)) {
 199        return false;
 200    }
 201    return visit_type_size(ffv->target, name, obj, errp);
 202}
 203
 204static bool forward_field_type_number(Visitor *v, const char *name, double *obj,
 205                                      Error **errp)
 206{
 207    ForwardFieldVisitor *ffv = to_ffv(v);
 208
 209    if (!forward_field_translate_name(ffv, &name, errp)) {
 210        return false;
 211    }
 212    return visit_type_number(ffv->target, name, obj, errp);
 213}
 214
 215static bool forward_field_type_any(Visitor *v, const char *name, QObject **obj,
 216                                   Error **errp)
 217{
 218    ForwardFieldVisitor *ffv = to_ffv(v);
 219
 220    if (!forward_field_translate_name(ffv, &name, errp)) {
 221        return false;
 222    }
 223    return visit_type_any(ffv->target, name, obj, errp);
 224}
 225
 226static bool forward_field_type_null(Visitor *v, const char *name,
 227                                    QNull **obj, Error **errp)
 228{
 229    ForwardFieldVisitor *ffv = to_ffv(v);
 230
 231    if (!forward_field_translate_name(ffv, &name, errp)) {
 232        return false;
 233    }
 234    return visit_type_null(ffv->target, name, obj, errp);
 235}
 236
 237static void forward_field_optional(Visitor *v, const char *name, bool *present)
 238{
 239    ForwardFieldVisitor *ffv = to_ffv(v);
 240
 241    if (!forward_field_translate_name(ffv, &name, NULL)) {
 242        *present = false;
 243        return;
 244    }
 245    visit_optional(ffv->target, name, present);
 246}
 247
 248static bool forward_field_policy_reject(Visitor *v, const char *name,
 249                                        unsigned special_features,
 250                                        Error **errp)
 251{
 252    ForwardFieldVisitor *ffv = to_ffv(v);
 253
 254    if (!forward_field_translate_name(ffv, &name, errp)) {
 255        return true;
 256    }
 257    return visit_policy_reject(ffv->target, name, special_features, errp);
 258}
 259
 260static bool forward_field_policy_skip(Visitor *v, const char *name,
 261                                      unsigned special_features)
 262{
 263    ForwardFieldVisitor *ffv = to_ffv(v);
 264
 265    if (!forward_field_translate_name(ffv, &name, NULL)) {
 266        return true;
 267    }
 268    return visit_policy_skip(ffv->target, name, special_features);
 269}
 270
 271static void forward_field_complete(Visitor *v, void *opaque)
 272{
 273    /*
 274     * Do nothing, the complete method will be called in due time
 275     * on the target visitor.
 276     */
 277}
 278
 279static void forward_field_free(Visitor *v)
 280{
 281    ForwardFieldVisitor *ffv = to_ffv(v);
 282
 283    g_free(ffv->from);
 284    g_free(ffv->to);
 285    g_free(ffv);
 286}
 287
 288Visitor *visitor_forward_field(Visitor *target, const char *from, const char *to)
 289{
 290    ForwardFieldVisitor *v = g_new0(ForwardFieldVisitor, 1);
 291
 292    /*
 293     * Clone and dealloc visitors don't use a name for the toplevel
 294     * visit, so they make no sense here.
 295     */
 296    assert(target->type == VISITOR_OUTPUT || target->type == VISITOR_INPUT);
 297
 298    v->visitor.type = target->type;
 299    v->visitor.start_struct = forward_field_start_struct;
 300    v->visitor.check_struct = forward_field_check_struct;
 301    v->visitor.end_struct = forward_field_end_struct;
 302    v->visitor.start_list = forward_field_start_list;
 303    v->visitor.next_list = forward_field_next_list;
 304    v->visitor.check_list = forward_field_check_list;
 305    v->visitor.end_list = forward_field_end_list;
 306    v->visitor.start_alternate = forward_field_start_alternate;
 307    v->visitor.end_alternate = forward_field_end_alternate;
 308    v->visitor.type_int64 = forward_field_type_int64;
 309    v->visitor.type_uint64 = forward_field_type_uint64;
 310    v->visitor.type_size = forward_field_type_size;
 311    v->visitor.type_bool = forward_field_type_bool;
 312    v->visitor.type_str = forward_field_type_str;
 313    v->visitor.type_number = forward_field_type_number;
 314    v->visitor.type_any = forward_field_type_any;
 315    v->visitor.type_null = forward_field_type_null;
 316    v->visitor.optional = forward_field_optional;
 317    v->visitor.policy_reject = forward_field_policy_reject;
 318    v->visitor.policy_skip = forward_field_policy_skip;
 319    v->visitor.complete = forward_field_complete;
 320    v->visitor.free = forward_field_free;
 321
 322    v->target = target;
 323    v->from = g_strdup(from);
 324    v->to = g_strdup(to);
 325
 326    return &v->visitor;
 327}
 328