qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
To: Markus Armbruster <armbru@redhat.com>
Cc: imammedo@redhat.com, alex.williamson@redhat.com,
	eblake@redhat.com, qemu-devel@nongnu.org
Subject: Re: [PATCH 1/2] qapi: introduce forwarding visitor
Date: Thu, 22 Jul 2021 17:08:19 +0200	[thread overview]
Message-ID: <3426ca4c-fc26-1730-76f8-c46bc7fddca3@redhat.com> (raw)
In-Reply-To: <87v952fnut.fsf@dusky.pond.sub.org>

On 22/07/21 16:02, Markus Armbruster wrote:
> Double-checking: the other fields are not accessible via this visitor.
> Correct?

Correct.

>>
>> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
>> ---
>>   include/qapi/forward-visitor.h    |  27 +++
>>   qapi/meson.build                  |   1 +
>>   qapi/qapi-forward-visitor.c       | 307 ++++++++++++++++++++++++++++++
>>   tests/unit/meson.build            |   1 +
>>   tests/unit/test-forward-visitor.c | 165 ++++++++++++++++
>>   5 files changed, 501 insertions(+)
>>   create mode 100644 include/qapi/forward-visitor.h
>>   create mode 100644 qapi/qapi-forward-visitor.c
>>   create mode 100644 tests/unit/test-forward-visitor.c
> 
> Missing: update of the big comment in include/qapi/visitor.h.  Can be
> done on top.

Also because I'm not sure what to add. :)

This is not a fifth type of visitor, it's a wrapper for the existing types (two of them, input and output; the other two don't break horribly but make no sense either).

>> +static bool forward_field_translate_name(ForwardFieldVisitor *v, const char **name,
>> +                                         Error **errp)
>> +{
>> +    if (v->depth) {
>> +        return true;
>> +    }
> 
> Succeed when we're in a sub-struct.
> 
>> +    if (g_str_equal(*name, v->from)) {
>> +        *name = v->to;
>> +        return true;
>> +    }
> 
> Succeed when we're in the root struct and @name is the alias name.
> Replace the alias name by the real one.
> 
>> +    error_setg(errp, QERR_MISSING_PARAMETER, *name);
>> +    return false;
> 
> Fail when we're in the root struct and @name is not the alias name.
> 
>> +}
> 
> Can you explain why you treat names in sub-structs differently than
> names other than the alias name in the root struct?

Taking the example of QOM alias properties, if the QOM property you're
aliasing is a struct, its field names are irrelevant.  The caller may
not even know what they are, as they are not part of the namespace (e.g.
the toplevel QDict returned by keyval_parse) that is being modified.

There are no aliased compound QOM properties that I can make a proper example with, unfortunately.

>> +    /*
>> +     * The name of alternates is reused when accessing the content,
>> +     * so do not increase depth here.
>> +     */
> 
> I understand why you don't increase @depth here (same reason
> qobject-input-visitor.c doesn't qobject_input_push() here).  I don't
> understand the comment :)

See above: the alternate is not a struct; the names that are passed
between start_alternate and end_alternate are within the same namespace
as the toplevel field.

As to the comment, the idea is: if those calls used e.g. name == NULL,
the depth would need to be increased, but the name will be the same one
that was received by start_alternate.  Change to "The name passed to
start_alternate is also used when accessing the content"?

>> +Visitor *visitor_forward_field(Visitor *target, const char *from, const char *to)
>> +{
>> +    ForwardFieldVisitor *v = g_new0(ForwardFieldVisitor, 1);
>> +
>> +    v->visitor.type = target->type;
> 
> Do arbitrary types work?  Or is this limited to input and output
> visitors?

They don't crash, but they don't make sense because 1) they should not
live outside qapi_clone and visit_free_* 2) they use NULL for the
outermost name.

> Not forwarded: method .type_size().  Impact: visit_type_size() will call
> the wrapped visitor's .type_uint64() instead of its .type_size().  The
> two differ for the opts visitor, the keyval input visitor, the string
> input visitor, and the string output visitor.

Fixed, of course.  Incremental diff after my sig.

Paolo

