diff mbox

[v2,2/3] qapi: Add enum_table[] parameter to start_alternate

Message ID 20170505201128.12099-3-ehabkost@redhat.com
State New
Headers show

Commit Message

Eduardo Habkost May 5, 2017, 8:11 p.m. UTC
The new parameter will be used by the string input visitor to detect
alternate types that can't be parsed unambiguously.

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
Changes v1 -> v2:
* (new patch added to series)
---
 include/qapi/visitor.h       | 10 +++++++++-
 include/qapi/visitor-impl.h  |  4 +++-
 scripts/qapi-visit.py        | 11 +++++++++--
 qapi/qapi-visit-core.c       |  7 +++++--
 qapi/qapi-clone-visitor.c    |  1 +
 qapi/qapi-dealloc-visitor.c  |  1 +
 qapi/qobject-input-visitor.c |  1 +
 qapi/trace-events            |  2 +-
 8 files changed, 30 insertions(+), 7 deletions(-)

Comments

Eric Blake May 5, 2017, 8:45 p.m. UTC | #1
On 05/05/2017 03:11 PM, Eduardo Habkost wrote:
> The new parameter will be used by the string input visitor to detect
> alternate types that can't be parsed unambiguously.
> 
> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
> ---
> Changes v1 -> v2:
> * (new patch added to series)
> ---

> +++ b/include/qapi/visitor.h
> @@ -411,13 +411,21 @@ void visit_end_list(Visitor *v, void **list);
>   * @supported_qtypes is a bit mask indicating which QTypes are supported
>   * by the alternate.
>   *
> + * @enum_table contains the enum value lookup table, in case
> + * strings in the input are going to be parsed as enums. Visitors
> + * aren't required to validate string input according to
> + * enum_table, as visit_type_enum() will be called automatically
> + * if (*obj)->type is QTYPE_QSTRING.

Presumably, enum_table will be NULL if the alternate type does not
include an enum?  [reads ahead] yes. Should be documented.

I'm less convinced we need this patch, if we can instead guarantee at
QAPI-generation time that alternates are not possible if they would
cause an ambiguity.


