From: Kevin Wolf <kwolf@redhat.com>
To: qemu-block@nongnu.org
Cc: kwolf@redhat.com, qemu-devel@nongnu.org, armbru@redhat.com,
marcandre.lureau@redhat.com, pbonzini@redhat.com
Subject: [PATCH 4/6] qapi: Optionally parse simple unions as flat
Date: Fri, 23 Oct 2020 12:12:20 +0200 [thread overview]
Message-ID: <20201023101222.250147-5-kwolf@redhat.com> (raw)
In-Reply-To: <20201023101222.250147-1-kwolf@redhat.com>
This extends the Visitor interface with an option that can enable flat
representation (without the 'data' wrapper) for simple unions. This way,
a command line parser can enable a more user friendly syntax while QMP
doesn't enable the option and uses the same representation as before.
We need to disable flat representation for ChardevSpiceChannel, which
has a 'type' option that conflicts with the ChardevBackend 'type'. This
variant will get nesting even when flat parsing is enabled in the
Visitor.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
qapi/char.json | 3 ++-
docs/devel/qapi-code-gen.txt | 11 ++++++++++-
include/qapi/visitor-impl.h | 3 +++
include/qapi/visitor.h | 10 ++++++++++
qapi/qapi-visit-core.c | 10 ++++++++++
scripts/qapi/expr.py | 7 ++++++-
scripts/qapi/schema.py | 25 ++++++++++++++++++-------
scripts/qapi/visit.py | 20 ++++++++++++++------
8 files changed, 73 insertions(+), 16 deletions(-)
diff --git a/qapi/char.json b/qapi/char.json
index 43486d1daa..57ec18220b 100644
--- a/qapi/char.json
+++ b/qapi/char.json
@@ -414,7 +414,8 @@
'stdio': 'ChardevStdio',
'console': 'ChardevCommon',
'spicevmc': { 'type': 'ChardevSpiceChannel',
- 'if': 'defined(CONFIG_SPICE)' },
+ 'if': 'defined(CONFIG_SPICE)',
+ 'allow-flat': false },
'spiceport': { 'type': 'ChardevSpicePort',
'if': 'defined(CONFIG_SPICE)' },
'vc': 'ChardevVC',
diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
index 9722c1a204..ee34d39a20 100644
--- a/docs/devel/qapi-code-gen.txt
+++ b/docs/devel/qapi-code-gen.txt
@@ -295,7 +295,9 @@ Syntax:
'*features': FEATURES }
BRANCHES = { BRANCH, ... }
BRANCH = STRING : TYPE-REF
- | STRING : { 'type': TYPE-REF, '*if': COND }
+ | STRING : { 'type': TYPE-REF,
+ '*if': COND,
+ '*allow-flat': BOOL }
Member 'union' names the union type.
@@ -334,6 +336,13 @@ values to data types like in this example:
'data': { 'file': 'BlockdevOptionsFile',
'qcow2': 'BlockdevOptionsQcow2' } }
+Simple unions can support both wrapped and flat representation of
+branches that have a struct type, unless it is explicitly disabled in
+the schema with 'allow-flat': false. Branches of other types are
+always wrapped. Which representation is used in the generated visitor
+C code can be configured per visitor. Flat representation is
+appropriate when parsing command line options.
+
In the Client JSON Protocol, all simple union branches have wrapped
representation, as in these examples:
diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h
index 7362c043be..f628b6eb36 100644
--- a/include/qapi/visitor-impl.h
+++ b/include/qapi/visitor-impl.h
@@ -121,6 +121,9 @@ struct Visitor
/* Must be set */
void (*free)(Visitor *v);
+
+ /* Set to true to make simple unions look like flat unions */
+ bool flat_simple_unions;
};
#endif
diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h
index ebc19ede7f..d41be4df48 100644
--- a/include/qapi/visitor.h
+++ b/include/qapi/visitor.h
@@ -496,6 +496,16 @@ bool visit_is_input(Visitor *v);
*/
bool visit_is_dealloc(Visitor *v);
+/*
+ * Check if simple unions should be treated as flat.
+ */
+bool visit_flat_simple_unions(Visitor *v);
+
+/*
+ * Set if simple unions should be treated as flat.
+ */
+void visit_set_flat_simple_unions(Visitor *v, bool flat);
+
/*** Visiting built-in types ***/
/*
diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
index 7e5f40e7f0..dc6fd78b8c 100644
--- a/qapi/qapi-visit-core.c
+++ b/qapi/qapi-visit-core.c
@@ -145,6 +145,16 @@ bool visit_is_dealloc(Visitor *v)
return v->type == VISITOR_DEALLOC;
}
+bool visit_flat_simple_unions(Visitor *v)
+{
+ return v->flat_simple_unions;
+}
+
+void visit_set_flat_simple_unions(Visitor *v, bool flat)
+{
+ v->flat_simple_unions = flat;
+}
+
bool visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp)
{
assert(obj);
diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py
index 2fcaaa2497..a39092e4a9 100644
--- a/scripts/qapi/expr.py
+++ b/scripts/qapi/expr.py
@@ -248,7 +248,12 @@ def check_union(expr, info):
for (key, value) in members.items():
source = "'data' member '%s'" % key
check_name_str(key, info, source)
- check_keys(value, info, source, ['type'], ['if'])
+ check_keys(value, info, source, ['type'], ['if', 'allow-flat'])
+ if 'allow-flat' in value:
+ if discriminator is not None:
+ raise QAPISemError(info, "'allow-flat' requires simple union")
+ if not isinstance(value['allow-flat'], bool):
+ raise QAPISemError(info, "'allow-flat' must be a boolean")
check_if(value, info, source)
check_type(value['type'], info, source, allow_array=not base)
diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
index 17525b4216..981d0d659f 100644
--- a/scripts/qapi/schema.py
+++ b/scripts/qapi/schema.py
@@ -721,9 +721,9 @@ class QAPISchemaVariant(QAPISchemaObjectTypeMember):
self.wrapped = bool(wrapper_type)
self.wrapper_type = wrapper_type
- # For now, unions are either flat or wrapped, never both
+ # Unions that are both flat and wrapped can look like either one,
+ # depending on Visitor.flat_simple_unions
assert self.flat or self.wrapped
- assert not (self.flat and self.wrapped)
def check(self, schema):
super().check(schema)
@@ -1038,7 +1038,7 @@ class QAPISchema:
def _make_variant(self, case, typ, ifcond, info):
return QAPISchemaVariant(case, info, typ, ifcond)
- def _make_simple_variant(self, union_name, case, typ, ifcond, info):
+ def _make_simple_variant(self, union_name, case, typ, ifcond, flat, info):
if isinstance(typ, list):
assert len(typ) == 1
typ = self._make_array_type(typ[0], info)
@@ -1049,7 +1049,14 @@ class QAPISchema:
wrapper_member = self._make_member('data', typ, None, None, info)
wrapper_type = QAPISchemaObjectType(wrapper_name, info, None, ifcond,
None, None, [wrapper_member], None)
- return QAPISchemaVariant(case, info, typ, ifcond, flat=False,
+
+ # Default to allowing flat representation for object types.
+ # Other types require a wrapper, so disable flat for them by default.
+ if flat is None:
+ variant_type = self.resolve_type(typ, info, 'variant type')
+ flat = isinstance(variant_type, QAPISchemaObjectType)
+
+ return QAPISchemaVariant(case, info, typ, ifcond, flat=flat,
wrapper_type=wrapper_type)
def _def_union_type(self, expr, info, doc):
@@ -1070,9 +1077,13 @@ class QAPISchema:
for (key, value) in data.items()]
members = []
else:
- variants = [self._make_simple_variant(name, key, value['type'],
- value.get('if'), info)
- for (key, value) in data.items()]
+ variants = [
+ self._make_simple_variant(name, key, value['type'],
+ value.get('if'),
+ value.get('allow-flat'),
+ info)
+ for (key, value) in data.items()
+ ]
enum = [{'name': v.name, 'if': v.ifcond} for v in variants]
typ = self._make_implicit_enum_type(name, info, ifcond, enum)
tag_member = QAPISchemaObjectTypeMember('type', info, typ, False)
diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py
index f72567cbcc..9d05d6bd08 100644
--- a/scripts/qapi/visit.py
+++ b/scripts/qapi/visit.py
@@ -127,23 +127,31 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
case=case_str,
c_type=var.type.c_name(), c_name=c_name(var.name))
elif var.wrapped:
+ if var.flat:
+ cond = "!visit_flat_simple_unions(v)"
+ else:
+ cond = "true"
ret += mcgen('''
case %(case)s:
{
bool ok;
- if (!visit_start_struct(v, "data", NULL, 0, errp)) {
- return false;
+ if (%(cond)s) {
+ if (!visit_start_struct(v, "data", NULL, 0, errp)) {
+ return false;
+ }
}
ok = visit_type_%(c_type)s_members(v, &obj->u.%(c_name)s, errp);
- if (ok) {
- ok = visit_check_struct(v, errp);
+ if (%(cond)s) {
+ if (ok) {
+ ok = visit_check_struct(v, errp);
+ }
+ visit_end_struct(v, NULL);
}
- visit_end_struct(v, NULL);
return ok;
}
''',
- case=case_str,
+ case=case_str, cond=cond,
c_type=var.type.c_name(), c_name=c_name(var.name))
else:
--
2.28.0
next prev parent reply other threads:[~2020-10-23 10:18 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-10-23 10:12 [PATCH 0/6] qemu-storage-daemon: QAPIfy --chardev Kevin Wolf
2020-10-23 10:12 ` [PATCH 1/6] char/stdio: Fix QMP default for 'signal' Kevin Wolf
2020-10-23 10:38 ` Marc-André Lureau
2020-10-23 12:12 ` Markus Armbruster
2020-10-23 10:12 ` [PATCH 2/6] char: Factor out qemu_chr_print_types() Kevin Wolf
2020-10-23 10:38 ` Marc-André Lureau
2020-10-23 12:15 ` Markus Armbruster
2020-10-23 10:12 ` [PATCH 3/6] qapi: Remove wrapper struct for simple unions Kevin Wolf
2020-10-23 10:40 ` Marc-André Lureau
2020-10-23 11:06 ` Marc-André Lureau
2020-10-23 12:28 ` Kevin Wolf
2020-10-23 12:49 ` Markus Armbruster
2020-10-23 14:06 ` Kevin Wolf
2020-10-23 10:12 ` Kevin Wolf [this message]
2020-10-23 10:12 ` [PATCH 5/6] tests/qapi-schema: Flat representation of " Kevin Wolf
2020-10-23 10:12 ` [PATCH 6/6] qemu-storage-daemon: Use qmp_chardev_add() for --chardev Kevin Wolf
2020-10-26 13:33 ` Markus Armbruster
2020-10-23 10:36 ` [PATCH 0/6] qemu-storage-daemon: QAPIfy --chardev Daniel P. Berrangé
2020-10-23 11:05 ` Paolo Bonzini
2020-10-23 11:56 ` Kevin Wolf
2020-10-23 13:40 ` Markus Armbruster
2020-10-23 16:08 ` Paolo Bonzini
2020-10-25 17:42 ` Markus Armbruster
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20201023101222.250147-5-kwolf@redhat.com \
--to=kwolf@redhat.com \
--cc=armbru@redhat.com \
--cc=marcandre.lureau@redhat.com \
--cc=pbonzini@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.