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