mirror of
https://github.com/qemu/qemu.git
synced 2025-08-09 01:50:43 +00:00
QAPI patches for 2016-02-19
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWxuoKAAoJEDhwtADrkYZT8ZkP/RqSevpfXSsLwmGa10olkGYd 9++3Sl2vu4X5iFFYBYHj9eIzzt5T9CCBRQGvu2N0baO3/NVFVmrXHrRXu5FHn3AV /dqnF5Cp8UMvBh4q/+z0IiN67mHlUMxZex/tjfL+6YeSi6TYEMGYxIq0cUv9HpPS jJtTNWgR/erNUMYg0IRePJ/Gounfs3nrWKy76Z2Ni7NABOACN5QFWMQWIS+P6+4j zJn92FziNh0qRckc/yYkd1x+p3IaCoALw38ovOZZE76EgBFEtkb2Ccl/4zQyxUkE ItjknuZFnjHdZCi2mngYFqqGEPspxYddtKoDKI6J6AoiZ4wXkkpfW44JrRLP8yIp 3ZPYutH7wyHsh0t+s3rML/hwxGnYuDvf0XTIgmh9ZfGGSLSw93KbujONqZ6OFqNC FFPSgdhtvyB/TETp+TYu469PBtlKCG/7cT4CZM64BxaYUxHPl1e1xb2TfVDdE4vK rurQwAg2woHU8BqUYdCfMdeDJOhtI2FyBK8F5jSPq6Bj+MRBWgYSRF1BQh0xJTay WU7Tkn3mnm8CaB55+sOQnnwtGoe77NhBj341g5uTSwsca4c1bpb7WFYZ5iQU/lvm 58ILjHs4mV09VkSs5QnNlfPLL4rz0gJtNWXT86T5VUveDDr0bj6qe1Ek2cO7fQ9z ztSODnQeM5nfvpH06cVe =PNgf -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2016-02-19' into staging QAPI patches for 2016-02-19 # gpg: Signature made Fri 19 Feb 2016 10:10:18 GMT using RSA key ID EB918653 # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" * remotes/armbru/tags/pull-qapi-2016-02-19: qapi: Change visit_start_implicit_struct to visit_start_alternate qapi: Don't box branches of flat unions qapi: Don't box struct branch of alternate qapi-visit: Use common idiom in gen_visit_fields_decl() qapi: Emit structs used as variants in topological order qapi: Adjust layout of FooList types qapi-visit: Less indirection in visit_type_Foo_fields() qapi-visit: Unify struct and union visit qapi: Visit variants in visit_type_FOO_fields() qapi-visit: Simplify how we visit common union members qapi: Add tests of complex objects within alternate qapi: Forbid 'any' inside an alternate qapi: Forbid empty unions and useless alternates qapi: Simplify excess input reporting in input visitors qapi-visit: Honor prefix of discriminator enum Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
5cfffc30de
18
cpus.c
18
cpus.c
@ -1568,28 +1568,22 @@ CpuInfoList *qmp_query_cpus(Error **errp)
|
|||||||
info->value->thread_id = cpu->thread_id;
|
info->value->thread_id = cpu->thread_id;
|
||||||
#if defined(TARGET_I386)
|
#if defined(TARGET_I386)
|
||||||
info->value->arch = CPU_INFO_ARCH_X86;
|
info->value->arch = CPU_INFO_ARCH_X86;
|
||||||
info->value->u.x86 = g_new0(CpuInfoX86, 1);
|
info->value->u.x86.pc = env->eip + env->segs[R_CS].base;
|
||||||
info->value->u.x86->pc = env->eip + env->segs[R_CS].base;
|
|
||||||
#elif defined(TARGET_PPC)
|
#elif defined(TARGET_PPC)
|
||||||
info->value->arch = CPU_INFO_ARCH_PPC;
|
info->value->arch = CPU_INFO_ARCH_PPC;
|
||||||
info->value->u.ppc = g_new0(CpuInfoPPC, 1);
|
info->value->u.ppc.nip = env->nip;
|
||||||
info->value->u.ppc->nip = env->nip;
|
|
||||||
#elif defined(TARGET_SPARC)
|
#elif defined(TARGET_SPARC)
|
||||||
info->value->arch = CPU_INFO_ARCH_SPARC;
|
info->value->arch = CPU_INFO_ARCH_SPARC;
|
||||||
info->value->u.q_sparc = g_new0(CpuInfoSPARC, 1);
|
info->value->u.q_sparc.pc = env->pc;
|
||||||
info->value->u.q_sparc->pc = env->pc;
|
info->value->u.q_sparc.npc = env->npc;
|
||||||
info->value->u.q_sparc->npc = env->npc;
|
|
||||||
#elif defined(TARGET_MIPS)
|
#elif defined(TARGET_MIPS)
|
||||||
info->value->arch = CPU_INFO_ARCH_MIPS;
|
info->value->arch = CPU_INFO_ARCH_MIPS;
|
||||||
info->value->u.q_mips = g_new0(CpuInfoMIPS, 1);
|
info->value->u.q_mips.PC = env->active_tc.PC;
|
||||||
info->value->u.q_mips->PC = env->active_tc.PC;
|
|
||||||
#elif defined(TARGET_TRICORE)
|
#elif defined(TARGET_TRICORE)
|
||||||
info->value->arch = CPU_INFO_ARCH_TRICORE;
|
info->value->arch = CPU_INFO_ARCH_TRICORE;
|
||||||
info->value->u.tricore = g_new0(CpuInfoTricore, 1);
|
info->value->u.tricore.PC = env->PC;
|
||||||
info->value->u.tricore->PC = env->PC;
|
|
||||||
#else
|
#else
|
||||||
info->value->arch = CPU_INFO_ARCH_OTHER;
|
info->value->arch = CPU_INFO_ARCH_OTHER;
|
||||||
info->value->u.other = g_new0(CpuInfoOther, 1);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* XXX: waiting for the qapi to support GSList */
|
/* XXX: waiting for the qapi to support GSList */
|
||||||
|
@ -187,11 +187,11 @@ prevent incomplete include files.
|
|||||||
|
|
||||||
Usage: { 'struct': STRING, 'data': DICT, '*base': STRUCT-NAME }
|
Usage: { 'struct': STRING, 'data': DICT, '*base': STRUCT-NAME }
|
||||||
|
|
||||||
A struct is a dictionary containing a single 'data' key whose
|
A struct is a dictionary containing a single 'data' key whose value is
|
||||||
value is a dictionary. This corresponds to a struct in C or an Object
|
a dictionary; the dictionary may be empty. This corresponds to a
|
||||||
in JSON. Each value of the 'data' dictionary must be the name of a
|
struct in C or an Object in JSON. Each value of the 'data' dictionary
|
||||||
type, or a one-element array containing a type name. An example of a
|
must be the name of a type, or a one-element array containing a type
|
||||||
struct is:
|
name. An example of a struct is:
|
||||||
|
|
||||||
{ 'struct': 'MyType',
|
{ 'struct': 'MyType',
|
||||||
'data': { 'member1': 'str', 'member2': 'int', '*member3': 'str' } }
|
'data': { 'member1': 'str', 'member2': 'int', '*member3': 'str' } }
|
||||||
@ -288,9 +288,10 @@ or: { 'union': STRING, 'data': DICT, 'base': STRUCT-NAME,
|
|||||||
|
|
||||||
Union types are used to let the user choose between several different
|
Union types are used to let the user choose between several different
|
||||||
variants for an object. There are two flavors: simple (no
|
variants for an object. There are two flavors: simple (no
|
||||||
discriminator or base), flat (both discriminator and base). A union
|
discriminator or base), and flat (both discriminator and base). A union
|
||||||
type is defined using a data dictionary as explained in the following
|
type is defined using a data dictionary as explained in the following
|
||||||
paragraphs.
|
paragraphs. The data dictionary for either type of union must not
|
||||||
|
be empty.
|
||||||
|
|
||||||
A simple union type defines a mapping from automatic discriminator
|
A simple union type defines a mapping from automatic discriminator
|
||||||
values to data types like in this example:
|
values to data types like in this example:
|
||||||
|
12
hmp.c
12
hmp.c
@ -314,22 +314,22 @@ void hmp_info_cpus(Monitor *mon, const QDict *qdict)
|
|||||||
|
|
||||||
switch (cpu->value->arch) {
|
switch (cpu->value->arch) {
|
||||||
case CPU_INFO_ARCH_X86:
|
case CPU_INFO_ARCH_X86:
|
||||||
monitor_printf(mon, " pc=0x%016" PRIx64, cpu->value->u.x86->pc);
|
monitor_printf(mon, " pc=0x%016" PRIx64, cpu->value->u.x86.pc);
|
||||||
break;
|
break;
|
||||||
case CPU_INFO_ARCH_PPC:
|
case CPU_INFO_ARCH_PPC:
|
||||||
monitor_printf(mon, " nip=0x%016" PRIx64, cpu->value->u.ppc->nip);
|
monitor_printf(mon, " nip=0x%016" PRIx64, cpu->value->u.ppc.nip);
|
||||||
break;
|
break;
|
||||||
case CPU_INFO_ARCH_SPARC:
|
case CPU_INFO_ARCH_SPARC:
|
||||||
monitor_printf(mon, " pc=0x%016" PRIx64,
|
monitor_printf(mon, " pc=0x%016" PRIx64,
|
||||||
cpu->value->u.q_sparc->pc);
|
cpu->value->u.q_sparc.pc);
|
||||||
monitor_printf(mon, " npc=0x%016" PRIx64,
|
monitor_printf(mon, " npc=0x%016" PRIx64,
|
||||||
cpu->value->u.q_sparc->npc);
|
cpu->value->u.q_sparc.npc);
|
||||||
break;
|
break;
|
||||||
case CPU_INFO_ARCH_MIPS:
|
case CPU_INFO_ARCH_MIPS:
|
||||||
monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->u.q_mips->PC);
|
monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->u.q_mips.PC);
|
||||||
break;
|
break;
|
||||||
case CPU_INFO_ARCH_TRICORE:
|
case CPU_INFO_ARCH_TRICORE:
|
||||||
monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->u.tricore->PC);
|
monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->u.tricore.PC);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -22,22 +22,23 @@ struct Visitor
|
|||||||
size_t size, Error **errp);
|
size_t size, Error **errp);
|
||||||
void (*end_struct)(Visitor *v, Error **errp);
|
void (*end_struct)(Visitor *v, Error **errp);
|
||||||
|
|
||||||
void (*start_implicit_struct)(Visitor *v, void **obj, size_t size,
|
|
||||||
Error **errp);
|
|
||||||
/* May be NULL */
|
|
||||||
void (*end_implicit_struct)(Visitor *v);
|
|
||||||
|
|
||||||
void (*start_list)(Visitor *v, const char *name, Error **errp);
|
void (*start_list)(Visitor *v, const char *name, Error **errp);
|
||||||
/* Must be set */
|
/* Must be set */
|
||||||
GenericList *(*next_list)(Visitor *v, GenericList **list);
|
GenericList *(*next_list)(Visitor *v, GenericList **list, size_t size);
|
||||||
/* Must be set */
|
/* Must be set */
|
||||||
void (*end_list)(Visitor *v);
|
void (*end_list)(Visitor *v);
|
||||||
|
|
||||||
|
/* Optional, needed for input and dealloc visitors. */
|
||||||
|
void (*start_alternate)(Visitor *v, const char *name,
|
||||||
|
GenericAlternate **obj, size_t size,
|
||||||
|
bool promote_int, Error **errp);
|
||||||
|
|
||||||
|
/* Optional, needed for dealloc visitor. */
|
||||||
|
void (*end_alternate)(Visitor *v);
|
||||||
|
|
||||||
|
/* Must be set. */
|
||||||
void (*type_enum)(Visitor *v, const char *name, int *obj,
|
void (*type_enum)(Visitor *v, const char *name, int *obj,
|
||||||
const char *const strings[], Error **errp);
|
const char *const strings[], Error **errp);
|
||||||
/* May be NULL; only needed for input visitors. */
|
|
||||||
void (*get_next_type)(Visitor *v, const char *name, QType *type,
|
|
||||||
bool promote_int, Error **errp);
|
|
||||||
|
|
||||||
/* Must be set. */
|
/* Must be set. */
|
||||||
void (*type_int64)(Visitor *v, const char *name, int64_t *obj,
|
void (*type_int64)(Visitor *v, const char *name, int64_t *obj,
|
||||||
@ -58,8 +59,6 @@ struct Visitor
|
|||||||
|
|
||||||
/* May be NULL; most useful for input visitors. */
|
/* May be NULL; most useful for input visitors. */
|
||||||
void (*optional)(Visitor *v, const char *name, bool *present);
|
void (*optional)(Visitor *v, const char *name, bool *present);
|
||||||
|
|
||||||
bool (*start_union)(Visitor *v, bool data_present, Error **errp);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void input_type_enum(Visitor *v, const char *name, int *obj,
|
void input_type_enum(Visitor *v, const char *name, int *obj,
|
||||||
|
@ -19,26 +19,60 @@
|
|||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
typedef struct GenericList
|
/* This struct is layout-compatible with all other *List structs
|
||||||
{
|
* created by the qapi generator. It is used as a typical
|
||||||
union {
|
* singly-linked list. */
|
||||||
void *value;
|
typedef struct GenericList {
|
||||||
uint64_t padding;
|
|
||||||
};
|
|
||||||
struct GenericList *next;
|
struct GenericList *next;
|
||||||
|
char padding[];
|
||||||
} GenericList;
|
} GenericList;
|
||||||
|
|
||||||
|
/* This struct is layout-compatible with all Alternate types
|
||||||
|
* created by the qapi generator. */
|
||||||
|
typedef struct GenericAlternate {
|
||||||
|
QType type;
|
||||||
|
char padding[];
|
||||||
|
} GenericAlternate;
|
||||||
|
|
||||||
void visit_start_struct(Visitor *v, const char *name, void **obj,
|
void visit_start_struct(Visitor *v, const char *name, void **obj,
|
||||||
size_t size, Error **errp);
|
size_t size, Error **errp);
|
||||||
void visit_end_struct(Visitor *v, Error **errp);
|
void visit_end_struct(Visitor *v, Error **errp);
|
||||||
void visit_start_implicit_struct(Visitor *v, void **obj, size_t size,
|
|
||||||
Error **errp);
|
|
||||||
void visit_end_implicit_struct(Visitor *v);
|
|
||||||
|
|
||||||
void visit_start_list(Visitor *v, const char *name, Error **errp);
|
void visit_start_list(Visitor *v, const char *name, Error **errp);
|
||||||
GenericList *visit_next_list(Visitor *v, GenericList **list);
|
GenericList *visit_next_list(Visitor *v, GenericList **list, size_t size);
|
||||||
void visit_end_list(Visitor *v);
|
void visit_end_list(Visitor *v);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start the visit of an alternate @obj with the given @size.
|
||||||
|
*
|
||||||
|
* @name specifies the relationship to the containing struct (ignored
|
||||||
|
* for a top level visit, the name of the key if this alternate is
|
||||||
|
* part of an object, or NULL if this alternate is part of a list).
|
||||||
|
*
|
||||||
|
* @obj must not be NULL. Input visitors will allocate @obj and
|
||||||
|
* determine the qtype of the next thing to be visited, stored in
|
||||||
|
* (*@obj)->type. Other visitors will leave @obj unchanged.
|
||||||
|
*
|
||||||
|
* If @promote_int, treat integers as QTYPE_FLOAT.
|
||||||
|
*
|
||||||
|
* If successful, this must be paired with visit_end_alternate(), even
|
||||||
|
* if visiting the contents of the alternate fails.
|
||||||
|
*/
|
||||||
|
void visit_start_alternate(Visitor *v, const char *name,
|
||||||
|
GenericAlternate **obj, size_t size,
|
||||||
|
bool promote_int, Error **errp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finish visiting an alternate type.
|
||||||
|
*
|
||||||
|
* Must be called after a successful visit_start_alternate(), even if
|
||||||
|
* an error occurred in the meantime.
|
||||||
|
*
|
||||||
|
* TODO: Should all the visit_end_* interfaces take obj parameter, so
|
||||||
|
* that dealloc visitor need not track what was passed in visit_start?
|
||||||
|
*/
|
||||||
|
void visit_end_alternate(Visitor *v);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if an optional member @name of an object needs visiting.
|
* Check if an optional member @name of an object needs visiting.
|
||||||
* For input visitors, set *@present according to whether the
|
* For input visitors, set *@present according to whether the
|
||||||
@ -47,14 +81,6 @@ void visit_end_list(Visitor *v);
|
|||||||
*/
|
*/
|
||||||
bool visit_optional(Visitor *v, const char *name, bool *present);
|
bool visit_optional(Visitor *v, const char *name, bool *present);
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine the qtype of the item @name in the current object visit.
|
|
||||||
* For input visitors, set *@type to the correct qtype of a qapi
|
|
||||||
* alternate type; for other visitors, leave *@type unchanged.
|
|
||||||
* If @promote_int, treat integers as QTYPE_FLOAT.
|
|
||||||
*/
|
|
||||||
void visit_get_next_type(Visitor *v, const char *name, QType *type,
|
|
||||||
bool promote_int, Error **errp);
|
|
||||||
void visit_type_enum(Visitor *v, const char *name, int *obj,
|
void visit_type_enum(Visitor *v, const char *name, int *obj,
|
||||||
const char *const strings[], Error **errp);
|
const char *const strings[], Error **errp);
|
||||||
void visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp);
|
void visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp);
|
||||||
@ -80,6 +106,5 @@ void visit_type_str(Visitor *v, const char *name, char **obj, Error **errp);
|
|||||||
void visit_type_number(Visitor *v, const char *name, double *obj,
|
void visit_type_number(Visitor *v, const char *name, double *obj,
|
||||||
Error **errp);
|
Error **errp);
|
||||||
void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp);
|
void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp);
|
||||||
bool visit_start_union(Visitor *v, bool data_present, Error **errp);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -157,17 +157,11 @@ opts_start_struct(Visitor *v, const char *name, void **obj,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
ghr_true(gpointer ign_key, gpointer ign_value, gpointer ign_user_data)
|
|
||||||
{
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
opts_end_struct(Visitor *v, Error **errp)
|
opts_end_struct(Visitor *v, Error **errp)
|
||||||
{
|
{
|
||||||
OptsVisitor *ov = to_ov(v);
|
OptsVisitor *ov = to_ov(v);
|
||||||
|
GHashTableIter iter;
|
||||||
GQueue *any;
|
GQueue *any;
|
||||||
|
|
||||||
if (--ov->depth > 0) {
|
if (--ov->depth > 0) {
|
||||||
@ -175,8 +169,8 @@ opts_end_struct(Visitor *v, Error **errp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* we should have processed all (distinct) QemuOpt instances */
|
/* we should have processed all (distinct) QemuOpt instances */
|
||||||
any = g_hash_table_find(ov->unprocessed_opts, &ghr_true, NULL);
|
g_hash_table_iter_init(&iter, ov->unprocessed_opts);
|
||||||
if (any) {
|
if (g_hash_table_iter_next(&iter, NULL, (void **)&any)) {
|
||||||
const QemuOpt *first;
|
const QemuOpt *first;
|
||||||
|
|
||||||
first = g_queue_peek_head(any);
|
first = g_queue_peek_head(any);
|
||||||
@ -221,7 +215,7 @@ opts_start_list(Visitor *v, const char *name, Error **errp)
|
|||||||
|
|
||||||
|
|
||||||
static GenericList *
|
static GenericList *
|
||||||
opts_next_list(Visitor *v, GenericList **list)
|
opts_next_list(Visitor *v, GenericList **list, size_t size)
|
||||||
{
|
{
|
||||||
OptsVisitor *ov = to_ov(v);
|
OptsVisitor *ov = to_ov(v);
|
||||||
GenericList **link;
|
GenericList **link;
|
||||||
@ -264,7 +258,7 @@ opts_next_list(Visitor *v, GenericList **list)
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
*link = g_malloc0(sizeof **link);
|
*link = g_malloc0(size);
|
||||||
return *link;
|
return *link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,16 +76,15 @@ static void qapi_dealloc_end_struct(Visitor *v, Error **errp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qapi_dealloc_start_implicit_struct(Visitor *v,
|
static void qapi_dealloc_start_alternate(Visitor *v, const char *name,
|
||||||
void **obj,
|
GenericAlternate **obj, size_t size,
|
||||||
size_t size,
|
bool promote_int, Error **errp)
|
||||||
Error **errp)
|
|
||||||
{
|
{
|
||||||
QapiDeallocVisitor *qov = to_qov(v);
|
QapiDeallocVisitor *qov = to_qov(v);
|
||||||
qapi_dealloc_push(qov, obj);
|
qapi_dealloc_push(qov, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qapi_dealloc_end_implicit_struct(Visitor *v)
|
static void qapi_dealloc_end_alternate(Visitor *v)
|
||||||
{
|
{
|
||||||
QapiDeallocVisitor *qov = to_qov(v);
|
QapiDeallocVisitor *qov = to_qov(v);
|
||||||
void **obj = qapi_dealloc_pop(qov);
|
void **obj = qapi_dealloc_pop(qov);
|
||||||
@ -100,7 +99,8 @@ static void qapi_dealloc_start_list(Visitor *v, const char *name, Error **errp)
|
|||||||
qapi_dealloc_push(qov, NULL);
|
qapi_dealloc_push(qov, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList **listp)
|
static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList **listp,
|
||||||
|
size_t size)
|
||||||
{
|
{
|
||||||
GenericList *list = *listp;
|
GenericList *list = *listp;
|
||||||
QapiDeallocVisitor *qov = to_qov(v);
|
QapiDeallocVisitor *qov = to_qov(v);
|
||||||
@ -168,31 +168,6 @@ static void qapi_dealloc_type_enum(Visitor *v, const char *name, int *obj,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If there's no data present, the dealloc visitor has nothing to free.
|
|
||||||
* Thus, indicate to visitor code that the subsequent union fields can
|
|
||||||
* be skipped. This is not an error condition, since the cleanup of the
|
|
||||||
* rest of an object can continue unhindered, so leave errp unset in
|
|
||||||
* these cases.
|
|
||||||
*
|
|
||||||
* NOTE: In cases where we're attempting to deallocate an object that
|
|
||||||
* may have missing fields, the field indicating the union type may
|
|
||||||
* be missing. In such a case, it's possible we don't have enough
|
|
||||||
* information to differentiate data_present == false from a case where
|
|
||||||
* data *is* present but happens to be a scalar with a value of 0.
|
|
||||||
* This is okay, since in the case of the dealloc visitor there's no
|
|
||||||
* work that needs to done in either situation.
|
|
||||||
*
|
|
||||||
* The current inability in QAPI code to more thoroughly verify a union
|
|
||||||
* type in such cases will likely need to be addressed if we wish to
|
|
||||||
* implement this interface for other types of visitors in the future,
|
|
||||||
* however.
|
|
||||||
*/
|
|
||||||
static bool qapi_dealloc_start_union(Visitor *v, bool data_present,
|
|
||||||
Error **errp)
|
|
||||||
{
|
|
||||||
return data_present;
|
|
||||||
}
|
|
||||||
|
|
||||||
Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v)
|
Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v)
|
||||||
{
|
{
|
||||||
return &v->visitor;
|
return &v->visitor;
|
||||||
@ -211,8 +186,8 @@ QapiDeallocVisitor *qapi_dealloc_visitor_new(void)
|
|||||||
|
|
||||||
v->visitor.start_struct = qapi_dealloc_start_struct;
|
v->visitor.start_struct = qapi_dealloc_start_struct;
|
||||||
v->visitor.end_struct = qapi_dealloc_end_struct;
|
v->visitor.end_struct = qapi_dealloc_end_struct;
|
||||||
v->visitor.start_implicit_struct = qapi_dealloc_start_implicit_struct;
|
v->visitor.start_alternate = qapi_dealloc_start_alternate;
|
||||||
v->visitor.end_implicit_struct = qapi_dealloc_end_implicit_struct;
|
v->visitor.end_alternate = qapi_dealloc_end_alternate;
|
||||||
v->visitor.start_list = qapi_dealloc_start_list;
|
v->visitor.start_list = qapi_dealloc_start_list;
|
||||||
v->visitor.next_list = qapi_dealloc_next_list;
|
v->visitor.next_list = qapi_dealloc_next_list;
|
||||||
v->visitor.end_list = qapi_dealloc_end_list;
|
v->visitor.end_list = qapi_dealloc_end_list;
|
||||||
@ -223,7 +198,6 @@ QapiDeallocVisitor *qapi_dealloc_visitor_new(void)
|
|||||||
v->visitor.type_str = qapi_dealloc_type_str;
|
v->visitor.type_str = qapi_dealloc_type_str;
|
||||||
v->visitor.type_number = qapi_dealloc_type_number;
|
v->visitor.type_number = qapi_dealloc_type_number;
|
||||||
v->visitor.type_any = qapi_dealloc_type_anything;
|
v->visitor.type_any = qapi_dealloc_type_anything;
|
||||||
v->visitor.start_union = qapi_dealloc_start_union;
|
|
||||||
|
|
||||||
QTAILQ_INIT(&v->stack);
|
QTAILQ_INIT(&v->stack);
|
||||||
|
|
||||||
|
@ -30,29 +30,15 @@ void visit_end_struct(Visitor *v, Error **errp)
|
|||||||
v->end_struct(v, errp);
|
v->end_struct(v, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit_start_implicit_struct(Visitor *v, void **obj, size_t size,
|
|
||||||
Error **errp)
|
|
||||||
{
|
|
||||||
if (v->start_implicit_struct) {
|
|
||||||
v->start_implicit_struct(v, obj, size, errp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void visit_end_implicit_struct(Visitor *v)
|
|
||||||
{
|
|
||||||
if (v->end_implicit_struct) {
|
|
||||||
v->end_implicit_struct(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void visit_start_list(Visitor *v, const char *name, Error **errp)
|
void visit_start_list(Visitor *v, const char *name, Error **errp)
|
||||||
{
|
{
|
||||||
v->start_list(v, name, errp);
|
v->start_list(v, name, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericList *visit_next_list(Visitor *v, GenericList **list)
|
GenericList *visit_next_list(Visitor *v, GenericList **list, size_t size)
|
||||||
{
|
{
|
||||||
return v->next_list(v, list);
|
assert(list && size >= sizeof(GenericList));
|
||||||
|
return v->next_list(v, list, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit_end_list(Visitor *v)
|
void visit_end_list(Visitor *v)
|
||||||
@ -60,12 +46,21 @@ void visit_end_list(Visitor *v)
|
|||||||
v->end_list(v);
|
v->end_list(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool visit_start_union(Visitor *v, bool data_present, Error **errp)
|
void visit_start_alternate(Visitor *v, const char *name,
|
||||||
|
GenericAlternate **obj, size_t size,
|
||||||
|
bool promote_int, Error **errp)
|
||||||
{
|
{
|
||||||
if (v->start_union) {
|
assert(obj && size >= sizeof(GenericAlternate));
|
||||||
return v->start_union(v, data_present, errp);
|
if (v->start_alternate) {
|
||||||
|
v->start_alternate(v, name, obj, size, promote_int, errp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void visit_end_alternate(Visitor *v)
|
||||||
|
{
|
||||||
|
if (v->end_alternate) {
|
||||||
|
v->end_alternate(v);
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool visit_optional(Visitor *v, const char *name, bool *present)
|
bool visit_optional(Visitor *v, const char *name, bool *present)
|
||||||
@ -76,14 +71,6 @@ bool visit_optional(Visitor *v, const char *name, bool *present)
|
|||||||
return *present;
|
return *present;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit_get_next_type(Visitor *v, const char *name, QType *type,
|
|
||||||
bool promote_int, Error **errp)
|
|
||||||
{
|
|
||||||
if (v->get_next_type) {
|
|
||||||
v->get_next_type(v, name, type, promote_int, errp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void visit_type_enum(Visitor *v, const char *name, int *obj,
|
void visit_type_enum(Visitor *v, const char *name, int *obj,
|
||||||
const char *const strings[], Error **errp)
|
const char *const strings[], Error **errp)
|
||||||
{
|
{
|
||||||
|
@ -90,12 +90,6 @@ static void qmp_input_push(QmpInputVisitor *qiv, QObject *obj, Error **errp)
|
|||||||
qiv->nb_stack++;
|
qiv->nb_stack++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Only for qmp_input_pop. */
|
|
||||||
static gboolean always_true(gpointer key, gpointer val, gpointer user_pkey)
|
|
||||||
{
|
|
||||||
*(const char **)user_pkey = (const char *)key;
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
|
static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
|
||||||
{
|
{
|
||||||
@ -104,9 +98,11 @@ static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
|
|||||||
if (qiv->strict) {
|
if (qiv->strict) {
|
||||||
GHashTable * const top_ht = qiv->stack[qiv->nb_stack - 1].h;
|
GHashTable * const top_ht = qiv->stack[qiv->nb_stack - 1].h;
|
||||||
if (top_ht) {
|
if (top_ht) {
|
||||||
if (g_hash_table_size(top_ht)) {
|
GHashTableIter iter;
|
||||||
const char *key;
|
const char *key;
|
||||||
g_hash_table_find(top_ht, always_true, &key);
|
|
||||||
|
g_hash_table_iter_init(&iter, top_ht);
|
||||||
|
if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) {
|
||||||
error_setg(errp, QERR_QMP_EXTRA_MEMBER, key);
|
error_setg(errp, QERR_QMP_EXTRA_MEMBER, key);
|
||||||
}
|
}
|
||||||
g_hash_table_unref(top_ht);
|
g_hash_table_unref(top_ht);
|
||||||
@ -147,14 +143,6 @@ static void qmp_input_end_struct(Visitor *v, Error **errp)
|
|||||||
qmp_input_pop(qiv, errp);
|
qmp_input_pop(qiv, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qmp_input_start_implicit_struct(Visitor *v, void **obj,
|
|
||||||
size_t size, Error **errp)
|
|
||||||
{
|
|
||||||
if (obj) {
|
|
||||||
*obj = g_malloc0(size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
|
static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
|
||||||
{
|
{
|
||||||
QmpInputVisitor *qiv = to_qiv(v);
|
QmpInputVisitor *qiv = to_qiv(v);
|
||||||
@ -169,7 +157,8 @@ static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
|
|||||||
qmp_input_push(qiv, qobj, errp);
|
qmp_input_push(qiv, qobj, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GenericList *qmp_input_next_list(Visitor *v, GenericList **list)
|
static GenericList *qmp_input_next_list(Visitor *v, GenericList **list,
|
||||||
|
size_t size)
|
||||||
{
|
{
|
||||||
QmpInputVisitor *qiv = to_qiv(v);
|
QmpInputVisitor *qiv = to_qiv(v);
|
||||||
GenericList *entry;
|
GenericList *entry;
|
||||||
@ -188,7 +177,7 @@ static GenericList *qmp_input_next_list(Visitor *v, GenericList **list)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = g_malloc0(sizeof(*entry));
|
entry = g_malloc0(size);
|
||||||
if (first) {
|
if (first) {
|
||||||
*list = entry;
|
*list = entry;
|
||||||
} else {
|
} else {
|
||||||
@ -205,19 +194,22 @@ static void qmp_input_end_list(Visitor *v)
|
|||||||
qmp_input_pop(qiv, &error_abort);
|
qmp_input_pop(qiv, &error_abort);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qmp_input_get_next_type(Visitor *v, const char *name, QType *type,
|
static void qmp_input_start_alternate(Visitor *v, const char *name,
|
||||||
|
GenericAlternate **obj, size_t size,
|
||||||
bool promote_int, Error **errp)
|
bool promote_int, Error **errp)
|
||||||
{
|
{
|
||||||
QmpInputVisitor *qiv = to_qiv(v);
|
QmpInputVisitor *qiv = to_qiv(v);
|
||||||
QObject *qobj = qmp_input_get_object(qiv, name, false);
|
QObject *qobj = qmp_input_get_object(qiv, name, false);
|
||||||
|
|
||||||
if (!qobj) {
|
if (!qobj) {
|
||||||
|
*obj = NULL;
|
||||||
error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null");
|
error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*type = qobject_type(qobj);
|
*obj = g_malloc0(size);
|
||||||
if (promote_int && *type == QTYPE_QINT) {
|
(*obj)->type = qobject_type(qobj);
|
||||||
*type = QTYPE_QFLOAT;
|
if (promote_int && (*obj)->type == QTYPE_QINT) {
|
||||||
|
(*obj)->type = QTYPE_QFLOAT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,10 +340,10 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
|
|||||||
|
|
||||||
v->visitor.start_struct = qmp_input_start_struct;
|
v->visitor.start_struct = qmp_input_start_struct;
|
||||||
v->visitor.end_struct = qmp_input_end_struct;
|
v->visitor.end_struct = qmp_input_end_struct;
|
||||||
v->visitor.start_implicit_struct = qmp_input_start_implicit_struct;
|
|
||||||
v->visitor.start_list = qmp_input_start_list;
|
v->visitor.start_list = qmp_input_start_list;
|
||||||
v->visitor.next_list = qmp_input_next_list;
|
v->visitor.next_list = qmp_input_next_list;
|
||||||
v->visitor.end_list = qmp_input_end_list;
|
v->visitor.end_list = qmp_input_end_list;
|
||||||
|
v->visitor.start_alternate = qmp_input_start_alternate;
|
||||||
v->visitor.type_enum = input_type_enum;
|
v->visitor.type_enum = input_type_enum;
|
||||||
v->visitor.type_int64 = qmp_input_type_int64;
|
v->visitor.type_int64 = qmp_input_type_int64;
|
||||||
v->visitor.type_uint64 = qmp_input_type_uint64;
|
v->visitor.type_uint64 = qmp_input_type_uint64;
|
||||||
@ -360,7 +352,6 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
|
|||||||
v->visitor.type_number = qmp_input_type_number;
|
v->visitor.type_number = qmp_input_type_number;
|
||||||
v->visitor.type_any = qmp_input_type_any;
|
v->visitor.type_any = qmp_input_type_any;
|
||||||
v->visitor.optional = qmp_input_optional;
|
v->visitor.optional = qmp_input_optional;
|
||||||
v->visitor.get_next_type = qmp_input_get_next_type;
|
|
||||||
|
|
||||||
qmp_input_push(v, obj, NULL);
|
qmp_input_push(v, obj, NULL);
|
||||||
qobject_incref(obj);
|
qobject_incref(obj);
|
||||||
|
@ -126,7 +126,8 @@ static void qmp_output_start_list(Visitor *v, const char *name, Error **errp)
|
|||||||
qmp_output_push(qov, list);
|
qmp_output_push(qov, list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GenericList *qmp_output_next_list(Visitor *v, GenericList **listp)
|
static GenericList *qmp_output_next_list(Visitor *v, GenericList **listp,
|
||||||
|
size_t size)
|
||||||
{
|
{
|
||||||
GenericList *list = *listp;
|
GenericList *list = *listp;
|
||||||
QmpOutputVisitor *qov = to_qov(v);
|
QmpOutputVisitor *qov = to_qov(v);
|
||||||
|
@ -139,7 +139,7 @@ start_list(Visitor *v, const char *name, Error **errp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static GenericList *next_list(Visitor *v, GenericList **list)
|
static GenericList *next_list(Visitor *v, GenericList **list, size_t size)
|
||||||
{
|
{
|
||||||
StringInputVisitor *siv = to_siv(v);
|
StringInputVisitor *siv = to_siv(v);
|
||||||
GenericList **link;
|
GenericList **link;
|
||||||
@ -173,7 +173,7 @@ static GenericList *next_list(Visitor *v, GenericList **list)
|
|||||||
link = &(*list)->next;
|
link = &(*list)->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
*link = g_malloc0(sizeof **link);
|
*link = g_malloc0(size);
|
||||||
return *link;
|
return *link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,7 +276,7 @@ start_list(Visitor *v, const char *name, Error **errp)
|
|||||||
sov->head = true;
|
sov->head = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GenericList *next_list(Visitor *v, GenericList **list)
|
static GenericList *next_list(Visitor *v, GenericList **list, size_t size)
|
||||||
{
|
{
|
||||||
StringOutputVisitor *sov = to_sov(v);
|
StringOutputVisitor *sov = to_sov(v);
|
||||||
GenericList *ret = NULL;
|
GenericList *ret = NULL;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
# QAPI types generator
|
# QAPI types generator
|
||||||
#
|
#
|
||||||
# Copyright IBM, Corp. 2011
|
# Copyright IBM, Corp. 2011
|
||||||
# Copyright (c) 2013-2015 Red Hat Inc.
|
# Copyright (c) 2013-2016 Red Hat Inc.
|
||||||
#
|
#
|
||||||
# Authors:
|
# Authors:
|
||||||
# Anthony Liguori <aliguori@us.ibm.com>
|
# Anthony Liguori <aliguori@us.ibm.com>
|
||||||
@ -14,6 +14,11 @@
|
|||||||
from qapi import *
|
from qapi import *
|
||||||
|
|
||||||
|
|
||||||
|
# variants must be emitted before their container; track what has already
|
||||||
|
# been output
|
||||||
|
objects_seen = set()
|
||||||
|
|
||||||
|
|
||||||
def gen_fwd_object_or_array(name):
|
def gen_fwd_object_or_array(name):
|
||||||
return mcgen('''
|
return mcgen('''
|
||||||
|
|
||||||
@ -26,11 +31,8 @@ def gen_array(name, element_type):
|
|||||||
return mcgen('''
|
return mcgen('''
|
||||||
|
|
||||||
struct %(c_name)s {
|
struct %(c_name)s {
|
||||||
union {
|
|
||||||
%(c_type)s value;
|
|
||||||
uint64_t padding;
|
|
||||||
};
|
|
||||||
%(c_name)s *next;
|
%(c_name)s *next;
|
||||||
|
%(c_type)s value;
|
||||||
};
|
};
|
||||||
''',
|
''',
|
||||||
c_name=c_name(name), c_type=element_type.c_type())
|
c_name=c_name(name), c_type=element_type.c_type())
|
||||||
@ -52,7 +54,19 @@ def gen_struct_fields(members):
|
|||||||
|
|
||||||
|
|
||||||
def gen_object(name, base, members, variants):
|
def gen_object(name, base, members, variants):
|
||||||
ret = mcgen('''
|
if name in objects_seen:
|
||||||
|
return ''
|
||||||
|
objects_seen.add(name)
|
||||||
|
|
||||||
|
ret = ''
|
||||||
|
if variants:
|
||||||
|
for v in variants.variants:
|
||||||
|
if (isinstance(v.type, QAPISchemaObjectType) and
|
||||||
|
not v.type.is_implicit()):
|
||||||
|
ret += gen_object(v.type.name, v.type.base,
|
||||||
|
v.type.local_members, v.type.variants)
|
||||||
|
|
||||||
|
ret += mcgen('''
|
||||||
|
|
||||||
struct %(c_name)s {
|
struct %(c_name)s {
|
||||||
''',
|
''',
|
||||||
@ -118,11 +132,12 @@ def gen_variants(variants):
|
|||||||
|
|
||||||
for var in variants.variants:
|
for var in variants.variants:
|
||||||
# Ugly special case for simple union TODO get rid of it
|
# Ugly special case for simple union TODO get rid of it
|
||||||
typ = var.simple_union_type() or var.type
|
simple_union_type = var.simple_union_type()
|
||||||
|
typ = simple_union_type or var.type
|
||||||
ret += mcgen('''
|
ret += mcgen('''
|
||||||
%(c_type)s %(c_name)s;
|
%(c_type)s %(c_name)s;
|
||||||
''',
|
''',
|
||||||
c_type=typ.c_type(),
|
c_type=typ.c_type(is_unboxed=not simple_union_type),
|
||||||
c_name=c_name(var.name))
|
c_name=c_name(var.name))
|
||||||
|
|
||||||
ret += mcgen('''
|
ret += mcgen('''
|
||||||
|
@ -15,10 +15,6 @@
|
|||||||
from qapi import *
|
from qapi import *
|
||||||
import re
|
import re
|
||||||
|
|
||||||
# visit_type_FOO_implicit() is emitted as needed; track if it has already
|
|
||||||
# been output.
|
|
||||||
implicit_structs_seen = set()
|
|
||||||
|
|
||||||
# visit_type_FOO_fields() is always emitted; track if a forward declaration
|
# visit_type_FOO_fields() is always emitted; track if a forward declaration
|
||||||
# or implementation has already been output.
|
# or implementation has already been output.
|
||||||
struct_fields_seen = set()
|
struct_fields_seen = set()
|
||||||
@ -35,52 +31,31 @@ def gen_visit_decl(name, scalar=False):
|
|||||||
|
|
||||||
|
|
||||||
def gen_visit_fields_decl(typ):
|
def gen_visit_fields_decl(typ):
|
||||||
ret = ''
|
if typ.name in struct_fields_seen:
|
||||||
if typ.name not in struct_fields_seen:
|
|
||||||
ret += mcgen('''
|
|
||||||
|
|
||||||
static void visit_type_%(c_type)s_fields(Visitor *v, %(c_type)s **obj, Error **errp);
|
|
||||||
''',
|
|
||||||
c_type=typ.c_name())
|
|
||||||
struct_fields_seen.add(typ.name)
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
def gen_visit_implicit_struct(typ):
|
|
||||||
if typ in implicit_structs_seen:
|
|
||||||
return ''
|
return ''
|
||||||
implicit_structs_seen.add(typ)
|
struct_fields_seen.add(typ.name)
|
||||||
|
return mcgen('''
|
||||||
|
|
||||||
ret = gen_visit_fields_decl(typ)
|
static void visit_type_%(c_type)s_fields(Visitor *v, %(c_type)s *obj, Error **errp);
|
||||||
|
|
||||||
ret += mcgen('''
|
|
||||||
|
|
||||||
static void visit_type_implicit_%(c_type)s(Visitor *v, %(c_type)s **obj, Error **errp)
|
|
||||||
{
|
|
||||||
Error *err = NULL;
|
|
||||||
|
|
||||||
visit_start_implicit_struct(v, (void **)obj, sizeof(%(c_type)s), &err);
|
|
||||||
if (!err) {
|
|
||||||
visit_type_%(c_type)s_fields(v, obj, errp);
|
|
||||||
visit_end_implicit_struct(v);
|
|
||||||
}
|
|
||||||
error_propagate(errp, err);
|
|
||||||
}
|
|
||||||
''',
|
''',
|
||||||
c_type=typ.c_name())
|
c_type=typ.c_name())
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
def gen_visit_struct_fields(name, base, members):
|
def gen_visit_struct_fields(name, base, members, variants):
|
||||||
ret = ''
|
ret = ''
|
||||||
|
|
||||||
if base:
|
if base:
|
||||||
ret += gen_visit_fields_decl(base)
|
ret += gen_visit_fields_decl(base)
|
||||||
|
if variants:
|
||||||
|
for var in variants.variants:
|
||||||
|
# Ugly special case for simple union TODO get rid of it
|
||||||
|
if not var.simple_union_type():
|
||||||
|
ret += gen_visit_fields_decl(var.type)
|
||||||
|
|
||||||
struct_fields_seen.add(name)
|
struct_fields_seen.add(name)
|
||||||
ret += mcgen('''
|
ret += mcgen('''
|
||||||
|
|
||||||
static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s **obj, Error **errp)
|
static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s *obj, Error **errp)
|
||||||
{
|
{
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
@ -89,57 +64,61 @@ def gen_visit_struct_fields(name, base, members):
|
|||||||
|
|
||||||
if base:
|
if base:
|
||||||
ret += mcgen('''
|
ret += mcgen('''
|
||||||
visit_type_%(c_type)s_fields(v, (%(c_type)s **)obj, &err);
|
visit_type_%(c_type)s_fields(v, (%(c_type)s *)obj, &err);
|
||||||
''',
|
''',
|
||||||
c_type=base.c_name())
|
c_type=base.c_name())
|
||||||
ret += gen_err_check()
|
ret += gen_err_check()
|
||||||
|
|
||||||
ret += gen_visit_fields(members, prefix='(*obj)->')
|
ret += gen_visit_fields(members, prefix='obj->')
|
||||||
|
|
||||||
# 'goto out' produced for base, and by gen_visit_fields() for each member
|
if variants:
|
||||||
if base or members:
|
|
||||||
ret += mcgen('''
|
ret += mcgen('''
|
||||||
|
switch (obj->%(c_name)s) {
|
||||||
out:
|
|
||||||
''')
|
|
||||||
ret += mcgen('''
|
|
||||||
error_propagate(errp, err);
|
|
||||||
}
|
|
||||||
''')
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
def gen_visit_struct(name, base, members):
|
|
||||||
ret = gen_visit_struct_fields(name, base, members)
|
|
||||||
|
|
||||||
# FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to
|
|
||||||
# *obj, but then visit_type_FOO_fields() fails, we should clean up *obj
|
|
||||||
# rather than leaving it non-NULL. As currently written, the caller must
|
|
||||||
# call qapi_free_FOO() to avoid a memory leak of the partial FOO.
|
|
||||||
ret += mcgen('''
|
|
||||||
|
|
||||||
void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp)
|
|
||||||
{
|
|
||||||
Error *err = NULL;
|
|
||||||
|
|
||||||
visit_start_struct(v, name, (void **)obj, sizeof(%(c_name)s), &err);
|
|
||||||
if (err) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (!*obj) {
|
|
||||||
goto out_obj;
|
|
||||||
}
|
|
||||||
visit_type_%(c_name)s_fields(v, obj, &err);
|
|
||||||
error_propagate(errp, err);
|
|
||||||
err = NULL;
|
|
||||||
out_obj:
|
|
||||||
visit_end_struct(v, &err);
|
|
||||||
out:
|
|
||||||
error_propagate(errp, err);
|
|
||||||
}
|
|
||||||
''',
|
''',
|
||||||
c_name=c_name(name))
|
c_name=c_name(variants.tag_member.name))
|
||||||
|
|
||||||
|
for var in variants.variants:
|
||||||
|
# TODO ugly special case for simple union
|
||||||
|
simple_union_type = var.simple_union_type()
|
||||||
|
ret += mcgen('''
|
||||||
|
case %(case)s:
|
||||||
|
''',
|
||||||
|
case=c_enum_const(variants.tag_member.type.name,
|
||||||
|
var.name,
|
||||||
|
variants.tag_member.type.prefix))
|
||||||
|
if simple_union_type:
|
||||||
|
ret += mcgen('''
|
||||||
|
visit_type_%(c_type)s(v, "data", &obj->u.%(c_name)s, &err);
|
||||||
|
''',
|
||||||
|
c_type=simple_union_type.c_name(),
|
||||||
|
c_name=c_name(var.name))
|
||||||
|
else:
|
||||||
|
ret += mcgen('''
|
||||||
|
visit_type_%(c_type)s_fields(v, &obj->u.%(c_name)s, &err);
|
||||||
|
''',
|
||||||
|
c_type=var.type.c_name(),
|
||||||
|
c_name=c_name(var.name))
|
||||||
|
ret += mcgen('''
|
||||||
|
break;
|
||||||
|
''')
|
||||||
|
|
||||||
|
ret += mcgen('''
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
''')
|
||||||
|
|
||||||
|
# 'goto out' produced for base, by gen_visit_fields() for each member,
|
||||||
|
# and if variants were present
|
||||||
|
if base or members or variants:
|
||||||
|
ret += mcgen('''
|
||||||
|
|
||||||
|
out:
|
||||||
|
''')
|
||||||
|
ret += mcgen('''
|
||||||
|
error_propagate(errp, err);
|
||||||
|
}
|
||||||
|
''')
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
@ -161,7 +140,7 @@ def gen_visit_list(name, element_type):
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (prev = (GenericList **)obj;
|
for (prev = (GenericList **)obj;
|
||||||
!err && (i = visit_next_list(v, prev)) != NULL;
|
!err && (i = visit_next_list(v, prev, sizeof(**obj))) != NULL;
|
||||||
prev = &i) {
|
prev = &i) {
|
||||||
%(c_name)s *native_i = (%(c_name)s *)i;
|
%(c_name)s *native_i = (%(c_name)s *)i;
|
||||||
visit_type_%(c_elt_type)s(v, NULL, &native_i->value, &err);
|
visit_type_%(c_elt_type)s(v, NULL, &native_i->value, &err);
|
||||||
@ -190,24 +169,24 @@ def gen_visit_enum(name):
|
|||||||
|
|
||||||
def gen_visit_alternate(name, variants):
|
def gen_visit_alternate(name, variants):
|
||||||
promote_int = 'true'
|
promote_int = 'true'
|
||||||
|
ret = ''
|
||||||
for var in variants.variants:
|
for var in variants.variants:
|
||||||
if var.type.alternate_qtype() == 'QTYPE_QINT':
|
if var.type.alternate_qtype() == 'QTYPE_QINT':
|
||||||
promote_int = 'false'
|
promote_int = 'false'
|
||||||
|
if isinstance(var.type, QAPISchemaObjectType):
|
||||||
|
ret += gen_visit_fields_decl(var.type)
|
||||||
|
|
||||||
ret = mcgen('''
|
ret += mcgen('''
|
||||||
|
|
||||||
void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp)
|
void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp)
|
||||||
{
|
{
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
visit_start_implicit_struct(v, (void**) obj, sizeof(%(c_name)s), &err);
|
visit_start_alternate(v, name, (GenericAlternate **)obj, sizeof(**obj),
|
||||||
|
%(promote_int)s, &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
visit_get_next_type(v, name, &(*obj)->type, %(promote_int)s, &err);
|
|
||||||
if (err) {
|
|
||||||
goto out_obj;
|
|
||||||
}
|
|
||||||
switch ((*obj)->type) {
|
switch ((*obj)->type) {
|
||||||
''',
|
''',
|
||||||
c_name=c_name(name), promote_int=promote_int)
|
c_name=c_name(name), promote_int=promote_int)
|
||||||
@ -215,20 +194,37 @@ def gen_visit_alternate(name, variants):
|
|||||||
for var in variants.variants:
|
for var in variants.variants:
|
||||||
ret += mcgen('''
|
ret += mcgen('''
|
||||||
case %(case)s:
|
case %(case)s:
|
||||||
visit_type_%(c_type)s(v, name, &(*obj)->u.%(c_name)s, &err);
|
|
||||||
break;
|
|
||||||
''',
|
''',
|
||||||
case=var.type.alternate_qtype(),
|
case=var.type.alternate_qtype())
|
||||||
|
if isinstance(var.type, QAPISchemaObjectType):
|
||||||
|
ret += mcgen('''
|
||||||
|
visit_start_struct(v, name, NULL, 0, &err);
|
||||||
|
if (err) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
visit_type_%(c_type)s_fields(v, &(*obj)->u.%(c_name)s, &err);
|
||||||
|
error_propagate(errp, err);
|
||||||
|
err = NULL;
|
||||||
|
visit_end_struct(v, &err);
|
||||||
|
''',
|
||||||
c_type=var.type.c_name(),
|
c_type=var.type.c_name(),
|
||||||
c_name=c_name(var.name))
|
c_name=c_name(var.name))
|
||||||
|
else:
|
||||||
|
ret += mcgen('''
|
||||||
|
visit_type_%(c_type)s(v, name, &(*obj)->u.%(c_name)s, &err);
|
||||||
|
''',
|
||||||
|
c_type=var.type.c_name(),
|
||||||
|
c_name=c_name(var.name))
|
||||||
|
ret += mcgen('''
|
||||||
|
break;
|
||||||
|
''')
|
||||||
|
|
||||||
ret += mcgen('''
|
ret += mcgen('''
|
||||||
default:
|
default:
|
||||||
error_setg(&err, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
|
error_setg(&err, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
|
||||||
"%(name)s");
|
"%(name)s");
|
||||||
}
|
}
|
||||||
out_obj:
|
visit_end_alternate(v);
|
||||||
visit_end_implicit_struct(v);
|
|
||||||
out:
|
out:
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
}
|
}
|
||||||
@ -238,17 +234,13 @@ def gen_visit_alternate(name, variants):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def gen_visit_union(name, base, variants):
|
def gen_visit_object(name, base, members, variants):
|
||||||
ret = ''
|
ret = gen_visit_struct_fields(name, base, members, variants)
|
||||||
|
|
||||||
if base:
|
|
||||||
ret += gen_visit_fields_decl(base)
|
|
||||||
|
|
||||||
for var in variants.variants:
|
|
||||||
# Ugly special case for simple union TODO get rid of it
|
|
||||||
if not var.simple_union_type():
|
|
||||||
ret += gen_visit_implicit_struct(var.type)
|
|
||||||
|
|
||||||
|
# FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to
|
||||||
|
# *obj, but then visit_type_FOO_fields() fails, we should clean up *obj
|
||||||
|
# rather than leaving it non-NULL. As currently written, the caller must
|
||||||
|
# call qapi_free_FOO() to avoid a memory leak of the partial FOO.
|
||||||
ret += mcgen('''
|
ret += mcgen('''
|
||||||
|
|
||||||
void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp)
|
void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp)
|
||||||
@ -262,66 +254,16 @@ def gen_visit_union(name, base, variants):
|
|||||||
if (!*obj) {
|
if (!*obj) {
|
||||||
goto out_obj;
|
goto out_obj;
|
||||||
}
|
}
|
||||||
''',
|
visit_type_%(c_name)s_fields(v, *obj, &err);
|
||||||
c_name=c_name(name))
|
|
||||||
|
|
||||||
if base:
|
|
||||||
ret += mcgen('''
|
|
||||||
visit_type_%(c_name)s_fields(v, (%(c_name)s **)obj, &err);
|
|
||||||
''',
|
|
||||||
c_name=base.c_name())
|
|
||||||
else:
|
|
||||||
ret += mcgen('''
|
|
||||||
visit_type_%(c_type)s(v, "%(name)s", &(*obj)->%(c_name)s, &err);
|
|
||||||
''',
|
|
||||||
c_type=variants.tag_member.type.c_name(),
|
|
||||||
c_name=c_name(variants.tag_member.name),
|
|
||||||
name=variants.tag_member.name)
|
|
||||||
ret += gen_err_check(label='out_obj')
|
|
||||||
ret += mcgen('''
|
|
||||||
if (!visit_start_union(v, !!(*obj)->u.data, &err) || err) {
|
|
||||||
goto out_obj;
|
|
||||||
}
|
|
||||||
switch ((*obj)->%(c_name)s) {
|
|
||||||
''',
|
|
||||||
c_name=c_name(variants.tag_member.name))
|
|
||||||
|
|
||||||
for var in variants.variants:
|
|
||||||
# TODO ugly special case for simple union
|
|
||||||
simple_union_type = var.simple_union_type()
|
|
||||||
ret += mcgen('''
|
|
||||||
case %(case)s:
|
|
||||||
''',
|
|
||||||
case=c_enum_const(variants.tag_member.type.name,
|
|
||||||
var.name))
|
|
||||||
if simple_union_type:
|
|
||||||
ret += mcgen('''
|
|
||||||
visit_type_%(c_type)s(v, "data", &(*obj)->u.%(c_name)s, &err);
|
|
||||||
''',
|
|
||||||
c_type=simple_union_type.c_name(),
|
|
||||||
c_name=c_name(var.name))
|
|
||||||
else:
|
|
||||||
ret += mcgen('''
|
|
||||||
visit_type_implicit_%(c_type)s(v, &(*obj)->u.%(c_name)s, &err);
|
|
||||||
''',
|
|
||||||
c_type=var.type.c_name(),
|
|
||||||
c_name=c_name(var.name))
|
|
||||||
ret += mcgen('''
|
|
||||||
break;
|
|
||||||
''')
|
|
||||||
|
|
||||||
ret += mcgen('''
|
|
||||||
default:
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
out_obj:
|
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
err = NULL;
|
err = NULL;
|
||||||
|
out_obj:
|
||||||
visit_end_struct(v, &err);
|
visit_end_struct(v, &err);
|
||||||
out:
|
out:
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
}
|
}
|
||||||
''')
|
''',
|
||||||
|
c_name=c_name(name))
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@ -375,14 +317,7 @@ def visit_array_type(self, name, info, element_type):
|
|||||||
|
|
||||||
def visit_object_type(self, name, info, base, members, variants):
|
def visit_object_type(self, name, info, base, members, variants):
|
||||||
self.decl += gen_visit_decl(name)
|
self.decl += gen_visit_decl(name)
|
||||||
if variants:
|
self.defn += gen_visit_object(name, base, members, variants)
|
||||||
if members:
|
|
||||||
# Members other than variants.tag_member not implemented
|
|
||||||
assert len(members) == 1
|
|
||||||
assert members[0] == variants.tag_member
|
|
||||||
self.defn += gen_visit_union(name, base, variants)
|
|
||||||
else:
|
|
||||||
self.defn += gen_visit_struct(name, base, members)
|
|
||||||
|
|
||||||
def visit_alternate_type(self, name, info, variants):
|
def visit_alternate_type(self, name, info, variants):
|
||||||
self.decl += gen_visit_decl(name)
|
self.decl += gen_visit_decl(name)
|
||||||
|
@ -590,7 +590,10 @@ def check_union(expr, expr_info):
|
|||||||
"Discriminator '%s' must be of enumeration "
|
"Discriminator '%s' must be of enumeration "
|
||||||
"type" % discriminator)
|
"type" % discriminator)
|
||||||
|
|
||||||
# Check every branch
|
# Check every branch; don't allow an empty union
|
||||||
|
if len(members) == 0:
|
||||||
|
raise QAPIExprError(expr_info,
|
||||||
|
"Union '%s' cannot have empty 'data'" % name)
|
||||||
for (key, value) in members.items():
|
for (key, value) in members.items():
|
||||||
check_name(expr_info, "Member of union '%s'" % name, key)
|
check_name(expr_info, "Member of union '%s'" % name, key)
|
||||||
|
|
||||||
@ -613,7 +616,11 @@ def check_alternate(expr, expr_info):
|
|||||||
members = expr['data']
|
members = expr['data']
|
||||||
types_seen = {}
|
types_seen = {}
|
||||||
|
|
||||||
# Check every branch
|
# Check every branch; require at least two branches
|
||||||
|
if len(members) < 2:
|
||||||
|
raise QAPIExprError(expr_info,
|
||||||
|
"Alternate '%s' should have at least two branches "
|
||||||
|
"in 'data'" % name)
|
||||||
for (key, value) in members.items():
|
for (key, value) in members.items():
|
||||||
check_name(expr_info, "Member of alternate '%s'" % name, key)
|
check_name(expr_info, "Member of alternate '%s'" % name, key)
|
||||||
|
|
||||||
@ -622,7 +629,10 @@ def check_alternate(expr, expr_info):
|
|||||||
value,
|
value,
|
||||||
allow_metas=['built-in', 'union', 'struct', 'enum'])
|
allow_metas=['built-in', 'union', 'struct', 'enum'])
|
||||||
qtype = find_alternate_member_qtype(value)
|
qtype = find_alternate_member_qtype(value)
|
||||||
assert qtype
|
if not qtype:
|
||||||
|
raise QAPIExprError(expr_info,
|
||||||
|
"Alternate '%s' member '%s' cannot use "
|
||||||
|
"type '%s'" % (name, key, value))
|
||||||
if qtype in types_seen:
|
if qtype in types_seen:
|
||||||
raise QAPIExprError(expr_info,
|
raise QAPIExprError(expr_info,
|
||||||
"Alternate '%s' member '%s' can't "
|
"Alternate '%s' member '%s' can't "
|
||||||
@ -814,7 +824,7 @@ def visit_event(self, name, info, arg_type):
|
|||||||
|
|
||||||
|
|
||||||
class QAPISchemaType(QAPISchemaEntity):
|
class QAPISchemaType(QAPISchemaEntity):
|
||||||
def c_type(self, is_param=False):
|
def c_type(self, is_param=False, is_unboxed=False):
|
||||||
return c_name(self.name) + pointer_suffix
|
return c_name(self.name) + pointer_suffix
|
||||||
|
|
||||||
def c_null(self):
|
def c_null(self):
|
||||||
@ -847,7 +857,7 @@ def __init__(self, name, json_type, c_type, c_null):
|
|||||||
def c_name(self):
|
def c_name(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def c_type(self, is_param=False):
|
def c_type(self, is_param=False, is_unboxed=False):
|
||||||
if is_param and self.name == 'str':
|
if is_param and self.name == 'str':
|
||||||
return 'const ' + self._c_type_name
|
return 'const ' + self._c_type_name
|
||||||
return self._c_type_name
|
return self._c_type_name
|
||||||
@ -881,7 +891,7 @@ def is_implicit(self):
|
|||||||
# See QAPISchema._make_implicit_enum_type()
|
# See QAPISchema._make_implicit_enum_type()
|
||||||
return self.name.endswith('Kind')
|
return self.name.endswith('Kind')
|
||||||
|
|
||||||
def c_type(self, is_param=False):
|
def c_type(self, is_param=False, is_unboxed=False):
|
||||||
return c_name(self.name)
|
return c_name(self.name)
|
||||||
|
|
||||||
def member_names(self):
|
def member_names(self):
|
||||||
@ -977,9 +987,11 @@ def c_name(self):
|
|||||||
assert not self.is_implicit()
|
assert not self.is_implicit()
|
||||||
return QAPISchemaType.c_name(self)
|
return QAPISchemaType.c_name(self)
|
||||||
|
|
||||||
def c_type(self, is_param=False):
|
def c_type(self, is_param=False, is_unboxed=False):
|
||||||
assert not self.is_implicit()
|
assert not self.is_implicit()
|
||||||
return QAPISchemaType.c_type(self)
|
if is_unboxed:
|
||||||
|
return c_name(self.name)
|
||||||
|
return c_name(self.name) + pointer_suffix
|
||||||
|
|
||||||
def json_type(self):
|
def json_type(self):
|
||||||
return 'object'
|
return 'object'
|
||||||
@ -1059,6 +1071,7 @@ def __init__(self, tag_name, tag_member, variants):
|
|||||||
assert bool(tag_member) != bool(tag_name)
|
assert bool(tag_member) != bool(tag_name)
|
||||||
assert (isinstance(tag_name, str) or
|
assert (isinstance(tag_name, str) or
|
||||||
isinstance(tag_member, QAPISchemaObjectTypeMember))
|
isinstance(tag_member, QAPISchemaObjectTypeMember))
|
||||||
|
assert len(variants) > 0
|
||||||
for v in variants:
|
for v in variants:
|
||||||
assert isinstance(v, QAPISchemaObjectTypeVariant)
|
assert isinstance(v, QAPISchemaObjectTypeVariant)
|
||||||
self.tag_name = tag_name
|
self.tag_name = tag_name
|
||||||
|
@ -242,6 +242,7 @@ check-qtest-xtensaeb-y = $(check-qtest-xtensa-y)
|
|||||||
|
|
||||||
check-qtest-generic-y += tests/qom-test$(EXESUF)
|
check-qtest-generic-y += tests/qom-test$(EXESUF)
|
||||||
|
|
||||||
|
qapi-schema += alternate-any.json
|
||||||
qapi-schema += alternate-array.json
|
qapi-schema += alternate-array.json
|
||||||
qapi-schema += alternate-base.json
|
qapi-schema += alternate-base.json
|
||||||
qapi-schema += alternate-clash.json
|
qapi-schema += alternate-clash.json
|
||||||
|
1
tests/qapi-schema/alternate-any.err
Normal file
1
tests/qapi-schema/alternate-any.err
Normal file
@ -0,0 +1 @@
|
|||||||
|
tests/qapi-schema/alternate-any.json:2: Alternate 'Alt' member 'one' cannot use type 'any'
|
1
tests/qapi-schema/alternate-any.exit
Normal file
1
tests/qapi-schema/alternate-any.exit
Normal file
@ -0,0 +1 @@
|
|||||||
|
1
|
4
tests/qapi-schema/alternate-any.json
Normal file
4
tests/qapi-schema/alternate-any.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# we do not allow the 'any' type as an alternate branch
|
||||||
|
{ 'alternate': 'Alt',
|
||||||
|
'data': { 'one': 'any',
|
||||||
|
'two': 'int' } }
|
0
tests/qapi-schema/alternate-any.out
Normal file
0
tests/qapi-schema/alternate-any.out
Normal file
@ -0,0 +1 @@
|
|||||||
|
tests/qapi-schema/alternate-empty.json:2: Alternate 'Alt' should have at least two branches in 'data'
|
@ -1 +1 @@
|
|||||||
0
|
1
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
# FIXME - alternates should list at least two types to be useful
|
# alternates must list at least two types to be useful
|
||||||
{ 'alternate': 'Alt', 'data': { 'i': 'int' } }
|
{ 'alternate': 'Alt', 'data': { 'i': 'int' } }
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
object :empty
|
|
||||||
alternate Alt
|
|
||||||
case i: int
|
|
||||||
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
|
|
||||||
prefix QTYPE
|
|
@ -0,0 +1 @@
|
|||||||
|
tests/qapi-schema/flat-union-empty.json:4: Union 'Union' cannot have empty 'data'
|
@ -1 +1 @@
|
|||||||
0
|
1
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# FIXME - flat unions should not be empty
|
# flat unions cannot be empty
|
||||||
{ 'enum': 'Empty', 'data': [ ] }
|
{ 'enum': 'Empty', 'data': [ ] }
|
||||||
{ 'struct': 'Base', 'data': { 'type': 'Empty' } }
|
{ 'struct': 'Base', 'data': { 'type': 'Empty' } }
|
||||||
{ 'union': 'Union', 'base': 'Base', 'discriminator': 'type', 'data': { } }
|
{ 'union': 'Union', 'base': 'Base', 'discriminator': 'type', 'data': { } }
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
object :empty
|
|
||||||
object Base
|
|
||||||
member type: Empty optional=False
|
|
||||||
enum Empty []
|
|
||||||
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
|
|
||||||
prefix QTYPE
|
|
||||||
object Union
|
|
||||||
base Base
|
|
||||||
tag type
|
|
@ -73,17 +73,22 @@
|
|||||||
'base': 'UserDefZero',
|
'base': 'UserDefZero',
|
||||||
'data': { 'string': 'str', 'enum1': 'EnumOne' } }
|
'data': { 'string': 'str', 'enum1': 'EnumOne' } }
|
||||||
|
|
||||||
|
{ 'struct': 'UserDefUnionBase2',
|
||||||
|
'base': 'UserDefZero',
|
||||||
|
'data': { 'string': 'str', 'enum1': 'QEnumTwo' } }
|
||||||
|
|
||||||
# this variant of UserDefFlatUnion defaults to a union that uses fields with
|
# this variant of UserDefFlatUnion defaults to a union that uses fields with
|
||||||
# allocated types to test corner cases in the cleanup/dealloc visitor
|
# allocated types to test corner cases in the cleanup/dealloc visitor
|
||||||
{ 'union': 'UserDefFlatUnion2',
|
{ 'union': 'UserDefFlatUnion2',
|
||||||
'base': 'UserDefUnionBase',
|
'base': 'UserDefUnionBase2',
|
||||||
'discriminator': 'enum1',
|
'discriminator': 'enum1',
|
||||||
'data': { 'value1' : 'UserDefC', # intentional forward reference
|
'data': { 'value1' : 'UserDefC', # intentional forward reference
|
||||||
'value2' : 'UserDefB',
|
'value2' : 'UserDefB' } }
|
||||||
'value3' : 'UserDefA' } }
|
|
||||||
|
|
||||||
|
{ 'struct': 'WrapAlternate',
|
||||||
|
'data': { 'alt': 'UserDefAlternate' } }
|
||||||
{ 'alternate': 'UserDefAlternate',
|
{ 'alternate': 'UserDefAlternate',
|
||||||
'data': { 'uda': 'UserDefA', 's': 'str', 'i': 'int' } }
|
'data': { 'udfu': 'UserDefFlatUnion', 's': 'str', 'i': 'int' } }
|
||||||
|
|
||||||
{ 'struct': 'UserDefC',
|
{ 'struct': 'UserDefC',
|
||||||
'data': { 'string1': 'str', 'string2': 'str' } }
|
'data': { 'string1': 'str', 'string2': 'str' } }
|
||||||
|
@ -105,7 +105,7 @@ object UserDefA
|
|||||||
member boolean: bool optional=False
|
member boolean: bool optional=False
|
||||||
member a_b: int optional=True
|
member a_b: int optional=True
|
||||||
alternate UserDefAlternate
|
alternate UserDefAlternate
|
||||||
case uda: UserDefA
|
case udfu: UserDefFlatUnion
|
||||||
case s: str
|
case s: str
|
||||||
case i: int
|
case i: int
|
||||||
object UserDefB
|
object UserDefB
|
||||||
@ -121,11 +121,10 @@ object UserDefFlatUnion
|
|||||||
case value2: UserDefB
|
case value2: UserDefB
|
||||||
case value3: UserDefB
|
case value3: UserDefB
|
||||||
object UserDefFlatUnion2
|
object UserDefFlatUnion2
|
||||||
base UserDefUnionBase
|
base UserDefUnionBase2
|
||||||
tag enum1
|
tag enum1
|
||||||
case value1: UserDefC
|
case value1: UserDefC
|
||||||
case value2: UserDefB
|
case value2: UserDefB
|
||||||
case value3: UserDefA
|
|
||||||
object UserDefNativeListUnion
|
object UserDefNativeListUnion
|
||||||
member type: UserDefNativeListUnionKind optional=False
|
member type: UserDefNativeListUnionKind optional=False
|
||||||
case integer: :obj-intList-wrapper
|
case integer: :obj-intList-wrapper
|
||||||
@ -167,8 +166,14 @@ object UserDefUnionBase
|
|||||||
base UserDefZero
|
base UserDefZero
|
||||||
member string: str optional=False
|
member string: str optional=False
|
||||||
member enum1: EnumOne optional=False
|
member enum1: EnumOne optional=False
|
||||||
|
object UserDefUnionBase2
|
||||||
|
base UserDefZero
|
||||||
|
member string: str optional=False
|
||||||
|
member enum1: QEnumTwo optional=False
|
||||||
object UserDefZero
|
object UserDefZero
|
||||||
member integer: int optional=False
|
member integer: int optional=False
|
||||||
|
object WrapAlternate
|
||||||
|
member alt: UserDefAlternate optional=False
|
||||||
event __ORG.QEMU_X-EVENT __org.qemu_x-Struct
|
event __ORG.QEMU_X-EVENT __org.qemu_x-Struct
|
||||||
alternate __org.qemu_x-Alt
|
alternate __org.qemu_x-Alt
|
||||||
case __org.qemu_x-branch: str
|
case __org.qemu_x-branch: str
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
tests/qapi-schema/union-empty.json:2: Union 'Union' cannot have empty 'data'
|
@ -1 +1 @@
|
|||||||
0
|
1
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
# FIXME - unions should not be empty
|
# unions cannot be empty
|
||||||
{ 'union': 'Union', 'data': { } }
|
{ 'union': 'Union', 'data': { } }
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
object :empty
|
|
||||||
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
|
|
||||||
prefix QTYPE
|
|
||||||
object Union
|
|
||||||
member type: UnionKind optional=False
|
|
||||||
enum UnionKind []
|
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* QMP Input Visitor unit-tests.
|
* QMP Input Visitor unit-tests.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2011, 2015 Red Hat Inc.
|
* Copyright (C) 2011-2016 Red Hat Inc.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
* Luiz Capitulino <lcapitulino@redhat.com>
|
* Luiz Capitulino <lcapitulino@redhat.com>
|
||||||
@ -295,7 +295,7 @@ static void test_visitor_in_union_flat(TestInputVisitorData *data,
|
|||||||
g_assert_cmpint(tmp->enum1, ==, ENUM_ONE_VALUE1);
|
g_assert_cmpint(tmp->enum1, ==, ENUM_ONE_VALUE1);
|
||||||
g_assert_cmpstr(tmp->string, ==, "str");
|
g_assert_cmpstr(tmp->string, ==, "str");
|
||||||
g_assert_cmpint(tmp->integer, ==, 41);
|
g_assert_cmpint(tmp->integer, ==, 41);
|
||||||
g_assert_cmpint(tmp->u.value1->boolean, ==, true);
|
g_assert_cmpint(tmp->u.value1.boolean, ==, true);
|
||||||
|
|
||||||
base = qapi_UserDefFlatUnion_base(tmp);
|
base = qapi_UserDefFlatUnion_base(tmp);
|
||||||
g_assert(&base->enum1 == &tmp->enum1);
|
g_assert(&base->enum1 == &tmp->enum1);
|
||||||
@ -309,6 +309,7 @@ static void test_visitor_in_alternate(TestInputVisitorData *data,
|
|||||||
Visitor *v;
|
Visitor *v;
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
UserDefAlternate *tmp;
|
UserDefAlternate *tmp;
|
||||||
|
WrapAlternate *wrap;
|
||||||
|
|
||||||
v = visitor_input_test_init(data, "42");
|
v = visitor_input_test_init(data, "42");
|
||||||
visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort);
|
visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort);
|
||||||
@ -322,10 +323,44 @@ static void test_visitor_in_alternate(TestInputVisitorData *data,
|
|||||||
g_assert_cmpstr(tmp->u.s, ==, "string");
|
g_assert_cmpstr(tmp->u.s, ==, "string");
|
||||||
qapi_free_UserDefAlternate(tmp);
|
qapi_free_UserDefAlternate(tmp);
|
||||||
|
|
||||||
|
v = visitor_input_test_init(data, "{'integer':1, 'string':'str', "
|
||||||
|
"'enum1':'value1', 'boolean':true}");
|
||||||
|
visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort);
|
||||||
|
g_assert_cmpint(tmp->type, ==, QTYPE_QDICT);
|
||||||
|
g_assert_cmpint(tmp->u.udfu.integer, ==, 1);
|
||||||
|
g_assert_cmpstr(tmp->u.udfu.string, ==, "str");
|
||||||
|
g_assert_cmpint(tmp->u.udfu.enum1, ==, ENUM_ONE_VALUE1);
|
||||||
|
g_assert_cmpint(tmp->u.udfu.u.value1.boolean, ==, true);
|
||||||
|
g_assert_cmpint(tmp->u.udfu.u.value1.has_a_b, ==, false);
|
||||||
|
qapi_free_UserDefAlternate(tmp);
|
||||||
|
|
||||||
v = visitor_input_test_init(data, "false");
|
v = visitor_input_test_init(data, "false");
|
||||||
visit_type_UserDefAlternate(v, NULL, &tmp, &err);
|
visit_type_UserDefAlternate(v, NULL, &tmp, &err);
|
||||||
error_free_or_abort(&err);
|
error_free_or_abort(&err);
|
||||||
qapi_free_UserDefAlternate(tmp);
|
qapi_free_UserDefAlternate(tmp);
|
||||||
|
|
||||||
|
v = visitor_input_test_init(data, "{ 'alt': 42 }");
|
||||||
|
visit_type_WrapAlternate(v, NULL, &wrap, &error_abort);
|
||||||
|
g_assert_cmpint(wrap->alt->type, ==, QTYPE_QINT);
|
||||||
|
g_assert_cmpint(wrap->alt->u.i, ==, 42);
|
||||||
|
qapi_free_WrapAlternate(wrap);
|
||||||
|
|
||||||
|
v = visitor_input_test_init(data, "{ 'alt': 'string' }");
|
||||||
|
visit_type_WrapAlternate(v, NULL, &wrap, &error_abort);
|
||||||
|
g_assert_cmpint(wrap->alt->type, ==, QTYPE_QSTRING);
|
||||||
|
g_assert_cmpstr(wrap->alt->u.s, ==, "string");
|
||||||
|
qapi_free_WrapAlternate(wrap);
|
||||||
|
|
||||||
|
v = visitor_input_test_init(data, "{ 'alt': {'integer':1, 'string':'str', "
|
||||||
|
"'enum1':'value1', 'boolean':true} }");
|
||||||
|
visit_type_WrapAlternate(v, NULL, &wrap, &error_abort);
|
||||||
|
g_assert_cmpint(wrap->alt->type, ==, QTYPE_QDICT);
|
||||||
|
g_assert_cmpint(wrap->alt->u.udfu.integer, ==, 1);
|
||||||
|
g_assert_cmpstr(wrap->alt->u.udfu.string, ==, "str");
|
||||||
|
g_assert_cmpint(wrap->alt->u.udfu.enum1, ==, ENUM_ONE_VALUE1);
|
||||||
|
g_assert_cmpint(wrap->alt->u.udfu.u.value1.boolean, ==, true);
|
||||||
|
g_assert_cmpint(wrap->alt->u.udfu.u.value1.has_a_b, ==, false);
|
||||||
|
qapi_free_WrapAlternate(wrap);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_visitor_in_alternate_number(TestInputVisitorData *data,
|
static void test_visitor_in_alternate_number(TestInputVisitorData *data,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* QMP Output Visitor unit-tests.
|
* QMP Output Visitor unit-tests.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2011, 2015 Red Hat Inc.
|
* Copyright (C) 2011-2016 Red Hat Inc.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
* Luiz Capitulino <lcapitulino@redhat.com>
|
* Luiz Capitulino <lcapitulino@redhat.com>
|
||||||
@ -403,9 +403,8 @@ static void test_visitor_out_union_flat(TestOutputVisitorData *data,
|
|||||||
UserDefFlatUnion *tmp = g_malloc0(sizeof(UserDefFlatUnion));
|
UserDefFlatUnion *tmp = g_malloc0(sizeof(UserDefFlatUnion));
|
||||||
tmp->enum1 = ENUM_ONE_VALUE1;
|
tmp->enum1 = ENUM_ONE_VALUE1;
|
||||||
tmp->string = g_strdup("str");
|
tmp->string = g_strdup("str");
|
||||||
tmp->u.value1 = g_malloc0(sizeof(UserDefA));
|
|
||||||
tmp->integer = 41;
|
tmp->integer = 41;
|
||||||
tmp->u.value1->boolean = true;
|
tmp->u.value1.boolean = true;
|
||||||
|
|
||||||
visit_type_UserDefFlatUnion(data->ov, NULL, &tmp, &error_abort);
|
visit_type_UserDefFlatUnion(data->ov, NULL, &tmp, &error_abort);
|
||||||
arg = qmp_output_get_qobject(data->qov);
|
arg = qmp_output_get_qobject(data->qov);
|
||||||
@ -427,6 +426,7 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data,
|
|||||||
{
|
{
|
||||||
QObject *arg;
|
QObject *arg;
|
||||||
UserDefAlternate *tmp;
|
UserDefAlternate *tmp;
|
||||||
|
QDict *qdict;
|
||||||
|
|
||||||
tmp = g_new0(UserDefAlternate, 1);
|
tmp = g_new0(UserDefAlternate, 1);
|
||||||
tmp->type = QTYPE_QINT;
|
tmp->type = QTYPE_QINT;
|
||||||
@ -453,6 +453,27 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data,
|
|||||||
|
|
||||||
qapi_free_UserDefAlternate(tmp);
|
qapi_free_UserDefAlternate(tmp);
|
||||||
qobject_decref(arg);
|
qobject_decref(arg);
|
||||||
|
|
||||||
|
tmp = g_new0(UserDefAlternate, 1);
|
||||||
|
tmp->type = QTYPE_QDICT;
|
||||||
|
tmp->u.udfu.integer = 1;
|
||||||
|
tmp->u.udfu.string = g_strdup("str");
|
||||||
|
tmp->u.udfu.enum1 = ENUM_ONE_VALUE1;
|
||||||
|
tmp->u.udfu.u.value1.boolean = true;
|
||||||
|
|
||||||
|
visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort);
|
||||||
|
arg = qmp_output_get_qobject(data->qov);
|
||||||
|
|
||||||
|
g_assert_cmpint(qobject_type(arg), ==, QTYPE_QDICT);
|
||||||
|
qdict = qobject_to_qdict(arg);
|
||||||
|
g_assert_cmpint(qdict_size(qdict), ==, 4);
|
||||||
|
g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 1);
|
||||||
|
g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "str");
|
||||||
|
g_assert_cmpstr(qdict_get_str(qdict, "enum1"), ==, "value1");
|
||||||
|
g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, true);
|
||||||
|
|
||||||
|
qapi_free_UserDefAlternate(tmp);
|
||||||
|
qobject_decref(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_visitor_out_empty(TestOutputVisitorData *data,
|
static void test_visitor_out_empty(TestOutputVisitorData *data,
|
||||||
|
Loading…
Reference in New Issue
Block a user