diff --git a/qapi/qapi-forward-visitor.c b/qapi/qapi-forward-visitor.c
index f04f72f66d..a4b111e22a 100644
--- a/qapi/qapi-forward-visitor.c
+++ b/qapi/qapi-forward-visitor.c
@@ -57,6 +57,7 @@ static bool forward_field_translate_name(ForwardFieldVisitor *v, const char **na
  static bool forward_field_check_struct(Visitor *v, Error **errp)
  {
      ForwardFieldVisitor *ffv = to_ffv(v);
+
      return visit_check_struct(ffv->target, errp);
  }
  
@@ -78,6 +79,7 @@ static bool forward_field_start_struct(Visitor *v, const char *name, void **obj,
  static void forward_field_end_struct(Visitor *v, void **obj)
  {
      ForwardFieldVisitor *ffv = to_ffv(v);
+
      assert(ffv->depth);
      ffv->depth--;
      visit_end_struct(ffv->target, obj);
@@ -132,8 +134,8 @@ static bool forward_field_start_alternate(Visitor *v, const char *name,
          return false;
      }
      /*
-     * The name of alternates is reused when accessing the content,
-     * so do not increase depth here.
+     * The name passed to start_alternate is used also in the visit_type_* calls
+     * that retrieve the alternate's content; so, do not increase depth here.
       */
      return visit_start_alternate(ffv->target, name, obj, size, errp);
  }
@@ -189,6 +191,17 @@ static bool forward_field_type_str(Visitor *v, const char *name, char **obj,
      return visit_type_str(ffv->target, name, obj, errp);
  }
  
+static bool forward_field_type_size(Visitor *v, const char *name, uint64_t *obj,
+                                    Error **errp)
+{
+    ForwardFieldVisitor *ffv = to_ffv(v);
+
+    if (!forward_field_translate_name(ffv, &name, errp)) {
+        return false;
+    }
+    return visit_type_size(ffv->target, name, obj, errp);
+}
+
  static bool forward_field_type_number(Visitor *v, const char *name, double *obj,
                                        Error **errp)
  {
@@ -275,6 +288,12 @@ Visitor *visitor_forward_field(Visitor *target, const char *from, const char *to
  {
      ForwardFieldVisitor *v = g_new0(ForwardFieldVisitor, 1);
  
+    /*
+     * Clone and dealloc visitors don't use a name for the toplevel
+     * visit, so they make no sense here.
+     */
+    assert(target->type == VISITOR_OUTPUT || target->type == VISITOR_INPUT);
+
      v->visitor.type = target->type;
      v->visitor.start_struct = forward_field_start_struct;
      v->visitor.check_struct = forward_field_check_struct;
@@ -285,18 +304,19 @@ Visitor *visitor_forward_field(Visitor *target, const char *from, const char *to
      v->visitor.end_list = forward_field_end_list;
      v->visitor.start_alternate = forward_field_start_alternate;
      v->visitor.end_alternate = forward_field_end_alternate;
-    v->visitor.optional = forward_field_optional;
-    v->visitor.deprecated_accept = forward_field_deprecated_accept;
-    v->visitor.deprecated = forward_field_deprecated;
-    v->visitor.free = forward_field_free;
      v->visitor.type_int64 = forward_field_type_int64;
      v->visitor.type_uint64 = forward_field_type_uint64;
+    v->visitor.type_size = forward_field_type_size;
      v->visitor.type_bool = forward_field_type_bool;
      v->visitor.type_str = forward_field_type_str;
      v->visitor.type_number = forward_field_type_number;
      v->visitor.type_any = forward_field_type_any;
      v->visitor.type_null = forward_field_type_null;
+    v->visitor.optional = forward_field_optional;
+    v->visitor.deprecated_accept = forward_field_deprecated_accept;
+    v->visitor.deprecated = forward_field_deprecated;
      v->visitor.complete = forward_field_complete;
+    v->visitor.free = forward_field_free;
  
      v->target = target;
      v->from = g_strdup(from);
diff --git a/tests/unit/test-forward-visitor.c b/tests/unit/test-forward-visitor.c
index 32ba359977..0de43964d2 100644
--- a/tests/unit/test-forward-visitor.c
+++ b/tests/unit/test-forward-visitor.c
@@ -69,6 +69,33 @@ static void test_forward_any(void)
      qapi_free_UserDefOne(dst);
  }
  
+static void test_forward_size(void)
+{
+    /*
+     * visit_type_size does not return a pointer, so visit_with_forward
+     * cannot be used.
+     */
+    bool help = false;
+    QDict *src = keyval_parse("src=1.5M", NULL, &help, &error_abort);
+    Visitor *v, *alias_v;
+    Error *err = NULL;
+    uint64_t result = 0;
+
+    v = qobject_input_visitor_new_keyval(QOBJECT(src));
+    visit_start_struct(v, NULL, NULL, 0, &error_abort);
+
+    alias_v = visitor_forward_field(v, "dst", "src");
+    visit_type_size(alias_v, "src", &result, &err);
+    error_free_or_abort(&err);
+    visit_type_size(alias_v, "dst", &result, &err);
+    assert(result == 3 << 19);
+    assert(err == NULL);
+    visit_free(alias_v);
+
+    visit_end_struct(v, NULL);
+    visit_free(v);
+}
+
  static void test_forward_number(void)
  {
      /*
@@ -157,6 +184,7 @@ int main(int argc, char **argv)
      g_test_add_func("/visitor/forward/struct", test_forward_struct);
      g_test_add_func("/visitor/forward/alternate", test_forward_alternate);
      g_test_add_func("/visitor/forward/string", test_forward_string);
+    g_test_add_func("/visitor/forward/size", test_forward_size);
      g_test_add_func("/visitor/forward/number", test_forward_number);
      g_test_add_func("/visitor/forward/any", test_forward_any);
      g_test_add_func("/visitor/forward/list", test_forward_list);



  reply	other threads:[~2021-07-22 15:09 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-07-19 10:40 [PATCH 0/2] qapi/qom: use correct field name when getting/setting alias properties Paolo Bonzini
2021-07-19 10:40 ` [PATCH 1/2] qapi: introduce forwarding visitor Paolo Bonzini
2021-07-20  0:54   ` Eric Blake
2021-07-22 14:02   ` Markus Armbruster
2021-07-22 15:08     ` Paolo Bonzini [this message]
2021-07-22 15:34       ` Markus Armbruster
2021-07-23  9:49         ` Paolo Bonzini
2021-07-19 10:40 ` [PATCH 2/2] qom: use correct field name when getting/setting alias properties Paolo Bonzini
2021-07-19 11:51   ` Philippe Mathieu-Daudé
2021-07-20  1:00   ` Eric Blake
2021-07-21  9:51     ` Paolo Bonzini
2021-07-21 14:43       ` Markus Armbruster
2021-07-20 15:54 ` [PATCH 0/2] qapi/qom: " Markus Armbruster
2021-07-21 11:50   ` Paolo Bonzini
2021-07-22 13:25 ` Markus Armbruster
2021-07-22 13:36   ` Paolo Bonzini

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=3426ca4c-fc26-1730-76f8-c46bc7fddca3@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=alex.williamson@redhat.com \
    --cc=armbru@redhat.com \
    --cc=eblake@redhat.com \
    --cc=imammedo@redhat.com \
    --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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).