> +++ b/scripts/qapi-visit.py
> @@ -166,6 +166,12 @@ def gen_visit_alternate(name, variants):
>      supported_qtypes = ' | '.join(qtypes)
>      ret = ''
>  
> +    enum_table = 'NULL'
> +    for var in variants.variants:
> +        if isinstance(var.type, QAPISchemaEnumType):
> +            enum_table = '%s_lookup' % (var.type.c_name())
> +            break
> +
>      ret += mcgen('''
>  
>  void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp)
> @@ -174,7 +180,7 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
>      uint32_t supported_qtypes = %(supported_qtypes)s;
>  
>      visit_start_alternate(v, name, (GenericAlternate **)obj, sizeof(**obj),
> -                          supported_qtypes, &err);
> +                          supported_qtypes, %(enum_table)s, &err);

So there's where you populate the enum through.

I'll have to see where 3/3 goes before deciding if this is worth having.
Eduardo Habkost May 5, 2017, 8:51 p.m. UTC | #2
On Fri, May 05, 2017 at 03:45:01PM -0500, Eric Blake wrote:
> On 05/05/2017 03:11 PM, Eduardo Habkost wrote:
> > The new parameter will be used by the string input visitor to detect
> > alternate types that can't be parsed unambiguously.
> > 
> > Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
> > ---
> > Changes v1 -> v2:
> > * (new patch added to series)
> > ---
> 
> > +++ b/include/qapi/visitor.h
> > @@ -411,13 +411,21 @@ void visit_end_list(Visitor *v, void **list);
> >   * @supported_qtypes is a bit mask indicating which QTypes are supported
> >   * by the alternate.
> >   *
> > + * @enum_table contains the enum value lookup table, in case
> > + * strings in the input are going to be parsed as enums. Visitors
> > + * aren't required to validate string input according to
> > + * enum_table, as visit_type_enum() will be called automatically
> > + * if (*obj)->type is QTYPE_QSTRING.
> 
> Presumably, enum_table will be NULL if the alternate type does not
> include an enum?  [reads ahead] yes. Should be documented.
> 
> I'm less convinced we need this patch, if we can instead guarantee at
> QAPI-generation time that alternates are not possible if they would
> cause an ambiguity.

I am not 100% sure either. I just have the feeling that we are
likely to break the rules and allow ambiguous enums in
exceptional cases in the future, and then this code will be
useful.

That doesn't mean we need to maintain it in the source tree. We
can leave it on the git history, or just on the qemu-devel
archives.
Markus Armbruster May 10, 2017, 1:34 p.m. UTC | #3
Eduardo Habkost <ehabkost@redhat.com> writes:

> The new parameter will be used by the string input visitor to detect
> alternate types that can't be parsed unambiguously.
>
> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
> ---
> Changes v1 -> v2:
> * (new patch added to series)
> ---
>  include/qapi/visitor.h       | 10 +++++++++-
>  include/qapi/visitor-impl.h  |  4 +++-
>  scripts/qapi-visit.py        | 11 +++++++++--
>  qapi/qapi-visit-core.c       |  7 +++++--
>  qapi/qapi-clone-visitor.c    |  1 +
>  qapi/qapi-dealloc-visitor.c  |  1 +
>  qapi/qobject-input-visitor.c |  1 +
>  qapi/trace-events            |  2 +-
>  8 files changed, 30 insertions(+), 7 deletions(-)
>
> diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h
> index 8f5a223714..05e5ca0eb2 100644
> --- a/include/qapi/visitor.h
> +++ b/include/qapi/visitor.h
> @@ -411,13 +411,21 @@ void visit_end_list(Visitor *v, void **list);
>   * @supported_qtypes is a bit mask indicating which QTypes are supported
>   * by the alternate.
>   *
> + * @enum_table contains the enum value lookup table, in case
> + * strings in the input are going to be parsed as enums. Visitors

I agree with Eric: spelling out it's null otherwise wouldn't hurt.

Also: please indulge me and put two spaces after sentence-ending
punctuation.

> + * aren't required to validate string input according to
> + * enum_table, as visit_type_enum() will be called automatically
> + * if (*obj)->type is QTYPE_QSTRING.
> + *
>   * If successful, this must be paired with visit_end_alternate() with
>   * the same @obj to clean up, even if visiting the contents of the
>   * alternate fails.
>   */
>  void visit_start_alternate(Visitor *v, const char *name,
>                             GenericAlternate **obj, size_t size,
> -                           uint32_t supported_qtypes, Error **errp);
> +                           uint32_t supported_qtypes,
> +                           const char *const enum_table[],
> +                           Error **errp);
>  
>  /*
>   * Finish visiting an alternate type.
> diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h
> index 8afcde0f5d..b98370fabb 100644
> --- a/include/qapi/visitor-impl.h
> +++ b/include/qapi/visitor-impl.h
> @@ -71,7 +71,9 @@ struct Visitor
>       * optional for output visitors. */
>      void (*start_alternate)(Visitor *v, const char *name,
>                              GenericAlternate **obj, size_t size,
> -                            uint32_t supported_qtypes, Error **errp);
> +                            uint32_t supported_qtypes,
> +                            const char *const enum_table[],
> +                            Error **errp);
>  
>      /* Optional, needed for dealloc visitor */
>      void (*end_alternate)(Visitor *v, void **obj);
> diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
> index 41c54982e2..2f4dc56918 100644
> --- a/scripts/qapi-visit.py
> +++ b/scripts/qapi-visit.py
> @@ -166,6 +166,12 @@ def gen_visit_alternate(name, variants):
       qtypes = ['(1U << %s)' % (var.type.alternate_qtype())
                 for var in variants.variants]
>      supported_qtypes = ' | '.join(qtypes)
>      ret = ''
>  
> +    enum_table = 'NULL'
> +    for var in variants.variants:
> +        if isinstance(var.type, QAPISchemaEnumType):
> +            enum_table = '%s_lookup' % (var.type.c_name())
> +            break
> +
>      ret += mcgen('''
>  

Iterating over variants.variants again is less than elegant, but I don't
have better ideas.

>  void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp)
> @@ -174,7 +180,7 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
>      uint32_t supported_qtypes = %(supported_qtypes)s;
>  
>      visit_start_alternate(v, name, (GenericAlternate **)obj, sizeof(**obj),
> -                          supported_qtypes, &err);
> +                          supported_qtypes, %(enum_table)s, &err);
>      if (err) {
>          goto out;
>      }
> @@ -183,7 +189,8 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
>      }
>      switch ((*obj)->type) {
>  ''',
> -                 c_name=c_name(name), supported_qtypes=supported_qtypes)
> +                 c_name=c_name(name), supported_qtypes=supported_qtypes,
> +                 enum_table=enum_table)
>  
>      for var in variants.variants:
>          ret += mcgen('''
> diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
> index 8d62914393..479aa763c8 100644
> --- a/qapi/qapi-visit-core.c
> +++ b/qapi/qapi-visit-core.c
> @@ -107,6 +107,7 @@ void visit_end_list(Visitor *v, void **obj)
>  void visit_start_alternate(Visitor *v, const char *name,
>                             GenericAlternate **obj, size_t size,
>                             uint32_t supported_qtypes,
> +                           const char *const enum_table[],
>                             Error **errp)
>  {
>      Error *err = NULL;
> @@ -115,9 +116,11 @@ void visit_start_alternate(Visitor *v, const char *name,
>  
>      assert(obj && size >= sizeof(GenericAlternate));
>      assert(!(v->type & VISITOR_OUTPUT) || *obj);
> -    trace_visit_start_alternate(v, name, obj, size, supported_qtypes);
> +    trace_visit_start_alternate(v, name, obj, size, supported_qtypes,
> +                                (void *)enum_table);
>      if (v->start_alternate) {
> -        v->start_alternate(v, name, obj, size, supported_qtypes, &err);
> +        v->start_alternate(v, name, obj, size, supported_qtypes,
> +                           enum_table, &err);
>      }
>      if (v->type & VISITOR_INPUT) {
>          assert(v->start_alternate && !err != !*obj);
> diff --git a/qapi/qapi-clone-visitor.c b/qapi/qapi-clone-visitor.c
> index 2e40da5981..9340441ee6 100644
> --- a/qapi/qapi-clone-visitor.c
> +++ b/qapi/qapi-clone-visitor.c
> @@ -71,6 +71,7 @@ static GenericList *qapi_clone_next_list(Visitor *v, GenericList *tail,
>  static void qapi_clone_start_alternate(Visitor *v, const char *name,
>                                         GenericAlternate **obj, size_t size,
>                                         uint32_t supported_qtypes,
> +                                       const char *const enum_table[],
>                                         Error **errp)
>  {
>      qapi_clone_start_struct(v, name, (void **)obj, size, errp);
> diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c
> index 23b64c21a4..fed366c660 100644
> --- a/qapi/qapi-dealloc-visitor.c
> +++ b/qapi/qapi-dealloc-visitor.c
> @@ -39,6 +39,7 @@ static void qapi_dealloc_end_struct(Visitor *v, void **obj)
>  static void qapi_dealloc_start_alternate(Visitor *v, const char *name,
>                                           GenericAlternate **obj, size_t size,
>                                           uint32_t supported_qtypes,
> +                                         const char *const enum_table[],
>                                           Error **errp)
>  {
>  }
> diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c
> index 25997ee816..ae4a6a04e1 100644
> --- a/qapi/qobject-input-visitor.c
> +++ b/qapi/qobject-input-visitor.c
> @@ -339,6 +339,7 @@ static void qobject_input_check_list(Visitor *v, Error **errp)
>  static void qobject_input_start_alternate(Visitor *v, const char *name,
>                                            GenericAlternate **obj, size_t size,
>                                            uint32_t supported_qtypes,
> +                                          const char *const enum_table[],
>                                            Error **errp)
>  {
>      QObjectInputVisitor *qiv = to_qiv(v);
> diff --git a/qapi/trace-events b/qapi/trace-events
> index b15a55b797..384c251814 100644
> --- a/qapi/trace-events
> +++ b/qapi/trace-events
> @@ -11,7 +11,7 @@ visit_next_list(void *v, void *tail, size_t size) "v=%p tail=%p size=%zu"
>  visit_check_list(void *v) "v=%p"
>  visit_end_list(void *v, void *obj) "v=%p obj=%p"
>  
> -visit_start_alternate(void *v, const char *name, void *obj, size_t size, uint32_t supported_qtypes) "v=%p name=%s obj=%p size=%zu supported_qtypes=0x%x"
> +visit_start_alternate(void *v, const char *name, void *obj, size_t size, uint32_t supported_qtypes, void *enum_table) "v=%p name=%s obj=%p size=%zu supported_qtypes=0x%x enum_table=%p"
>  visit_end_alternate(void *v, void *obj) "v=%p obj=%p"
>  
>  visit_optional(void *v, const char *name, bool *present) "v=%p name=%s present=%p"

Not yet sure we need this, but if we do, clarify the function comment,
and you may add

Reviewed-by: Markus Armbruster <armbru@redhat.com>
Eduardo Habkost May 10, 2017, 1:38 p.m. UTC | #4
On Wed, May 10, 2017 at 03:34:52PM +0200, Markus Armbruster wrote:
> Eduardo Habkost <ehabkost@redhat.com> writes:
> 
> > The new parameter will be used by the string input visitor to detect
> > alternate types that can't be parsed unambiguously.
> >
> > Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
[...]
> > diff --git a/qapi/trace-events b/qapi/trace-events
> > index b15a55b797..384c251814 100644
> > --- a/qapi/trace-events
> > +++ b/qapi/trace-events
> > @@ -11,7 +11,7 @@ visit_next_list(void *v, void *tail, size_t size) "v=%p tail=%p size=%zu"
> >  visit_check_list(void *v) "v=%p"
> >  visit_end_list(void *v, void *obj) "v=%p obj=%p"
> >  
> > -visit_start_alternate(void *v, const char *name, void *obj, size_t size, uint32_t supported_qtypes) "v=%p name=%s obj=%p size=%zu supported_qtypes=0x%x"
> > +visit_start_alternate(void *v, const char *name, void *obj, size_t size, uint32_t supported_qtypes, void *enum_table) "v=%p name=%s obj=%p size=%zu supported_qtypes=0x%x enum_table=%p"
> >  visit_end_alternate(void *v, void *obj) "v=%p obj=%p"
> >  
> >  visit_optional(void *v, const char *name, bool *present) "v=%p name=%s present=%p"
> 
> Not yet sure we need this, but if we do, clarify the function comment,
> and you may add
> 
> Reviewed-by: Markus Armbruster <armbru@redhat.com>

Thanks.

The only reason for this patch is to allow code in patch 3/3 to
detect ambiguous enums at runtime. I don't think the runtime
detection solution looked good, though, so I will probably drop
this patch.
diff mbox

Patch

diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h
index 8f5a223714..05e5ca0eb2 100644
--- a/include/qapi/visitor.h
+++ b/include/qapi/visitor.h
@@ -411,13 +411,21 @@  void visit_end_list(Visitor *v, void **list);
  * @supported_qtypes is a bit mask indicating which QTypes are supported
  * by the alternate.
  *
+ * @enum_table contains the enum value lookup table, in case
+ * strings in the input are going to be parsed as enums. Visitors
+ * aren't required to validate string input according to
+ * enum_table, as visit_type_enum() will be called automatically
+ * if (*obj)->type is QTYPE_QSTRING.
+ *
  * If successful, this must be paired with visit_end_alternate() with
  * the same @obj to clean up, even if visiting the contents of the
  * alternate fails.
  */
 void visit_start_alternate(Visitor *v, const char *name,
                            GenericAlternate **obj, size_t size,
-                           uint32_t supported_qtypes, Error **errp);
+                           uint32_t supported_qtypes,
+                           const char *const enum_table[],
+                           Error **errp);
 
 /*
  * Finish visiting an alternate type.
diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h
index 8afcde0f5d..b98370fabb 100644
--- a/include/qapi/visitor-impl.h
+++ b/include/qapi/visitor-impl.h
@@ -71,7 +71,9 @@  struct Visitor
      * optional for output visitors. */
     void (*start_alternate)(Visitor *v, const char *name,
                             GenericAlternate **obj, size_t size,
-                            uint32_t supported_qtypes, Error **errp);
+                            uint32_t supported_qtypes,
+                            const char *const enum_table[],
+                            Error **errp);
 
     /* Optional, needed for dealloc visitor */
     void (*end_alternate)(Visitor *v, void **obj);
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 41c54982e2..2f4dc56918 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -166,6 +166,12 @@  def gen_visit_alternate(name, variants):
     supported_qtypes = ' | '.join(qtypes)
     ret = ''
 
+    enum_table = 'NULL'
+    for var in variants.variants:
+        if isinstance(var.type, QAPISchemaEnumType):
+            enum_table = '%s_lookup' % (var.type.c_name())
+            break
+
     ret += mcgen('''
 
 void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp)
@@ -174,7 +180,7 @@  void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
     uint32_t supported_qtypes = %(supported_qtypes)s;
 
     visit_start_alternate(v, name, (GenericAlternate **)obj, sizeof(**obj),
-                          supported_qtypes, &err);
+                          supported_qtypes, %(enum_table)s, &err);
     if (err) {
         goto out;
     }
@@ -183,7 +189,8 @@  void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
     }
     switch ((*obj)->type) {
 ''',
-                 c_name=c_name(name), supported_qtypes=supported_qtypes)
+                 c_name=c_name(name), supported_qtypes=supported_qtypes,
+                 enum_table=enum_table)
 
     for var in variants.variants:
         ret += mcgen('''
diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
index 8d62914393..479aa763c8 100644
--- a/qapi/qapi-visit-core.c
+++ b/qapi/qapi-visit-core.c
@@ -107,6 +107,7 @@  void visit_end_list(Visitor *v, void **obj)
 void visit_start_alternate(Visitor *v, const char *name,
                            GenericAlternate **obj, size_t size,
                            uint32_t supported_qtypes,
+                           const char *const enum_table[],
                            Error **errp)
 {
     Error *err = NULL;
@@ -115,9 +116,11 @@  void visit_start_alternate(Visitor *v, const char *name,
 
     assert(obj && size >= sizeof(GenericAlternate));
     assert(!(v->type & VISITOR_OUTPUT) || *obj);
-    trace_visit_start_alternate(v, name, obj, size, supported_qtypes);
+    trace_visit_start_alternate(v, name, obj, size, supported_qtypes,
+                                (void *)enum_table);
     if (v->start_alternate) {
-        v->start_alternate(v, name, obj, size, supported_qtypes, &err);
+        v->start_alternate(v, name, obj, size, supported_qtypes,
+                           enum_table, &err);
     }
     if (v->type & VISITOR_INPUT) {
         assert(v->start_alternate && !err != !*obj);
diff --git a/qapi/qapi-clone-visitor.c b/qapi/qapi-clone-visitor.c
index 2e40da5981..9340441ee6 100644
--- a/qapi/qapi-clone-visitor.c
+++ b/qapi/qapi-clone-visitor.c
@@ -71,6 +71,7 @@  static GenericList *qapi_clone_next_list(Visitor *v, GenericList *tail,
 static void qapi_clone_start_alternate(Visitor *v, const char *name,
                                        GenericAlternate **obj, size_t size,
                                        uint32_t supported_qtypes,
+                                       const char *const enum_table[],
                                        Error **errp)
 {
     qapi_clone_start_struct(v, name, (void **)obj, size, errp);
diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c
index 23b64c21a4..fed366c660 100644
--- a/qapi/qapi-dealloc-visitor.c
+++ b/qapi/qapi-dealloc-visitor.c
@@ -39,6 +39,7 @@  static void qapi_dealloc_end_struct(Visitor *v, void **obj)
 static void qapi_dealloc_start_alternate(Visitor *v, const char *name,
                                          GenericAlternate **obj, size_t size,
                                          uint32_t supported_qtypes,
+                                         const char *const enum_table[],
                                          Error **errp)
 {
 }
diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c
index 25997ee816..ae4a6a04e1 100644
--- a/qapi/qobject-input-visitor.c
+++ b/qapi/qobject-input-visitor.c
@@ -339,6 +339,7 @@  static void qobject_input_check_list(Visitor *v, Error **errp)
 static void qobject_input_start_alternate(Visitor *v, const char *name,
                                           GenericAlternate **obj, size_t size,
                                           uint32_t supported_qtypes,
+                                          const char *const enum_table[],
                                           Error **errp)
 {
     QObjectInputVisitor *qiv = to_qiv(v);
diff --git a/qapi/trace-events b/qapi/trace-events
index b15a55b797..384c251814 100644
--- a/qapi/trace-events
+++ b/qapi/trace-events
@@ -11,7 +11,7 @@  visit_next_list(void *v, void *tail, size_t size) "v=%p tail=%p size=%zu"
 visit_check_list(void *v) "v=%p"
 visit_end_list(void *v, void *obj) "v=%p obj=%p"
 
-visit_start_alternate(void *v, const char *name, void *obj, size_t size, uint32_t supported_qtypes) "v=%p name=%s obj=%p size=%zu supported_qtypes=0x%x"
+visit_start_alternate(void *v, const char *name, void *obj, size_t size, uint32_t supported_qtypes, void *enum_table) "v=%p name=%s obj=%p size=%zu supported_qtypes=0x%x enum_table=%p"
 visit_end_alternate(void *v, void *obj) "v=%p obj=%p"
 
 visit_optional(void *v, const char *name, bool *present) "v=%p name=%s present=%p"