12345c77cSMichael Roth /* 22345c77cSMichael Roth * Core Definitions for QAPI Visitor Classes 32345c77cSMichael Roth * 47c91aabdSEric Blake * Copyright (C) 2012-2016 Red Hat, Inc. 52345c77cSMichael Roth * Copyright IBM, Corp. 2011 62345c77cSMichael Roth * 72345c77cSMichael Roth * Authors: 82345c77cSMichael Roth * Anthony Liguori <aliguori@us.ibm.com> 92345c77cSMichael Roth * 102345c77cSMichael Roth * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. 112345c77cSMichael Roth * See the COPYING.LIB file in the top-level directory. 122345c77cSMichael Roth * 132345c77cSMichael Roth */ 142345c77cSMichael Roth 15cbf21151SPeter Maydell #include "qemu/osdep.h" 16da34e65cSMarkus Armbruster #include "qapi/error.h" 1779ee7df8SPaolo Bonzini #include "qemu-common.h" 1869dd62dfSKevin Wolf #include "qapi/qmp/qobject.h" 197b1b5d19SPaolo Bonzini #include "qapi/qmp/qerror.h" 207b1b5d19SPaolo Bonzini #include "qapi/visitor.h" 217b1b5d19SPaolo Bonzini #include "qapi/visitor-impl.h" 222345c77cSMichael Roth 233b098d56SEric Blake void visit_complete(Visitor *v, void *opaque) 243b098d56SEric Blake { 253b098d56SEric Blake assert(v->type != VISITOR_OUTPUT || v->complete); 263b098d56SEric Blake if (v->complete) { 273b098d56SEric Blake v->complete(v, opaque); 283b098d56SEric Blake } 293b098d56SEric Blake } 303b098d56SEric Blake 312c0ef9f4SEric Blake void visit_free(Visitor *v) 322c0ef9f4SEric Blake { 332c0ef9f4SEric Blake if (v) { 342c0ef9f4SEric Blake v->free(v); 352c0ef9f4SEric Blake } 362c0ef9f4SEric Blake } 372c0ef9f4SEric Blake 3851e72bc1SEric Blake void visit_start_struct(Visitor *v, const char *name, void **obj, 39337283dfSEric Blake size_t size, Error **errp) 402345c77cSMichael Roth { 41e58d695eSEric Blake Error *err = NULL; 42e58d695eSEric Blake 43adfb264cSEric Blake if (obj) { 44adfb264cSEric Blake assert(size); 45*a15fcc3cSEric Blake assert(!(v->type & VISITOR_OUTPUT) || *obj); 46adfb264cSEric Blake } 47e58d695eSEric Blake v->start_struct(v, name, obj, size, &err); 48*a15fcc3cSEric Blake if (obj && (v->type & VISITOR_INPUT)) { 49e58d695eSEric Blake assert(!err != !*obj); 50e58d695eSEric Blake } 51e58d695eSEric Blake error_propagate(errp, err); 522345c77cSMichael Roth } 532345c77cSMichael Roth 5415c2f669SEric Blake void visit_check_struct(Visitor *v, Error **errp) 552345c77cSMichael Roth { 5615c2f669SEric Blake if (v->check_struct) { 5715c2f669SEric Blake v->check_struct(v, errp); 5815c2f669SEric Blake } 5915c2f669SEric Blake } 6015c2f669SEric Blake 611158bb2aSEric Blake void visit_end_struct(Visitor *v, void **obj) 6215c2f669SEric Blake { 631158bb2aSEric Blake v->end_struct(v, obj); 642345c77cSMichael Roth } 652345c77cSMichael Roth 66d9f62ddeSEric Blake void visit_start_list(Visitor *v, const char *name, GenericList **list, 67d9f62ddeSEric Blake size_t size, Error **errp) 682345c77cSMichael Roth { 69d9f62ddeSEric Blake Error *err = NULL; 70d9f62ddeSEric Blake 71d9f62ddeSEric Blake assert(!list || size >= sizeof(GenericList)); 72d9f62ddeSEric Blake v->start_list(v, name, list, size, &err); 73*a15fcc3cSEric Blake if (list && (v->type & VISITOR_INPUT)) { 74d9f62ddeSEric Blake assert(!(err && *list)); 75d9f62ddeSEric Blake } 76d9f62ddeSEric Blake error_propagate(errp, err); 772345c77cSMichael Roth } 782345c77cSMichael Roth 79d9f62ddeSEric Blake GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size) 802345c77cSMichael Roth { 81d9f62ddeSEric Blake assert(tail && size >= sizeof(GenericList)); 82d9f62ddeSEric Blake return v->next_list(v, tail, size); 832345c77cSMichael Roth } 842345c77cSMichael Roth 851158bb2aSEric Blake void visit_end_list(Visitor *v, void **obj) 862345c77cSMichael Roth { 871158bb2aSEric Blake v->end_list(v, obj); 882345c77cSMichael Roth } 892345c77cSMichael Roth 90dbf11922SEric Blake void visit_start_alternate(Visitor *v, const char *name, 91dbf11922SEric Blake GenericAlternate **obj, size_t size, 92dbf11922SEric Blake bool promote_int, Error **errp) 93dbf11922SEric Blake { 94e58d695eSEric Blake Error *err = NULL; 95e58d695eSEric Blake 96dbf11922SEric Blake assert(obj && size >= sizeof(GenericAlternate)); 97*a15fcc3cSEric Blake assert(!(v->type & VISITOR_OUTPUT) || *obj); 98dbf11922SEric Blake if (v->start_alternate) { 99e58d695eSEric Blake v->start_alternate(v, name, obj, size, promote_int, &err); 100dbf11922SEric Blake } 101*a15fcc3cSEric Blake if (v->type & VISITOR_INPUT) { 102e58d695eSEric Blake assert(v->start_alternate && !err != !*obj); 103e58d695eSEric Blake } 104e58d695eSEric Blake error_propagate(errp, err); 105dbf11922SEric Blake } 106dbf11922SEric Blake 1071158bb2aSEric Blake void visit_end_alternate(Visitor *v, void **obj) 108dbf11922SEric Blake { 109dbf11922SEric Blake if (v->end_alternate) { 1101158bb2aSEric Blake v->end_alternate(v, obj); 111dbf11922SEric Blake } 112dbf11922SEric Blake } 113dbf11922SEric Blake 11451e72bc1SEric Blake bool visit_optional(Visitor *v, const char *name, bool *present) 1152345c77cSMichael Roth { 116297a3646SMarkus Armbruster if (v->optional) { 1170b2a0d6bSEric Blake v->optional(v, name, present); 1182345c77cSMichael Roth } 11929637a6eSEric Blake return *present; 1202345c77cSMichael Roth } 1212345c77cSMichael Roth 12268ab47e4SEric Blake bool visit_is_input(Visitor *v) 12368ab47e4SEric Blake { 12468ab47e4SEric Blake return v->type == VISITOR_INPUT; 12568ab47e4SEric Blake } 12668ab47e4SEric Blake 12751e72bc1SEric Blake void visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp) 1282345c77cSMichael Roth { 129adfb264cSEric Blake assert(obj); 1300b2a0d6bSEric Blake v->type_int64(v, name, obj, errp); 1312345c77cSMichael Roth } 1322345c77cSMichael Roth 13304e070d2SEric Blake static void visit_type_uintN(Visitor *v, uint64_t *obj, const char *name, 13404e070d2SEric Blake uint64_t max, const char *type, Error **errp) 13504e070d2SEric Blake { 13604e070d2SEric Blake Error *err = NULL; 13704e070d2SEric Blake uint64_t value = *obj; 13804e070d2SEric Blake 1390b2a0d6bSEric Blake v->type_uint64(v, name, &value, &err); 14004e070d2SEric Blake if (err) { 14104e070d2SEric Blake error_propagate(errp, err); 14204e070d2SEric Blake } else if (value > max) { 14304e070d2SEric Blake error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 14404e070d2SEric Blake name ? name : "null", type); 14504e070d2SEric Blake } else { 14604e070d2SEric Blake *obj = value; 14704e070d2SEric Blake } 14804e070d2SEric Blake } 14904e070d2SEric Blake 15051e72bc1SEric Blake void visit_type_uint8(Visitor *v, const char *name, uint8_t *obj, 15151e72bc1SEric Blake Error **errp) 1524e27e819SMichael Roth { 15304e070d2SEric Blake uint64_t value = *obj; 15404e070d2SEric Blake visit_type_uintN(v, &value, name, UINT8_MAX, "uint8_t", errp); 1554e27e819SMichael Roth *obj = value; 1564e27e819SMichael Roth } 1574e27e819SMichael Roth 15851e72bc1SEric Blake void visit_type_uint16(Visitor *v, const char *name, uint16_t *obj, 15904e070d2SEric Blake Error **errp) 1604e27e819SMichael Roth { 16104e070d2SEric Blake uint64_t value = *obj; 16204e070d2SEric Blake visit_type_uintN(v, &value, name, UINT16_MAX, "uint16_t", errp); 1634e27e819SMichael Roth *obj = value; 1644e27e819SMichael Roth } 1654e27e819SMichael Roth 16651e72bc1SEric Blake void visit_type_uint32(Visitor *v, const char *name, uint32_t *obj, 16704e070d2SEric Blake Error **errp) 1684e27e819SMichael Roth { 16904e070d2SEric Blake uint64_t value = *obj; 17004e070d2SEric Blake visit_type_uintN(v, &value, name, UINT32_MAX, "uint32_t", errp); 1714e27e819SMichael Roth *obj = value; 1724e27e819SMichael Roth } 1734e27e819SMichael Roth 17451e72bc1SEric Blake void visit_type_uint64(Visitor *v, const char *name, uint64_t *obj, 17504e070d2SEric Blake Error **errp) 1764e27e819SMichael Roth { 177adfb264cSEric Blake assert(obj); 1780b2a0d6bSEric Blake v->type_uint64(v, name, obj, errp); 1794e27e819SMichael Roth } 1804e27e819SMichael Roth 18104e070d2SEric Blake static void visit_type_intN(Visitor *v, int64_t *obj, const char *name, 18204e070d2SEric Blake int64_t min, int64_t max, const char *type, 18304e070d2SEric Blake Error **errp) 1844e27e819SMichael Roth { 18504e070d2SEric Blake Error *err = NULL; 18604e070d2SEric Blake int64_t value = *obj; 187297a3646SMarkus Armbruster 1880b2a0d6bSEric Blake v->type_int64(v, name, &value, &err); 18904e070d2SEric Blake if (err) { 19004e070d2SEric Blake error_propagate(errp, err); 19104e070d2SEric Blake } else if (value < min || value > max) { 192c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 19304e070d2SEric Blake name ? name : "null", type); 19404e070d2SEric Blake } else { 1954e27e819SMichael Roth *obj = value; 1964e27e819SMichael Roth } 1974e27e819SMichael Roth } 1984e27e819SMichael Roth 19951e72bc1SEric Blake void visit_type_int8(Visitor *v, const char *name, int8_t *obj, Error **errp) 20004e070d2SEric Blake { 20104e070d2SEric Blake int64_t value = *obj; 20204e070d2SEric Blake visit_type_intN(v, &value, name, INT8_MIN, INT8_MAX, "int8_t", errp); 20304e070d2SEric Blake *obj = value; 20404e070d2SEric Blake } 20504e070d2SEric Blake 20651e72bc1SEric Blake void visit_type_int16(Visitor *v, const char *name, int16_t *obj, 20751e72bc1SEric Blake Error **errp) 2084e27e819SMichael Roth { 20904e070d2SEric Blake int64_t value = *obj; 21004e070d2SEric Blake visit_type_intN(v, &value, name, INT16_MIN, INT16_MAX, "int16_t", errp); 2114e27e819SMichael Roth *obj = value; 2124e27e819SMichael Roth } 2134e27e819SMichael Roth 21451e72bc1SEric Blake void visit_type_int32(Visitor *v, const char *name, int32_t *obj, 21551e72bc1SEric Blake Error **errp) 2164e27e819SMichael Roth { 21704e070d2SEric Blake int64_t value = *obj; 21804e070d2SEric Blake visit_type_intN(v, &value, name, INT32_MIN, INT32_MAX, "int32_t", errp); 2194e27e819SMichael Roth *obj = value; 2204e27e819SMichael Roth } 2214e27e819SMichael Roth 22251e72bc1SEric Blake void visit_type_int64(Visitor *v, const char *name, int64_t *obj, 22351e72bc1SEric Blake Error **errp) 2244e27e819SMichael Roth { 225adfb264cSEric Blake assert(obj); 2260b2a0d6bSEric Blake v->type_int64(v, name, obj, errp); 2274e27e819SMichael Roth } 2284e27e819SMichael Roth 22951e72bc1SEric Blake void visit_type_size(Visitor *v, const char *name, uint64_t *obj, 23051e72bc1SEric Blake Error **errp) 231092705d4SLaszlo Ersek { 232adfb264cSEric Blake assert(obj); 233b8877962SVasilis Liaskovitis if (v->type_size) { 2340b2a0d6bSEric Blake v->type_size(v, name, obj, errp); 235b8877962SVasilis Liaskovitis } else { 2360b2a0d6bSEric Blake v->type_uint64(v, name, obj, errp); 237b8877962SVasilis Liaskovitis } 238092705d4SLaszlo Ersek } 239092705d4SLaszlo Ersek 24051e72bc1SEric Blake void visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) 2412345c77cSMichael Roth { 242adfb264cSEric Blake assert(obj); 2430b2a0d6bSEric Blake v->type_bool(v, name, obj, errp); 2442345c77cSMichael Roth } 2452345c77cSMichael Roth 24651e72bc1SEric Blake void visit_type_str(Visitor *v, const char *name, char **obj, Error **errp) 2472345c77cSMichael Roth { 248e58d695eSEric Blake Error *err = NULL; 249e58d695eSEric Blake 250e58d695eSEric Blake assert(obj); 251adfb264cSEric Blake /* TODO: Fix callers to not pass NULL when they mean "", so that we 252adfb264cSEric Blake * can enable: 253*a15fcc3cSEric Blake assert(!(v->type & VISITOR_OUTPUT) || *obj); 254adfb264cSEric Blake */ 255e58d695eSEric Blake v->type_str(v, name, obj, &err); 256*a15fcc3cSEric Blake if (v->type & VISITOR_INPUT) { 257e58d695eSEric Blake assert(!err != !*obj); 258e58d695eSEric Blake } 259e58d695eSEric Blake error_propagate(errp, err); 2602345c77cSMichael Roth } 2612345c77cSMichael Roth 26251e72bc1SEric Blake void visit_type_number(Visitor *v, const char *name, double *obj, 26351e72bc1SEric Blake Error **errp) 2642345c77cSMichael Roth { 265adfb264cSEric Blake assert(obj); 2660b2a0d6bSEric Blake v->type_number(v, name, obj, errp); 2672345c77cSMichael Roth } 2680f71a1e0SPaolo Bonzini 26951e72bc1SEric Blake void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp) 27028770e05SMarkus Armbruster { 271e58d695eSEric Blake Error *err = NULL; 272e58d695eSEric Blake 273e58d695eSEric Blake assert(obj); 274adfb264cSEric Blake assert(v->type != VISITOR_OUTPUT || *obj); 275e58d695eSEric Blake v->type_any(v, name, obj, &err); 276e58d695eSEric Blake if (v->type == VISITOR_INPUT) { 277e58d695eSEric Blake assert(!err != !*obj); 278e58d695eSEric Blake } 279e58d695eSEric Blake error_propagate(errp, err); 28028770e05SMarkus Armbruster } 28128770e05SMarkus Armbruster 2823bc97fd5SEric Blake void visit_type_null(Visitor *v, const char *name, Error **errp) 2833bc97fd5SEric Blake { 2843bc97fd5SEric Blake v->type_null(v, name, errp); 2853bc97fd5SEric Blake } 2863bc97fd5SEric Blake 287983f52d4SEric Blake static void output_type_enum(Visitor *v, const char *name, int *obj, 288337283dfSEric Blake const char *const strings[], Error **errp) 2890f71a1e0SPaolo Bonzini { 2900f71a1e0SPaolo Bonzini int i = 0; 2910f71a1e0SPaolo Bonzini int value = *obj; 2920f71a1e0SPaolo Bonzini char *enum_str; 2930f71a1e0SPaolo Bonzini 2940f71a1e0SPaolo Bonzini while (strings[i++] != NULL); 2950f71a1e0SPaolo Bonzini if (value < 0 || value >= i - 1) { 296c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER, name ? name : "null"); 2970f71a1e0SPaolo Bonzini return; 2980f71a1e0SPaolo Bonzini } 2990f71a1e0SPaolo Bonzini 3000f71a1e0SPaolo Bonzini enum_str = (char *)strings[value]; 30151e72bc1SEric Blake visit_type_str(v, name, &enum_str, errp); 3020f71a1e0SPaolo Bonzini } 3030f71a1e0SPaolo Bonzini 304983f52d4SEric Blake static void input_type_enum(Visitor *v, const char *name, int *obj, 305337283dfSEric Blake const char *const strings[], Error **errp) 3060f71a1e0SPaolo Bonzini { 307297a3646SMarkus Armbruster Error *local_err = NULL; 3080f71a1e0SPaolo Bonzini int64_t value = 0; 3090f71a1e0SPaolo Bonzini char *enum_str; 3100f71a1e0SPaolo Bonzini 31151e72bc1SEric Blake visit_type_str(v, name, &enum_str, &local_err); 312297a3646SMarkus Armbruster if (local_err) { 313297a3646SMarkus Armbruster error_propagate(errp, local_err); 3140f71a1e0SPaolo Bonzini return; 3150f71a1e0SPaolo Bonzini } 3160f71a1e0SPaolo Bonzini 3170f71a1e0SPaolo Bonzini while (strings[value] != NULL) { 3180f71a1e0SPaolo Bonzini if (strcmp(strings[value], enum_str) == 0) { 3190f71a1e0SPaolo Bonzini break; 3200f71a1e0SPaolo Bonzini } 3210f71a1e0SPaolo Bonzini value++; 3220f71a1e0SPaolo Bonzini } 3230f71a1e0SPaolo Bonzini 3240f71a1e0SPaolo Bonzini if (strings[value] == NULL) { 325c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER, enum_str); 3260f71a1e0SPaolo Bonzini g_free(enum_str); 3270f71a1e0SPaolo Bonzini return; 3280f71a1e0SPaolo Bonzini } 3290f71a1e0SPaolo Bonzini 3300f71a1e0SPaolo Bonzini g_free(enum_str); 3310f71a1e0SPaolo Bonzini *obj = value; 3320f71a1e0SPaolo Bonzini } 333983f52d4SEric Blake 334983f52d4SEric Blake void visit_type_enum(Visitor *v, const char *name, int *obj, 335983f52d4SEric Blake const char *const strings[], Error **errp) 336983f52d4SEric Blake { 337adfb264cSEric Blake assert(obj && strings); 338*a15fcc3cSEric Blake switch (v->type) { 339*a15fcc3cSEric Blake case VISITOR_INPUT: 340983f52d4SEric Blake input_type_enum(v, name, obj, strings, errp); 341*a15fcc3cSEric Blake break; 342*a15fcc3cSEric Blake case VISITOR_OUTPUT: 343983f52d4SEric Blake output_type_enum(v, name, obj, strings, errp); 344*a15fcc3cSEric Blake break; 345*a15fcc3cSEric Blake case VISITOR_CLONE: 346*a15fcc3cSEric Blake /* nothing further to do, scalar value was already copied by 347*a15fcc3cSEric Blake * g_memdup() during visit_start_*() */ 348*a15fcc3cSEric Blake break; 349*a15fcc3cSEric Blake case VISITOR_DEALLOC: 350*a15fcc3cSEric Blake /* nothing to deallocate for a scalar */ 351*a15fcc3cSEric Blake break; 352983f52d4SEric Blake } 353983f52d4SEric Blake } 354