[glib] GVariant: support NULL for empty arrays in varargs



commit b1d02f9323d4eb157dc99e0b7a79d06a2e510500
Author: Ryan Lortie <desrt desrt ca>
Date:   Fri Feb 11 10:14:29 2011 -0500

    GVariant: support NULL for empty arrays in varargs
    
    g_variant_new("as", NULL); now gives an empty array of strings, for
    example.
    
    This was documented as working already, but was never actually
    implemented (due to the fact that it muddies the water when considering
    maybe types).  It's being implemented now because its convenience to
    programmers exceeds any damage done to the conceptual purity of the API.

 docs/reference/glib/gvariant-varargs.xml |    5 +++
 glib/gvariant.c                          |   52 +++++++++++++++++++----------
 glib/tests/gvariant.c                    |   16 +++++++++
 3 files changed, 55 insertions(+), 18 deletions(-)
---
diff --git a/docs/reference/glib/gvariant-varargs.xml b/docs/reference/glib/gvariant-varargs.xml
index 3342859..8e87cde 100644
--- a/docs/reference/glib/gvariant-varargs.xml
+++ b/docs/reference/glib/gvariant-varargs.xml
@@ -682,6 +682,11 @@ g_variant_unref (value);]]></programlisting></informalexample>
     <link linkend='NULL--CAPS'><literal>NULL</literal></link> becomes a permissable value, to indicate the Nothing case.
    </para>
    <para>
+    Note that the "special exception" introduced in the array section for constructing empty arrays is ignored
+    here.  Using a <literal>NULL</literal> pointer with the format string '<literal>mas</literal>' constructs
+    the Nothing value -- not an empty array.
+   </para>
+   <para>
     The second way is used with all other format strings.  For
     <link linkend='g-variant-new'><function>g_variant_new()</function></link> an additional
     <link linkend='gboolean'><type>gboolean</type></link> argument is collected and for
diff --git a/glib/gvariant.c b/glib/gvariant.c
index 33bae03..6bfc900 100644
--- a/glib/gvariant.c
+++ b/glib/gvariant.c
@@ -3643,30 +3643,46 @@ g_variant_valist_new_nnp (const gchar **str,
   switch (*(*str)++)
     {
     case 'a':
-      {
-        const GVariantType *type;
-        GVariant *value;
+      if (ptr != NULL)
+        {
+          const GVariantType *type;
+          GVariant *value;
 
-        value = g_variant_builder_end (ptr);
-        type = g_variant_get_type (value);
+          value = g_variant_builder_end (ptr);
+          type = g_variant_get_type (value);
 
-        if G_UNLIKELY (!g_variant_type_is_array (type))
-          g_error ("g_variant_new: expected array GVariantBuilder but "
-                   "the built value has type `%s'",
-                   g_variant_get_type_string (value));
+          if G_UNLIKELY (!g_variant_type_is_array (type))
+            g_error ("g_variant_new: expected array GVariantBuilder but "
+                     "the built value has type `%s'",
+                     g_variant_get_type_string (value));
 
-        type = g_variant_type_element (type);
+          type = g_variant_type_element (type);
 
-        if G_UNLIKELY (!g_variant_type_is_subtype_of (type, (GVariantType *) *str))
-          g_error ("g_variant_new: expected GVariantBuilder array element "
-                   "type `%s' but the built value has element type `%s'",
-                   g_variant_type_dup_string ((GVariantType *) *str),
-                   g_variant_get_type_string (value) + 1);
+          if G_UNLIKELY (!g_variant_type_is_subtype_of (type, (GVariantType *) *str))
+            g_error ("g_variant_new: expected GVariantBuilder array element "
+                     "type `%s' but the built value has element type `%s'",
+                     g_variant_type_dup_string ((GVariantType *) *str),
+                     g_variant_get_type_string (value) + 1);
 
-        g_variant_type_string_scan (*str, NULL, str);
+          g_variant_type_string_scan (*str, NULL, str);
 
-        return value;
-      }
+          return value;
+        }
+      else
+
+        /* special case: NULL pointer for empty array */
+        {
+          const GVariantType *type = (GVariantType *) *str;
+
+          g_variant_type_string_scan (*str, NULL, str);
+
+          if G_UNLIKELY (!g_variant_type_is_definite (type))
+            g_error ("g_variant_new: NULL pointer given with indefinite "
+                     "array type; unable to determine which type of empty "
+                     "array to construct.");
+
+          return g_variant_new_array (type, NULL, 0);
+        }
 
     case 's':
       return g_variant_new_string (ptr);
diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
index afbafd4..7fc96e5 100644
--- a/glib/tests/gvariant.c
+++ b/glib/tests/gvariant.c
@@ -3331,6 +3331,22 @@ test_varargs (void)
     g_variant_unref (value);
   }
 
+  {
+    GVariant *value;
+    gchar *str;
+
+    value = g_variant_new ("(masas)", NULL, NULL);
+    g_variant_ref_sink (value);
+
+    str = g_variant_print (value, TRUE);
+    g_assert_cmpstr (str, ==, "(@mas nothing, @as [])");
+    g_variant_unref (value);
+    g_free (str);
+
+    if (do_failed_test ("*which type of empty array*"))
+      g_variant_new ("(a{s*})", NULL);
+  }
+
   g_variant_type_info_assert_no_infos ();
 }
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]