diff options
author | Eric Blake <eblake@redhat.com> | 2016-06-09 10:48:43 -0600 |
---|---|---|
committer | Markus Armbruster <armbru@redhat.com> | 2016-07-06 10:52:04 +0200 |
commit | 3b098d56979d2f7fd707c5be85555d114353a28d (patch) | |
tree | 85f234e99b363f4417c0b4a09971ad63935031d9 /qapi | |
parent | 23d1705f425ca847f11d92e4363cd7f67f369fd8 (diff) |
qapi: Add new visit_complete() function
Making each output visitor provide its own output collection
function was the only remaining reason for exposing visitor
sub-types to the rest of the code base. Add a polymorphic
visit_complete() function which is a no-op for input visitors,
and which populates an opaque pointer for output visitors. For
maximum type-safety, also add a parameter to the output visitor
constructors with a type-correct version of the output pointer,
and assert that the two uses match.
This approach was considered superior to either passing the
output parameter only during construction (action at a distance
during visit_free() feels awkward) or only during visit_complete()
(defeating type safety makes it easier to use incorrectly).
Most callers were function-local, and therefore a mechanical
conversion; the testsuite was a bit trickier, but the previous
cleanup patch minimized the churn here.
The visit_complete() function may be called at most once; doing
so lets us use transfer semantics rather than duplication or
ref-count semantics to get the just-built output back to the
caller, even though it means our behavior is not idempotent.
Generated code is simplified as follows for events:
|@@ -26,7 +26,7 @@ void qapi_event_send_acpi_device_ost(ACP
| QDict *qmp;
| Error *err = NULL;
| QMPEventFuncEmit emit;
|- QmpOutputVisitor *qov;
|+ QObject *obj;
| Visitor *v;
| q_obj_ACPI_DEVICE_OST_arg param = {
| info
|@@ -39,8 +39,7 @@ void qapi_event_send_acpi_device_ost(ACP
|
| qmp = qmp_event_build_dict("ACPI_DEVICE_OST");
|
|- qov = qmp_output_visitor_new();
|- v = qmp_output_get_visitor(qov);
|+ v = qmp_output_visitor_new(&obj);
|
| visit_start_struct(v, "ACPI_DEVICE_OST", NULL, 0, &err);
| if (err) {
|@@ -55,7 +54,8 @@ void qapi_event_send_acpi_device_ost(ACP
| goto out;
| }
|
|- qdict_put_obj(qmp, "data", qmp_output_get_qobject(qov));
|+ visit_complete(v, &obj);
|+ qdict_put_obj(qmp, "data", obj);
| emit(QAPI_EVENT_ACPI_DEVICE_OST, qmp, &err);
and for commands:
| {
| Error *err = NULL;
|- QmpOutputVisitor *qov = qmp_output_visitor_new();
| Visitor *v;
|
|- v = qmp_output_get_visitor(qov);
|+ v = qmp_output_visitor_new(ret_out);
| visit_type_AddfdInfo(v, "unused", &ret_in, &err);
|- if (err) {
|- goto out;
|+ if (!err) {
|+ visit_complete(v, ret_out);
| }
|- *ret_out = qmp_output_get_qobject(qov);
|-
|-out:
| error_propagate(errp, err);
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-13-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Diffstat (limited to 'qapi')
-rw-r--r-- | qapi/qapi-visit-core.c | 8 | ||||
-rw-r--r-- | qapi/qmp-output-visitor.c | 21 | ||||
-rw-r--r-- | qapi/string-output-visitor.c | 22 |
3 files changed, 32 insertions, 19 deletions
diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c index 5f68c251d2..eb7dd7253c 100644 --- a/qapi/qapi-visit-core.c +++ b/qapi/qapi-visit-core.c @@ -20,6 +20,14 @@ #include "qapi/visitor.h" #include "qapi/visitor-impl.h" +void visit_complete(Visitor *v, void *opaque) +{ + assert(v->type != VISITOR_OUTPUT || v->complete); + if (v->complete) { + v->complete(v, opaque); + } +} + void visit_free(Visitor *v) { if (v) { diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c index 3d12623cf9..0452056d42 100644 --- a/qapi/qmp-output-visitor.c +++ b/qapi/qmp-output-visitor.c @@ -33,6 +33,7 @@ struct QmpOutputVisitor Visitor visitor; QStack stack; /* Stack of containers that haven't yet been finished */ QObject *root; /* Root of the output visit */ + QObject **result; /* User's storage location for result */ }; #define qmp_output_add(qov, name, value) \ @@ -200,18 +201,17 @@ static void qmp_output_type_null(Visitor *v, const char *name, Error **errp) /* Finish building, and return the root object. * The root object is never null. The caller becomes the object's * owner, and should use qobject_decref() when done with it. */ -QObject *qmp_output_get_qobject(QmpOutputVisitor *qov) +static void qmp_output_complete(Visitor *v, void *opaque) { + QmpOutputVisitor *qov = to_qov(v); + /* A visit must have occurred, with each start paired with end. */ assert(qov->root && QTAILQ_EMPTY(&qov->stack)); + assert(opaque == qov->result); qobject_incref(qov->root); - return qov->root; -} - -Visitor *qmp_output_get_visitor(QmpOutputVisitor *v) -{ - return &v->visitor; + *qov->result = qov->root; + qov->result = NULL; } static void qmp_output_free(Visitor *v) @@ -228,7 +228,7 @@ static void qmp_output_free(Visitor *v) g_free(qov); } -QmpOutputVisitor *qmp_output_visitor_new(void) +Visitor *qmp_output_visitor_new(QObject **result) { QmpOutputVisitor *v; @@ -247,9 +247,12 @@ QmpOutputVisitor *qmp_output_visitor_new(void) v->visitor.type_number = qmp_output_type_number; v->visitor.type_any = qmp_output_type_any; v->visitor.type_null = qmp_output_type_null; + v->visitor.complete = qmp_output_complete; v->visitor.free = qmp_output_free; QTAILQ_INIT(&v->stack); + *result = NULL; + v->result = result; - return v; + return &v->visitor; } diff --git a/qapi/string-output-visitor.c b/qapi/string-output-visitor.c index 78aab876e3..94ac8211d1 100644 --- a/qapi/string-output-visitor.c +++ b/qapi/string-output-visitor.c @@ -58,6 +58,7 @@ struct StringOutputVisitor Visitor visitor; bool human; GString *string; + char **result; ListMode list_mode; union { int64_t s; @@ -305,16 +306,13 @@ static void end_list(Visitor *v, void **obj) sov->list_mode = LM_NONE; } -char *string_output_get_string(StringOutputVisitor *sov) +static void string_output_complete(Visitor *v, void *opaque) { - char *string = g_string_free(sov->string, false); - sov->string = NULL; - return string; -} + StringOutputVisitor *sov = to_sov(v); -Visitor *string_output_get_visitor(StringOutputVisitor *sov) -{ - return &sov->visitor; + assert(opaque == sov->result); + *sov->result = g_string_free(sov->string, false); + sov->string = NULL; } static void free_range(void *range, void *dummy) @@ -335,7 +333,7 @@ static void string_output_free(Visitor *v) g_free(sov); } -StringOutputVisitor *string_output_visitor_new(bool human) +Visitor *string_output_visitor_new(bool human, char **result) { StringOutputVisitor *v; @@ -343,6 +341,9 @@ StringOutputVisitor *string_output_visitor_new(bool human) v->string = g_string_new(NULL); v->human = human; + v->result = result; + *result = NULL; + v->visitor.type = VISITOR_OUTPUT; v->visitor.type_int64 = print_type_int64; v->visitor.type_uint64 = print_type_uint64; @@ -353,7 +354,8 @@ StringOutputVisitor *string_output_visitor_new(bool human) v->visitor.start_list = start_list; v->visitor.next_list = next_list; v->visitor.end_list = end_list; + v->visitor.complete = string_output_complete; v->visitor.free = string_output_free; - return v; + return &v->visitor; } |