[glib] GVariantIter, GVariantBuilder



commit 515434bdcb63073d62b424c4b352a9d509cee5e6
Author: Ryan Lortie <desrt desrt ca>
Date:   Mon Feb 22 00:39:01 2010 -0500

    GVariantIter, GVariantBuilder

 docs/reference/glib/glib-sections.txt     |   22 +
 docs/reference/glib/tmpl/glib-unused.sgml |   67 --
 docs/reference/glib/tmpl/macros_misc.sgml |    5 +-
 docs/reference/glib/tmpl/version.sgml     |   68 ++
 glib/glib.symbols                         |   18 +
 glib/gvariant.c                           | 1387 +++++++++++++++++++++++------
 glib/gvariant.h                           |   36 +
 glib/gvarianttype.c                       |   17 +
 glib/gvarianttype.h                       |    1 +
 9 files changed, 1295 insertions(+), 326 deletions(-)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index 7c71c33..9063458 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -2754,6 +2754,7 @@ g_variant_type_is_maybe
 g_variant_type_is_array
 g_variant_type_is_tuple
 g_variant_type_is_dict_entry
+g_variant_type_is_variant
 
 <SUBSECTION>
 g_variant_type_hash
@@ -2851,6 +2852,27 @@ g_variant_equal
 <SUBSECTION>
 g_variant_print
 g_variant_print_string
+
+<SUBSECTION>
+GVariantIter
+g_variant_iter_copy
+g_variant_iter_free
+g_variant_iter_init
+g_variant_iter_n_children
+g_variant_iter_new
+g_variant_iter_next_value
+g_variant_iter_next
+g_variant_iter_loop
+
+<SUBSECTION>
+GVariantBuilder
+g_variant_builder_unref
+g_variant_builder_ref
+g_variant_builder_new
+g_variant_builder_add_value
+g_variant_builder_end
+g_variant_builder_open
+g_variant_builder_close
 </SECTION>
 
 
diff --git a/docs/reference/glib/tmpl/glib-unused.sgml b/docs/reference/glib/tmpl/glib-unused.sgml
index 139c500..ca73e16 100644
--- a/docs/reference/glib/tmpl/glib-unused.sgml
+++ b/docs/reference/glib/tmpl/glib-unused.sgml
@@ -900,73 +900,6 @@ Turns the argument into a string literal by using the '#' stringizing operator.
 </para>
 
 
-<!-- ##### VARIABLE glib_binary_age ##### -->
-<para>
-This is the binary age passed to <application>libtool</application>. If 
-<application>libtool</application> means nothing to you, don't worry 
-about it. ;-)
-</para>
-
-
-<!-- ##### FUNCTION glib_check_version ##### -->
-<para>
-
-</para>
-
- required_major: 
- required_minor: 
- required_micro: 
- Returns: 
-
-<!-- ##### VARIABLE glib_interface_age ##### -->
-<para>
-This is the interface age passed to <application>libtool</application>. If 
-<application>libtool</application> means nothing to you, don't worry 
-about it. ;-)
-</para>
-
-
-<!-- ##### VARIABLE glib_major_version ##### -->
-<para>
-The major version number of the GLib library. 
-(e.g. in GLib version 1.2.5 this is 1.)
-</para>
-
-<para>
-This variable is in the library, so represents the
-GLib library you have linked against. Contrast with the
-#GLIB_MAJOR_VERSION macro, which represents the major version of the
-GLib headers you have included.
-</para>
-
-
-<!-- ##### VARIABLE glib_micro_version ##### -->
-<para>
-The micro version number of the GLib library.
-(e.g. in GLib version 1.2.5 this is 5.)
-</para>
-
-<para>
-This variable is in the library, so represents the GLib library you
-have linked against. Contrast with the #GLIB_MICRO_VERSION macro, which
-represents the micro version of the GLib headers you have included.
-</para>
-
-
-<!-- ##### VARIABLE glib_minor_version ##### -->
-<para>
-The minor version number of the GLib library.
-(e.g. in GLib version 1.2.5 this is 2.)
-</para>
-
-<para>
-This variable is in the library, so represents the
-GLib library you have linked against. Contrast with the
-#GLIB_MINOR_VERSION macro, which represents the minor version of the
-GLib headers you have included.
-</para>
-
-
 <!-- ##### MACRO lseek ##### -->
 <para>
 
diff --git a/docs/reference/glib/tmpl/macros_misc.sgml b/docs/reference/glib/tmpl/macros_misc.sgml
index 29ad670..7ce3ff3 100644
--- a/docs/reference/glib/tmpl/macros_misc.sgml
+++ b/docs/reference/glib/tmpl/macros_misc.sgml
@@ -403,7 +403,7 @@ Since: 2.14
 
 
 
-<!-- ##### MACRO G_LIKELY ##### -->
+<!-- ##### FUNCTION G_LIKELY ##### -->
 <para>
 Hints the compiler that the expression is likely to evaluate to a true
 value. The compiler may use this information for optimizations.
@@ -413,9 +413,10 @@ if (G_LIKELY (random () != 1))
   g_print ("not one");
 </programlisting></informalexample>
 
- expr: the expression
 @Returns: the value of @expr
 @Since: 2.2
+<!-- # Unused Parameters # -->
+ expr: the expression
 
 
 <!-- ##### MACRO G_UNLIKELY ##### -->
diff --git a/docs/reference/glib/tmpl/version.sgml b/docs/reference/glib/tmpl/version.sgml
index b1cf0bb..f46c1e1 100644
--- a/docs/reference/glib/tmpl/version.sgml
+++ b/docs/reference/glib/tmpl/version.sgml
@@ -19,6 +19,74 @@ typically use the features described here.
 <!-- ##### SECTION Stability_Level ##### -->
 
 
+<!-- ##### VARIABLE glib_major_version ##### -->
+<para>
+The major version number of the GLib library. 
+(e.g. in GLib version 1.2.5 this is 1.)
+</para>
+
+<para>
+This variable is in the library, so represents the
+GLib library you have linked against. Contrast with the
+#GLIB_MAJOR_VERSION macro, which represents the major version of the
+GLib headers you have included.
+</para>
+
+
+<!-- ##### VARIABLE glib_minor_version ##### -->
+<para>
+The minor version number of the GLib library.
+(e.g. in GLib version 1.2.5 this is 2.)
+</para>
+
+<para>
+This variable is in the library, so represents the
+GLib library you have linked against. Contrast with the
+#GLIB_MINOR_VERSION macro, which represents the minor version of the
+GLib headers you have included.
+</para>
+
+
+<!-- ##### VARIABLE glib_micro_version ##### -->
+<para>
+The micro version number of the GLib library.
+(e.g. in GLib version 1.2.5 this is 5.)
+</para>
+
+<para>
+This variable is in the library, so represents the GLib library you
+have linked against. Contrast with the #GLIB_MICRO_VERSION macro, which
+represents the micro version of the GLib headers you have included.
+</para>
+
+
+<!-- ##### VARIABLE glib_binary_age ##### -->
+<para>
+This is the binary age passed to <application>libtool</application>. If 
+<application>libtool</application> means nothing to you, don't worry 
+about it. ;-)
+</para>
+
+
+<!-- ##### VARIABLE glib_interface_age ##### -->
+<para>
+This is the interface age passed to <application>libtool</application>. If 
+<application>libtool</application> means nothing to you, don't worry 
+about it. ;-)
+</para>
+
+
+<!-- ##### FUNCTION glib_check_version ##### -->
+<para>
+
+</para>
+
+ required_major: 
+ required_minor: 
+ required_micro: 
+ Returns: 
+
+
 <!-- ##### MACRO GLIB_MAJOR_VERSION ##### -->
 <para>
 The major version number of the GLib library.
diff --git a/glib/glib.symbols b/glib/glib.symbols
index 8222b2b..2d9786c 100644
--- a/glib/glib.symbols
+++ b/glib/glib.symbols
@@ -1671,6 +1671,7 @@ g_variant_type_is_maybe
 g_variant_type_is_array
 g_variant_type_is_tuple
 g_variant_type_is_dict_entry
+g_variant_type_is_variant
 g_variant_type_hash
 g_variant_type_equal
 g_variant_type_is_subtype_of
@@ -1754,6 +1755,23 @@ g_variant_print_string
 
 g_variant_hash
 g_variant_equal
+
+g_variant_iter_copy
+g_variant_iter_free
+g_variant_iter_init
+g_variant_iter_n_children
+g_variant_iter_new
+g_variant_iter_next
+g_variant_iter_loop
+g_variant_iter_next_value
+
+g_variant_builder_add_value
+g_variant_builder_close
+g_variant_builder_end
+g_variant_builder_new
+g_variant_builder_open
+g_variant_builder_ref
+g_variant_builder_unref
 #endif
 #endif
 
diff --git a/glib/gvariant.c b/glib/gvariant.c
index b0648a9..c28dde9 100644
--- a/glib/gvariant.c
+++ b/glib/gvariant.c
@@ -20,6 +20,8 @@
  * Author: Ryan Lortie <desrt desrt ca>
  */
 
+/* Prologue {{{1 */
+
 #include "config.h"
 
 #include <glib/gvariant-serialiser.h>
@@ -285,6 +287,7 @@
     return val;                                                   \
   }
 
+/* Numeric Type Constructor/Getters {{{1 */
 /* < private >
  * g_variant_new_from_trusted:
  * @type: the #GVariantType
@@ -583,83 +586,7 @@ NUMERIC_TYPE (HANDLE, handle, gint32)
  **/
 NUMERIC_TYPE (DOUBLE, double, gdouble)
 
-/**
- * g_variant_get_type:
- * @value: a #GVariant
- * @returns: a #GVariantType
- *
- * Determines the type of @value.
- *
- * The return value is valid for the lifetime of @value and must not
- * be freed.
- *
- * Since: 2.24
- **/
-const GVariantType *
-g_variant_get_type (GVariant *value)
-{
-  GVariantTypeInfo *type_info;
-
-  g_return_val_if_fail (value != NULL, NULL);
-
-  type_info = g_variant_get_type_info (value);
-
-  return (GVariantType *) g_variant_type_info_get_type_string (type_info);
-}
-
-/**
- * g_variant_get_type_string:
- * @value: a #GVariant
- * @returns: the type string for the type of @value
- *
- * Returns the type string of @value.  Unlike the result of calling
- * g_variant_type_peek_string(), this string is nul-terminated.  This
- * string belongs to #GVariant and must not be freed.
- *
- * Since: 2.24
- **/
-const gchar *
-g_variant_get_type_string (GVariant *value)
-{
-  GVariantTypeInfo *type_info;
-
-  g_return_val_if_fail (value != NULL, NULL);
-
-  type_info = g_variant_get_type_info (value);
-
-  return g_variant_type_info_get_type_string (type_info);
-}
-
-/**
- * g_variant_is_of_type:
- * @value: a #GVariant instance
- * @type: a #GVariantType
- * @returns: %TRUE if the type of @value matches @type
- *
- * Checks if a value has a type matching the provided type.
- *
- * Since: 2.24
- **/
-gboolean
-g_variant_is_of_type (GVariant           *value,
-                      const GVariantType *type)
-{
-  return g_variant_type_is_subtype_of (g_variant_get_type (value), type);
-}
-
-/**
- * g_variant_is_container:
- * @value: a #GVariant instance
- * @returns: %TRUE if @value is a container
- *
- * Checks if @value is a container.
- */
-gboolean
-g_variant_is_container (GVariant *value)
-{
-  return g_variant_type_is_container (g_variant_get_type (value));
-}
-
+/* Container type Constructor / Deconstructors {{{1 */
 /**
  * g_variant_new_maybe:
  * @child_type: the #GVariantType of the child
@@ -773,6 +700,259 @@ g_variant_get_variant (GVariant *value)
 }
 
 /**
+ * g_variant_new_array:
+ * @child_type: the element type of the new array
+ * @children: an array of #GVariant pointers, the children
+ * @n_children: the length of @children
+ * @returns: a new #GVariant array
+ *
+ * Creates a new #GVariant array from @children.
+ *
+ * @child_type must be non-%NULL if @n_children is zero.  Otherwise, the
+ * child type is determined by inspecting the first element of the
+ * @children array.  If @child_type is non-%NULL then it must be a
+ * definite type.
+ *
+ * The items of the array are taken from the @children array.  No entry
+ * in the @children array may be %NULL.
+ *
+ * All items in the array must have the same type, which must be the
+ * same as @child_type, if given.
+ *
+ * Since: 2.24
+ **/
+GVariant *
+g_variant_new_array (const GVariantType *child_type,
+                     GVariant * const   *children,
+                     gsize               n_children)
+{
+  GVariantType *array_type;
+  GVariant **my_children;
+  gboolean trusted;
+  GVariant *value;
+  gsize i;
+
+  g_return_val_if_fail (n_children > 0 || child_type != NULL, NULL);
+  g_return_val_if_fail (n_children == 0 || children != NULL, NULL);
+  g_return_val_if_fail (child_type == NULL ||
+                        g_variant_type_is_definite (child_type), NULL);
+
+  my_children = g_new (GVariant *, n_children);
+  trusted = TRUE;
+
+  if (child_type == NULL)
+    child_type = g_variant_get_type (children[0]);
+  array_type = g_variant_type_new_array (child_type);
+
+  for (i = 0; i < n_children; i++)
+    {
+      TYPE_CHECK (children[i], child_type, NULL);
+      my_children[i] = g_variant_ref_sink (children[i]);
+      trusted &= g_variant_is_trusted (children[i]);
+    }
+
+  value = g_variant_new_from_children (array_type, my_children,
+                                       n_children, trusted);
+  g_variant_type_free (array_type);
+
+  return value;
+}
+
+/*< private >
+ * g_variant_make_tuple_type:
+ * @children: an array of GVariant *
+ * @n_children: the length of @children
+ *
+ * Return the type of a tuple containing @children as its items.
+ **/
+static GVariantType *
+g_variant_make_tuple_type (GVariant * const *children,
+                           gsize             n_children)
+{
+  const GVariantType **types;
+  GVariantType *type;
+  gsize i;
+
+  types = g_new (const GVariantType *, n_children);
+
+  for (i = 0; i < n_children; i++)
+    types[i] = g_variant_get_type (children[i]);
+
+  type = g_variant_type_new_tuple (types, n_children);
+  g_free (types);
+
+  return type;
+}
+
+/**
+ * g_variant_new_tuple:
+ * @children: the items to make the tuple out of
+ * @n_children: the length of @children
+ * @returns: a new #GVariant tuple
+ *
+ * Creates a new tuple #GVariant out of the items in @children.  The
+ * type is determined from the types of @children.  No entry in the
+ * @children array may be %NULL.
+ *
+ * If @n_children is 0 then the unit tuple is constructed.
+ *
+ * Since: 2.24
+ **/
+GVariant *
+g_variant_new_tuple (GVariant * const *children,
+                     gsize             n_children)
+{
+  GVariantType *tuple_type;
+  GVariant **my_children;
+  gboolean trusted;
+  GVariant *value;
+  gsize i;
+
+  g_return_val_if_fail (n_children == 0 || children != NULL, NULL);
+
+  my_children = g_new (GVariant *, n_children);
+  trusted = TRUE;
+
+  for (i = 0; i < n_children; i++)
+    {
+      my_children[i] = g_variant_ref_sink (children[i]);
+      trusted &= g_variant_is_trusted (children[i]);
+    }
+
+  tuple_type = g_variant_make_tuple_type (children, n_children);
+  value = g_variant_new_from_children (tuple_type, my_children,
+                                       n_children, trusted);
+  g_variant_type_free (tuple_type);
+
+  return value;
+}
+
+/*< private >
+ * g_variant_make_dict_entry_type:
+ * @key: a #GVariant, the key
+ * @val: a #GVariant, the value
+ *
+ * Return the type of a dictionary entry containing @key and @val as its
+ * children.
+ **/
+static GVariantType *
+g_variant_make_dict_entry_type (GVariant *key,
+                                GVariant *val)
+{
+  return g_variant_type_new_dict_entry (g_variant_get_type (key),
+                                        g_variant_get_type (val));
+}
+
+/**
+ * g_variant_new_dict_entry:
+ * @key: a basic #GVariant, the key
+ * @value: a #GVariant, the value
+ * @returns: a new dictionary entry #GVariant
+ *
+ * Creates a new dictionary entry #GVariant.  @key and @value must be
+ * non-%NULL.
+ *
+ * @key must be a value of a basic type (ie: not a container).
+ *
+ * Since: 2.24
+ **/
+GVariant *
+g_variant_new_dict_entry (GVariant *key,
+                          GVariant *value)
+{
+  GVariantType *dict_type;
+  GVariant **children;
+  gboolean trusted;
+
+  g_return_val_if_fail (key != NULL && value != NULL, NULL);
+  g_return_val_if_fail (!g_variant_is_container (key), NULL);
+
+  children = g_new (GVariant *, 2);
+  children[0] = g_variant_ref_sink (key);
+  children[1] = g_variant_ref_sink (value);
+  trusted = g_variant_is_trusted (key) && g_variant_is_trusted (value);
+
+  dict_type = g_variant_make_dict_entry_type (key, value);
+  value = g_variant_new_from_children (dict_type, children, 2, trusted);
+  g_variant_type_free (dict_type);
+
+  return value;
+}
+
+/**
+ * g_variant_get_fixed_array:
+ * @value: a #GVariant array with fixed-sized elements
+ * @n_elements: a pointer to the location to store the number of items
+ * @element_size: the size of each element
+ * @returns: a pointer to the fixed array
+ *
+ * Provides access to the serialised data for an array of fixed-sized
+ * items.
+ *
+ * @value must be an array with fixed-sized elements.  Numeric types are
+ * fixed-size as are tuples containing only other fixed-sized types.
+ *
+ * @element_size must be the size of a single element in the array.  For
+ * example, if calling this function for an array of 32 bit integers,
+ * you might say <code>sizeof (gint32)</code>.  This value isn't used
+ * except for the purpose of a double-check that the form of the
+ * seralised data matches the caller's expectation.
+ *
+ * @n_elements, which must be non-%NULL is set equal to the number of
+ * items in the array.
+ *
+ * Since: 2.24
+ **/
+gconstpointer
+g_variant_get_fixed_array (GVariant *value,
+                           gsize    *n_elements,
+                           gsize     element_size)
+{
+  GVariantTypeInfo *array_info;
+  gsize array_element_size;
+  gconstpointer data;
+  gsize size;
+
+  TYPE_CHECK (value, G_VARIANT_TYPE_ARRAY, NULL);
+
+  g_return_val_if_fail (n_elements != NULL, NULL);
+  g_return_val_if_fail (element_size > 0, NULL);
+
+  array_info = g_variant_get_type_info (value);
+  g_variant_type_info_query_element (array_info, NULL, &array_element_size);
+
+  g_return_val_if_fail (array_element_size, NULL);
+
+  if G_UNLIKELY (array_element_size != element_size)
+    {
+      if (array_element_size)
+        g_critical ("g_variant_get_fixed_array: assertion "
+                    "`g_variant_array_has_fixed_size (value, element_size)' "
+                    "failed: array size %"G_GSIZE_FORMAT" does not match "
+                    "given element_size %"G_GSIZE_FORMAT".",
+                    array_element_size, element_size);
+      else
+        g_critical ("g_variant_get_fixed_array: assertion "
+                    "`g_variant_array_has_fixed_size (value, element_size)' "
+                    "failed: array does not have fixed size.");
+    }
+
+  data = g_variant_get_data (value);
+  size = g_variant_get_size (value);
+
+  if (size % element_size)
+    *n_elements = 0;
+  else
+    *n_elements = size / element_size;
+
+  if (*n_elements)
+    return data;
+
+  return NULL;
+}
+
+/* String type constructor/getters/validation {{{1 */
+/**
  * g_variant_new_string:
  * @string: a normal C nul-terminated string
  * @returns: a new string #GVariant instance
@@ -834,7 +1014,6 @@ g_variant_is_object_path (const gchar *string)
   return g_variant_serialiser_is_object_path (string, strlen (string) + 1);
 }
 
-
 /**
  * g_variant_new_signature:
  * @signature: a normal C nul-terminated string
@@ -1100,221 +1279,85 @@ g_variant_dup_strv (GVariant *value,
   return strv;
 }
 
+/* Type checking and querying {{{1 */
 /**
- * g_variant_new_array:
- * @child_type: the element type of the new array
- * @children: an array of #GVariant pointers, the children
- * @n_children: the length of @children
- * @returns: a new #GVariant array
- *
- * Creates a new #GVariant array from @children.
- *
- * @child_type must be non-%NULL if @n_children is zero.  Otherwise, the
- * child type is determined by inspecting the first element of the
- * @children array.  If @child_type is non-%NULL then it must be a
- * definite type.
+ * g_variant_get_type:
+ * @value: a #GVariant
+ * @returns: a #GVariantType
  *
- * The items of the array are taken from the @children array.  No entry
- * in the @children array may be %NULL.
+ * Determines the type of @value.
  *
- * All items in the array must have the same type, which must be the
- * same as @child_type, if given.
+ * The return value is valid for the lifetime of @value and must not
+ * be freed.
  *
  * Since: 2.24
  **/
-GVariant *
-g_variant_new_array (const GVariantType *child_type,
-                     GVariant * const   *children,
-                     gsize               n_children)
+const GVariantType *
+g_variant_get_type (GVariant *value)
 {
-  GVariantType *array_type;
-  GVariant **my_children;
-  gboolean trusted;
-  GVariant *value;
-  gsize i;
-
-  g_return_val_if_fail (n_children > 0 || child_type != NULL, NULL);
-  g_return_val_if_fail (n_children == 0 || children != NULL, NULL);
-  g_return_val_if_fail (child_type == NULL ||
-                        g_variant_type_is_definite (child_type), NULL);
-
-  my_children = g_new (GVariant *, n_children);
-  trusted = TRUE;
-
-  if (child_type == NULL)
-    child_type = g_variant_get_type (children[0]);
-  array_type = g_variant_type_new_array (child_type);
+  GVariantTypeInfo *type_info;
 
-  for (i = 0; i < n_children; i++)
-    {
-      TYPE_CHECK (children[i], child_type, NULL);
-      my_children[i] = g_variant_ref_sink (children[i]);
-      trusted &= g_variant_is_trusted (children[i]);
-    }
+  g_return_val_if_fail (value != NULL, NULL);
 
-  value = g_variant_new_from_children (array_type, my_children,
-                                       n_children, trusted);
-  g_variant_type_free (array_type);
+  type_info = g_variant_get_type_info (value);
 
-  return value;
+  return (GVariantType *) g_variant_type_info_get_type_string (type_info);
 }
 
 /**
- * g_variant_new_tuple:
- * @children: the items to make the tuple out of
- * @n_children: the length of @children
- * @returns: a new #GVariant tuple
- *
- * Creates a new tuple #GVariant out of the items in @children.  The
- * type is determined from the types of @children.  No entry in the
- * @children array may be %NULL.
+ * g_variant_get_type_string:
+ * @value: a #GVariant
+ * @returns: the type string for the type of @value
  *
- * If @n_children is 0 then the unit tuple is constructed.
+ * Returns the type string of @value.  Unlike the result of calling
+ * g_variant_type_peek_string(), this string is nul-terminated.  This
+ * string belongs to #GVariant and must not be freed.
  *
  * Since: 2.24
  **/
-GVariant *
-g_variant_new_tuple (GVariant * const *children,
-                     gsize             n_children)
+const gchar *
+g_variant_get_type_string (GVariant *value)
 {
-  const GVariantType **types;
-  GVariantType *tuple_type;
-  GVariant **my_children;
-  gboolean trusted;
-  GVariant *value;
-  gsize i;
-
-  g_return_val_if_fail (n_children == 0 || children != NULL, NULL);
-
-  types = g_new (const GVariantType *, n_children);
-  my_children = g_new (GVariant *, n_children);
-  trusted = TRUE;
+  GVariantTypeInfo *type_info;
 
-  for (i = 0; i < n_children; i++)
-    {
-      types[i] = g_variant_get_type (children[i]);
-      my_children[i] = g_variant_ref_sink (children[i]);
-      trusted &= g_variant_is_trusted (children[i]);
-    }
+  g_return_val_if_fail (value != NULL, NULL);
 
-  tuple_type = g_variant_type_new_tuple (types, n_children);
-  value = g_variant_new_from_children (tuple_type, my_children,
-                                       n_children, trusted);
-  g_variant_type_free (tuple_type);
-  g_free (types);
+  type_info = g_variant_get_type_info (value);
 
-  return value;
+  return g_variant_type_info_get_type_string (type_info);
 }
 
 /**
- * g_variant_new_dict_entry:
- * @key: a basic #GVariant, the key
- * @value: a #GVariant, the value
- * @returns: a new dictionary entry #GVariant
- *
- * Creates a new dictionary entry #GVariant.  @key and @value must be
- * non-%NULL.
+ * g_variant_is_of_type:
+ * @value: a #GVariant instance
+ * @type: a #GVariantType
+ * @returns: %TRUE if the type of @value matches @type
  *
- * @key must be a value of a basic type (ie: not a container).
+ * Checks if a value has a type matching the provided type.
  *
  * Since: 2.24
  **/
-GVariant *
-g_variant_new_dict_entry (GVariant *key,
-                          GVariant *value)
+gboolean
+g_variant_is_of_type (GVariant           *value,
+                      const GVariantType *type)
 {
-  GVariantType *dict_type;
-  GVariant **children;
-  gboolean trusted;
-
-  g_return_val_if_fail (key != NULL && value != NULL, NULL);
-  g_return_val_if_fail (!g_variant_is_container (key), NULL);
-
-  children = g_new (GVariant *, 2);
-  children[0] = g_variant_ref_sink (key);
-  children[1] = g_variant_ref_sink (value);
-  trusted = g_variant_is_trusted (key) && g_variant_is_trusted (value);
-
-  dict_type = g_variant_type_new_dict_entry (g_variant_get_type (key),
-                                             g_variant_get_type (value));
-  value = g_variant_new_from_children (dict_type, children, 2, trusted);
-  g_variant_type_free (dict_type);
-
-  return value;
+  return g_variant_type_is_subtype_of (g_variant_get_type (value), type);
 }
 
 /**
- * g_variant_get_fixed_array:
- * @value: a #GVariant array with fixed-sized elements
- * @n_elements: a pointer to the location to store the number of items
- * @element_size: the size of each element
- * @returns: a pointer to the fixed array
- *
- * Provides access to the serialised data for an array of fixed-sized
- * items.
- *
- * @value must be an array with fixed-sized elements.  Numeric types are
- * fixed-size as are tuples containing only other fixed-sized types.
- *
- * @element_size must be the size of a single element in the array.  For
- * example, if calling this function for an array of 32 bit integers,
- * you might say <code>sizeof (gint32)</code>.  This value isn't used
- * except for the purpose of a double-check that the form of the
- * seralised data matches the caller's expectation.
- *
- * @n_elements, which must be non-%NULL is set equal to the number of
- * items in the array.
+ * g_variant_is_container:
+ * @value: a #GVariant instance
+ * @returns: %TRUE if @value is a container
  *
- * Since: 2.24
- **/
-gconstpointer
-g_variant_get_fixed_array (GVariant *value,
-                           gsize    *n_elements,
-                           gsize     element_size)
+ * Checks if @value is a container.
+ */
+gboolean
+g_variant_is_container (GVariant *value)
 {
-  GVariantTypeInfo *array_info;
-  gsize array_element_size;
-  gconstpointer data;
-  gsize size;
-
-  TYPE_CHECK (value, G_VARIANT_TYPE_ARRAY, NULL);
-
-  g_return_val_if_fail (n_elements != NULL, NULL);
-  g_return_val_if_fail (element_size > 0, NULL);
-
-  array_info = g_variant_get_type_info (value);
-  g_variant_type_info_query_element (array_info, NULL, &array_element_size);
-
-  g_return_val_if_fail (array_element_size, NULL);
-
-  if G_UNLIKELY (array_element_size != element_size)
-    {
-      if (array_element_size)
-        g_critical ("g_variant_get_fixed_array: assertion "
-                    "`g_variant_array_has_fixed_size (value, element_size)' "
-                    "failed: array size %"G_GSIZE_FORMAT" does not match "
-                    "given element_size %"G_GSIZE_FORMAT".",
-                    array_element_size, element_size);
-      else
-        g_critical ("g_variant_get_fixed_array: assertion "
-                    "`g_variant_array_has_fixed_size (value, element_size)' "
-                    "failed: array does not have fixed size.");
-    }
-
-  data = g_variant_get_data (value);
-  size = g_variant_get_size (value);
-
-  if (size % element_size)
-    *n_elements = 0;
-  else
-    *n_elements = size / element_size;
-
-  if (*n_elements)
-    return data;
-
-  return NULL;
+  return g_variant_type_is_container (g_variant_get_type (value));
 }
 
+
 /**
  * g_variant_classify:
  * @value: a #GVariant
@@ -1359,6 +1402,7 @@ g_variant_classify (GVariant *value)
   return *g_variant_get_type_string (value);
 }
 
+/* Pretty printer {{{1 */
 /**
  * g_variant_print_string:
  * @value: a #GVariant
@@ -1703,6 +1747,7 @@ g_variant_print (GVariant *value,
                         FALSE);
 };
 
+/* Hash, Equal {{{1 */
 /**
  * g_variant_hash:
  * @value: a basic #GVariant value as a #gconstpointer
@@ -1854,5 +1899,833 @@ g_variant_equal (gconstpointer one,
   return equal;
 }
 
+/* GVariantIter {{{1 */
+/**
+ * GVariantIter:
+ *
+ * #GVariantIter is an opaque data structure and can only be accessed
+ * using the following functions.
+ **/
+struct stack_iter
+{
+  GVariant *value;
+  gssize n, i;
+
+  const gchar *loop_format;
+
+  gsize padding[3];
+  gsize magic;
+};
+
+struct heap_iter
+{
+  struct stack_iter iter;
+
+  GVariant *value_ref;
+  gsize magic;
+};
+
+#define GVSI(i)                 ((struct stack_iter *) (i))
+#define GVHI(i)                 ((struct heap_iter *) (i))
+#define GVSI_MAGIC              ((gsize) 3579507750u)
+#define GVHI_MAGIC              ((gsize) 1450270775u)
+#define is_valid_iter(i)        (GVSI(i)->magic == GVSI_MAGIC)
+#define is_valid_heap_iter(i)   (GVHI(i)->magic == GVHI_MAGIC && \
+                                 is_valid_iter(i))
+
+/**
+ * g_variant_iter_new:
+ * @value: a container #GVariant
+ * @returns: a new heap-allocated #GVariantIter
+ *
+ * Creates a heap-allocated #GVariantIter for iterating over the items
+ * in @value.
+ *
+ * Use g_variant_iter_free() to free the return value when you no longer
+ * need it.
+ *
+ * A reference is taken to @value and will be released only when
+ * g_variant_iter_free() is called.
+ *
+ * Since: 2.24
+ **/
+GVariantIter *
+g_variant_iter_new (GVariant *value)
+{
+  GVariantIter *iter;
+
+  iter = (GVariantIter *) g_slice_new (struct heap_iter);
+  GVHI(iter)->value_ref = g_variant_ref (value);
+  GVHI(iter)->magic = GVHI_MAGIC;
+
+  g_variant_iter_init (iter, value);
+
+  return iter;
+}
+
+/**
+ * g_variant_iter_init:
+ * @iter: a pointer to a #GVariantIter
+ * @value: a container #GVariant
+ * @returns: the number of items in @value
+ *
+ * Initialises (without allocating) a #GVariantIter.  @iter may be
+ * completely uninitialised prior to this call; its old value is
+ * ignored.
+ *
+ * The iterator remains valid for as long as @value exists, and need not
+ * be freed in any way.
+ *
+ * Since: 2.24
+ **/
+gsize
+g_variant_iter_init (GVariantIter *iter,
+                     GVariant     *value)
+{
+  g_assert (sizeof (GVariantIter) == sizeof (struct stack_iter));
+
+  GVSI(iter)->magic = GVSI_MAGIC;
+  GVSI(iter)->value = value;
+  GVSI(iter)->n = g_variant_n_children (value);
+  GVSI(iter)->i = -1;
+  GVSI(iter)->loop_format = NULL;
+
+  return GVSI(iter)->n;
+}
+
+/**
+ * g_variant_iter_copy:
+ * @iter: a #GVariantIter
+ * @returns: a new heap-allocated #GVariantIter
+ *
+ * Creates a new heap-allocated #GVariantIter to iterate over the
+ * container that was being iterated over by @iter.  Iteration begins on
+ * the new iterator from the current position of the old iterator but
+ * the two copies are independent past that point.
+ *
+ * Use g_variant_iter_free() to free the return value when you no longer
+ * need it.
+ *
+ * A reference is taken to the container that @iter is iterating over
+ * and will be releated only when g_variant_iter_free() is called.
+ *
+ * Since: 2.24
+ **/
+GVariantIter *
+g_variant_iter_copy (GVariantIter *iter)
+{
+  GVariantIter *copy;
+
+  g_return_val_if_fail (is_valid_iter (iter), 0);
+
+  copy = g_variant_iter_new (GVSI(iter)->value);
+  GVSI(copy)->i = GVSI(iter)->i;
+
+  return copy;
+}
+
+/**
+ * g_variant_iter_n_children:
+ * @iter: a #GVariantIter
+ * @returns: the number of children in the container
+ *
+ * Queries the number of child items in the container that we are
+ * iterating over.  This is the total number of items -- not the number
+ * of items remaining.
+ *
+ * This function might be useful for preallocation of arrays.
+ *
+ * Since: 2.24
+ **/
+gsize
+g_variant_iter_n_children (GVariantIter *iter)
+{
+  g_return_val_if_fail (is_valid_iter (iter), 0);
+
+  return GVSI(iter)->n;
+}
+
+/**
+ * g_variant_iter_free:
+ * @iter: a heap-allocated #GVariantIter
+ *
+ * Frees a heap-allocated #GVariantIter.  Only call this function on
+ * iterators that were returned by g_variant_iter_new() or
+ * g_variant_iter_copy().
+ *
+ * Since: 2.24
+ **/
+void
+g_variant_iter_free (GVariantIter *iter)
+{
+  g_return_if_fail (is_valid_heap_iter (iter));
+
+  g_variant_unref (GVHI(iter)->value_ref);
+  GVHI(iter)->magic = 0;
+
+  g_slice_free (struct heap_iter, GVHI(iter));
+}
+
+/**
+ * g_variant_iter_next_value:
+ * @iter: a #GVariantIter
+ * @returns: a #GVariant, or %NULL
+ *
+ * Gets the next item in the container.  If no more items remain then
+ * %NULL is returned.
+ *
+ * Use g_variant_unref() to drop your reference on the return value when
+ * you no longer need it.
+ *
+ * <example>
+ *  <title>Iterating with g_variant_iter_next_value()</title>
+ *  <programlisting>
+ *   /<!-- -->* recursively iterate a container *<!-- -->/
+ *   void
+ *   iterate_container_recursive (GVariant *container)
+ *   {
+ *     GVariantIter iter;
+ *     GVariant *child;
+ *
+ *     g_variant_iter_init (&iter, dictionary);
+ *     while ((child = g_variant_iter_next_value (&iter)))
+ *       {
+ *         g_print ("type '%s'\n", g_variant_get_type_string (child));
+ *
+ *         if (g_variant_is_container (child))
+ *           iterate_container_recursive (child);
+ *
+ *         g_variant_unref (child);
+ *       }
+ *   }
+ * </programlisting>
+ * </example>
+ *
+ * Since: 2.24
+ **/
+GVariant *
+g_variant_iter_next_value (GVariantIter *iter)
+{
+  g_return_val_if_fail (is_valid_iter (iter), FALSE);
+
+  if G_UNLIKELY (GVSI(iter)->i >= GVSI(iter)->n)
+    {
+      g_critical ("g_variant_iter_next_value: must not be called again "
+                  "after NULL has already been returned.");
+      return NULL;
+    }
+
+  GVSI(iter)->i++;
+
+  if (GVSI(iter)->i < GVSI(iter)->n)
+    return g_variant_get_child_value (GVSI(iter)->value, GVSI(iter)->i);
+
+  return NULL;
+}
+
+/**
+ * g_variant_iter_loop:
+ * @iter: a #GVariantIter
+ * @format_string: a GVariant format string
+ * @...: the arguments to unpack the value into
+ * @returns: %TRUE if a value was unpacked, or %FALSE if there as no
+ *           value
+ *
+ * Gets the next item in the container and unpacks it into the variable
+ * argument list according to @format_string, returning %TRUE.
+ *
+ * If no more items remain then %FALSE is returned.
+ *
+ * On the first call to this function, the pointers appearing on the
+ * variable argument list are assumed to point at uninitialised memory.
+ * On the second and later calls, it is assumed that the same pointers
+ * will be given and that they will point to the memory as set by the
+ * previous call to this function.  This allows the previous values to
+ * be freed, as appropriate.
+ *
+ * This function is intended to be used with a while loop as
+ * demonstrated in the following example.  This function can only be
+ * used when iterating over an array.  It is only valid to call this
+ * function with a string constant for the format string and the same
+ * string constant must be used each time.  Mixing calls to this
+ * function and g_variant_iter_next() or g_variant_iter_next_value() on
+ * the same iterator is not recommended.
+ *
+ * <example>
+ *  <title>Memory management with g_variant_iter_loop()</title>
+ *  <programlisting>
+ *   /<!-- -->* Iterates a dictionary of type 'a{sv}' *<!-- -->/
+ *   void
+ *   iterate_dictionary (GVariant *dictionary)
+ *   {
+ *     GVariantIter iter;
+ *     GVariant *value;
+ *     gchar *key;
+ *
+ *     g_variant_iter_init (&iter, dictionary);
+ *     while (g_variant_iter_loop (&iter, "{sv}", &key, &value))
+ *       {
+ *         g_print ("Item '%s' has type '%s'\n", key,
+ *                  g_variant_get_type_string (value));
+ *
+ *         /<!-- -->* no need to free 'key' and 'value' here *<!-- -->/
+ *       }
+ *   }
+ *  </programlisting>
+ * </example>
+ *
+ * If you want a slightly less magical alternative that requires more
+ * typing, see g_variant_iter_next().
+ *
+ * Since: 2.24
+ **/
+gboolean
+g_variant_iter_loop (GVariantIter *iter,
+                     const gchar  *format_string,
+                     ...)
+{
+  gboolean first_time = GVSI(iter)->loop_format == NULL;
+  GVariant *value;
+
+  g_return_val_if_fail (first_time ||
+                        format_string == GVSI(iter)->loop_format,
+                        FALSE);
+
+  if (first_time)
+    {
+      TYPE_CHECK (GVSI(iter)->value, G_VARIANT_TYPE_ARRAY, FALSE);
+      GVSI(iter)->loop_format = format_string;
+    }
+
+  value = g_variant_iter_next_value (iter);
+
+  if (value != NULL)
+    {
+      va_list ap;
+
+      va_start (ap, format_string);
+      /* varargs get stuff */
+      va_end (ap);
+
+      g_variant_unref (value);
+    }
+
+  return value != NULL;
+}
+
+/**
+ * g_variant_iter_next:
+ * @iter: a #GVariantIter
+ * @format_string: a GVariant format string
+ * @...: the arguments to unpack the value into
+ * @returns: %TRUE if a value was unpacked, or %FALSE if there as no
+ *           value
+ *
+ * Gets the next item in the container and unpacks it into the variable
+ * argument list according to @format_string, returning %TRUE.
+ *
+ * If no more items remain then %FALSE is returned.
+ *
+ * All of the pointers given on the variable arguments list of this
+ * function are assumed to point at uninitialised memory.  It is the
+ * responsibility of the caller to free all of the values returned by
+ * the unpacking process.
+ *
+ * <example>
+ *  <title>Memory management with g_variant_iter_next()</title>
+ *  <programlisting>
+ *   /<!-- -->* Iterates a dictionary of type 'a{sv}' *<!-- -->/
+ *   void
+ *   iterate_dictionary (GVariant *dictionary)
+ *   {
+ *     GVariantIter iter;
+ *     GVariant *value;
+ *     gchar *key;
+ *
+ *     g_variant_iter_init (&iter, dictionary);
+ *     while (g_variant_iter_next (&iter, "{sv}", &key, &value))
+ *       {
+ *         g_print ("Item '%s' has type '%s'\n", key,
+ *                  g_variant_get_type_string (value));
+ *
+ *         /<!-- -->* must free data for ourselves *<!-- -->/
+ *         g_variant_unref (value);
+ *         g_free (key);
+ *       }
+ *   }
+ *  </programlisting>
+ * </example>
+ *
+ * For a solution that is likely to be more convenient to C programmers,
+ * see g_variant_iter_loop().
+ *
+ * Since: 2.24
+ **/
+gboolean
+g_variant_iter_next (GVariantIter *iter,
+                     const gchar  *format_string,
+                     ...)
+{
+  GVariant *value;
+
+  value = g_variant_iter_next_value (iter);
+
+  if (value != NULL)
+    {
+      va_list ap;
+
+      va_start (ap, format_string);
+      /* varargs get stuff */
+      va_end (ap);
+
+      g_variant_unref (value);
+    }
+
+  return value != NULL;
+}
+
+/* GVariantBuilder {{{1 */
+
+/**
+ * GVariantBuilder:
+ *
+ * A utility class for constructing container-type #GVariant instances.
+ *
+ * This is an opaque structure and may only be accessed using the
+ * following functions.
+ *
+ * #GVariantBuilder is not threadsafe in any way.  Do not attempt to
+ * access it from more than one thread.
+ **/
+struct _GVariantBuilder
+{
+  GVariantBuilder *parent;
+  GVariantType *type;
+
+  /* type constraint explicitly specified by 'type'.
+   * for tuple types, this moves along as we add more items.
+   */
+  const GVariantType *expected_type;
+
+  /* type constraint implied by previous array item.
+   */
+  const GVariantType *prev_item_type;
+
+  /* constraints on the number of children.  max = -1 for unlimited. */
+  gsize min_items;
+  gsize max_items;
+
+  /* dynamically-growing pointer array */
+  GVariant **children;
+  gsize allocated_children;
+  gsize offset;
+
+  /* set to '1' if all items in the container will have the same type
+   * (ie: maybe, array, variant) '0' if not (ie: tuple, dict entry)
+   */
+  guint uniform_item_types : 1;
+
+  /* set to '1' until _end() or _close() is called. */
+  guint is_active : 1;
+
+  /* set to '1' by _open() until _close() is called */
+  guint has_child : 1;
+
+  /* set to '1' initially and changed to '0' if an untrusted value is
+   * added
+   */
+  guint trusted : 1;
+
+  gint ref_count;
+};
+
+/**
+ * g_variant_builder_new:
+ * @type: a container type
+ * @returns: a #GVariantBuilder
+ *
+ * Creates a new #GVariantBuilder.
+ *
+ * @type must be non-%NULL.  It specifies the type of container to
+ * construct.  It can be an indefinite type such as
+ * %G_VARIANT_TYPE_ARRAY or a definite type such as "as" or "(ii)".
+ * Maybe, array, tuple, dictionary entry and variants may be
+ * constructed.
+ *
+ * After the builder is created, values are added using
+ * g_variant_builder_add_value() or g_variant_builder_add().
+ *
+ * After all the child values are added, g_variant_builder_end() frees
+ * the builder and returns the #GVariant that was created.
+ **/
+GVariantBuilder *
+g_variant_builder_new (const GVariantType *type)
+{
+  GVariantBuilder *builder;
+
+  g_return_val_if_fail (type != NULL, NULL);
+  g_return_val_if_fail (g_variant_type_is_container (type), NULL);
+
+  builder = g_slice_new (GVariantBuilder);
+  builder->parent = NULL;
+  builder->offset = 0;
+
+  builder->has_child = FALSE;
+  builder->is_active = TRUE;
+  builder->trusted = TRUE;
+
+  builder->type = g_variant_type_copy (type);
+  builder->prev_item_type = NULL;
+
+  builder->ref_count = 1;
+
+  switch (*(const gchar *) type)
+    {
+    case G_VARIANT_CLASS_VARIANT:
+      builder->uniform_item_types = TRUE;
+      builder->allocated_children = 1;
+      builder->expected_type = NULL;
+      builder->min_items = 1;
+      builder->max_items = 1;
+      break;
+
+    case G_VARIANT_CLASS_ARRAY:
+      builder->uniform_item_types = TRUE;
+      builder->allocated_children = 8;
+      builder->expected_type = g_variant_type_element (builder->type);
+      builder->min_items = 0;
+      builder->max_items = -1;
+      break;
+
+    case G_VARIANT_CLASS_MAYBE:
+      builder->uniform_item_types = TRUE;
+      builder->allocated_children = 1;
+      builder->expected_type = g_variant_type_element (builder->type);
+      builder->min_items = 0;
+      builder->max_items = 1;
+      break;
+
+    case G_VARIANT_CLASS_DICT_ENTRY:
+      builder->uniform_item_types = FALSE;
+      builder->allocated_children = 2;
+      builder->expected_type = g_variant_type_key (builder->type);
+      builder->min_items = 2;
+      builder->max_items = 2;
+      break;
+
+    case 'r': /* G_VARIANT_TYPE_TUPLE was given */
+      builder->uniform_item_types = FALSE;
+      builder->allocated_children = 8;
+      builder->expected_type = NULL;
+      builder->min_items = 0;
+      builder->max_items = -1;
+      break;
+
+    case G_VARIANT_CLASS_TUPLE: /* a definite tuple type was given */
+      builder->allocated_children = g_variant_type_n_items (type);
+      builder->expected_type = g_variant_type_first (builder->type);
+      builder->min_items = builder->allocated_children;
+      builder->max_items = builder->allocated_children;
+      builder->uniform_item_types = FALSE;
+      break;
+
+    default:
+      g_assert_not_reached ();
+   }
+
+  builder->children = g_new (GVariant *, builder->allocated_children);
+
+  return builder;
+}
+
+/**
+ * g_variant_builder_unref:
+ * @builder: a #GVariantBuilder
+ *
+ * Reduces the reference count on @builder.  If no other references are
+ * held, the builder is freed.  If the builder was created using
+ * g_variant_builder_open() then this may result in the destruction of
+ * the parent builder too (if no other references are held on it).
+ **/
+void
+g_variant_builder_unref (GVariantBuilder *builder)
+{
+  GVariantBuilder *parent;
+  gsize i;
+
+  if (--builder->ref_count)
+    return;
+
+  for (i = 0; i < builder->offset; i++)
+    g_variant_unref (builder->children[i]);
+
+  g_free (builder->children);
+
+  parent = builder->parent;
+  g_slice_free (GVariantBuilder, builder);
+
+  g_variant_builder_unref (parent);
+}
+
+/**
+ * g_variant_builder_ref;
+ * @builder: a #GVariantBuilder
+ * @returns: the same #GVariantBuilder
+ *
+ * Increases the reference count on @builder by 1.
+ **/
+GVariantBuilder *
+g_variant_builder_ref (GVariantBuilder *builder)
+{
+  builder->ref_count++;
+
+  return builder;
+}
+
+static void
+g_variant_builder_make_room (GVariantBuilder *builder)
+{
+  if (builder->offset == builder->allocated_children)
+    {
+      builder->allocated_children *= 2;
+      builder->children = g_renew (GVariant *, builder->children,
+                                   builder->allocated_children);
+    }
+}
+
+/**
+ * g_variant_builder_add_value:
+ * @builder: a #GVariantBuilder
+ * @value: a #GVariant
+ *
+ * Adds @value to @builder.
+ *
+ * It is an error to call this function in any way that would create an
+ * inconsistent value to be constructed.  Some examples of this are
+ * putting different types of items into an array, putting the wrong
+ * types or number of items in a tuple, putting more than one value into
+ * a variant, etc.
+ **/
+void
+g_variant_builder_add_value (GVariantBuilder *builder,
+                             GVariant        *value)
+{
+  g_return_if_fail (builder != NULL && value != NULL);
+  g_return_if_fail (builder->is_active && !builder->has_child);
+  g_return_if_fail (builder->offset < builder->max_items);
+  g_return_if_fail (builder->expected_type &&
+                    g_variant_is_of_type (value, builder->expected_type));
+  g_return_if_fail (builder->prev_item_type &&
+                    g_variant_is_of_type (value, builder->prev_item_type));
+
+  builder->trusted &= g_variant_is_trusted (value);
+
+  if (!builder->uniform_item_types)
+    {
+      /* advance our expected type pointers */
+      if (builder->expected_type)
+        builder->expected_type =
+          g_variant_type_next (builder->expected_type);
+
+      if (builder->prev_item_type)
+        builder->prev_item_type =
+          g_variant_type_next (builder->prev_item_type);
+    }
+  else
+    builder->prev_item_type = g_variant_get_type (value);
+
+  g_variant_builder_make_room (builder);
+
+  builder->children[builder->offset++] = g_variant_ref_sink (value);
+}
+
+/**
+ * g_variant_builder_open:
+ * @builder: a #GVariantBuilder
+ * @type: a #GVariantType
+ * @returns: a new #GVariantBuilder
+ *
+ * Opens a subcontainer inside the given @builder.
+ *
+ * This call consumes the caller's reference to @builder.
+ * g_variant_builder_close() returns the reference.
+ *
+ * Even if additional references are held, it is not permissible to use
+ * @builder in any way (except for further reference counting
+ * operations) until g_variant_builder_close() is called on the return
+ * value of this function.
+ *
+ * It is an error to call this function in any way that would create an
+ * inconsistent value to be constructed.
+ **/
+GVariantBuilder *
+g_variant_builder_open (GVariantBuilder    *builder,
+                        const GVariantType *type)
+{
+  GVariantBuilder *child;
+
+  g_return_val_if_fail (builder != NULL && type != NULL, NULL);
+  g_return_val_if_fail (builder->is_active && !builder->has_child, NULL);
+  g_return_val_if_fail (builder->offset < builder->max_items, NULL);
+  g_return_val_if_fail (builder->expected_type &&
+                        g_variant_type_is_subtype_of (type,
+                                                      builder->expected_type),
+                        NULL);
+  g_return_val_if_fail (builder->prev_item_type &&
+                        g_variant_type_is_subtype_of (builder->prev_item_type,
+                                                      type), NULL);
+  child = g_variant_builder_new (type);
+  builder->has_child = TRUE;
+  child->parent = builder;
+
+  /* push the prev_item_type down into the subcontainer */
+  if (builder->prev_item_type)
+    {
+      if (!child->uniform_item_types)
+        /* tuples and dict entries */
+        child->prev_item_type =
+          g_variant_type_first (builder->prev_item_type);
+
+      else if (!g_variant_type_is_variant (child->type))
+        /* maybes and arrays */
+        child->prev_item_type =
+          g_variant_type_element (builder->prev_item_type);
+    }
+
+  return child;
+}
+
+/**
+ * g_variant_builder_close:
+ * @builder: a #GVariantBuilder
+ * @returns: the original parent of @builder
+ *
+ * This function closes a builder that was created with a call to
+ * g_variant_builder_open().
+ *
+ * This function consumes the caller's reference to @builder and drops
+ * it.  The return result is the reference to the parent
+ * #GVariantBuilder that was originally taken from the caller by
+ * g_variant_builder_open().
+ *
+ * Even if additional references are held, it is not permissible to use
+ * @builder in any way after this call except for further reference
+ * counting operations.
+ *
+ * It is an error to call this function in any way that would create an
+ * inconsistent value to be constructed (ie: insufficient number of
+ * items added to a container with a specific number of children
+ * required).  It is also an error to call this function if the builder
+ * was created with an indefinite array or maybe type and no children
+ * have been added; in this case it is impossible to infer the type of
+ * the empty array.
+ **/
+GVariantBuilder *
+g_variant_builder_close (GVariantBuilder *builder)
+{
+  GVariantBuilder *parent;
+
+  g_return_val_if_fail (builder != NULL, NULL);
+  g_return_val_if_fail (builder->parent != NULL, NULL);
+  g_assert (builder->parent->has_child);
+
+  /* steal reference so _end() doesn't free it. */
+  parent = builder->parent;
+  builder->parent = NULL;
+
+  parent->has_child = FALSE;
+
+  g_variant_builder_add_value (parent, g_variant_builder_end (builder));
+
+  return parent;
+}
+
+/*< private >
+ * g_variant_make_maybe_type:
+ * @element: a #GVariant
+ *
+ * Return the type of a maybe containing @element.
+ */
+static GVariantType *
+g_variant_make_maybe_type (GVariant *element)
+{
+  return g_variant_type_new_maybe (g_variant_get_type (element));
+}
+
+/*< private >
+ * g_variant_make_array_type:
+ * @element: a #GVariant
+ *
+ * Return the type of an array containing @element.
+ */
+static GVariantType *
+g_variant_make_array_type (GVariant *element)
+{
+  return g_variant_type_new_array (g_variant_get_type (element));
+}
+
+/**
+ * g_variant_builder_end:
+ * @builder: a #GVariantBuilder
+ * @returns: a new, floating, #GVariant
+ *
+ * Ends the builder process and returns the constructed value.
+ *
+ * It is an error to call this function on a #GVariantBuilder created
+ * by a call to g_variant_builder_open().  It is an error to call this
+ * function if @builder has an outstanding child.  It is an error to
+ * call this function in any case that g_variant_builder_check_end()
+ * would return %FALSE.
+ **/
+GVariant *
+g_variant_builder_end (GVariantBuilder *builder)
+{
+  GVariantType *my_type;
+  GVariant *value;
+
+  g_return_val_if_fail (builder != NULL, NULL);
+  g_return_val_if_fail (builder->is_active && !builder->has_child, NULL);
+  g_return_val_if_fail (builder->offset >= builder->min_items, NULL);
+  g_return_val_if_fail (!builder->uniform_item_types ||
+                        builder->prev_item_type != NULL ||
+                        g_variant_type_is_definite (builder->type), NULL);
+
+  if (g_variant_type_is_definite (builder->type))
+    my_type = g_variant_type_copy (builder->type);
+
+  else if (g_variant_type_is_maybe (builder->type))
+    my_type = g_variant_make_maybe_type (builder->children[0]);
+
+  else if (g_variant_type_is_array (builder->type))
+    my_type = g_variant_make_array_type (builder->children[0]);
+
+  else if (g_variant_type_is_tuple (builder->type))
+    my_type = g_variant_make_tuple_type (builder->children, builder->offset);
+
+  else if (g_variant_type_is_dict_entry (builder->type))
+    my_type = g_variant_make_dict_entry_type (builder->children[0],
+                                              builder->children[1]);
+  else
+    g_assert_not_reached ();
+
+  value = g_variant_new_from_children (my_type,
+                                       g_renew (GVariant *,
+                                                builder->children,
+                                                builder->offset),
+                                       builder->offset,
+                                       builder->trusted);
+  builder->is_active = FALSE;
+  builder->children = NULL;
+
+  g_variant_type_free (builder->type);
+  g_slice_free (GVariantBuilder, builder);
+  g_variant_type_free (my_type);
+
+  return value;
+}
+
+/* Epilogue {{{1 */
 #define __G_VARIANT_C__
 #include "galiasdef.c"
+
+/* vim:set foldmethod=marker: */
diff --git a/glib/gvariant.h b/glib/gvariant.h
index 1860bc2..2dade1f 100644
--- a/glib/gvariant.h
+++ b/glib/gvariant.h
@@ -135,6 +135,42 @@ guint                           g_variant_hash                          (gconstp
 gboolean                        g_variant_equal                         (gconstpointer         one,
                                                                          gconstpointer         two);
 
+typedef struct _GVariantIter GVariantIter;
+struct _GVariantIter {
+  /*< private >*/
+  gsize x[8];
+};
+
+GVariantIter *                  g_variant_iter_new                      (GVariant             *value);
+gsize                           g_variant_iter_init                     (GVariantIter         *iter,
+                                                                         GVariant             *value);
+GVariantIter *                  g_variant_iter_copy                     (GVariantIter         *iter);
+gsize                           g_variant_iter_n_children               (GVariantIter         *iter);
+void                            g_variant_iter_free                     (GVariantIter         *iter);
+GVariant *                      g_variant_iter_next_value               (GVariantIter         *iter);
+gboolean                        g_variant_iter_next                     (GVariantIter         *iter,
+                                                                         const gchar          *format_string,
+                                                                         ...);
+gboolean                        g_variant_iter_loop                     (GVariantIter         *iter,
+                                                                         const gchar          *format_string,
+                                                                         ...);
+
+
+typedef struct _GVariantBuilder GVariantBuilder;
+
+void                            g_variant_builder_unref                 (GVariantBuilder      *builder);
+GVariantBuilder *               g_variant_builder_ref                   (GVariantBuilder      *builder);
+GVariantBuilder *               g_variant_builder_new                   (const GVariantType   *type);
+GVariant *                      g_variant_builder_end                   (GVariantBuilder      *builder);
+GVariantBuilder *               g_variant_builder_open                  (GVariantBuilder      *builder,
+                                                                         const GVariantType   *type);
+GVariantBuilder *               g_variant_builder_close                 (GVariantBuilder      *builder);
+void                            g_variant_builder_add_value             (GVariantBuilder      *builder,
+                                                                         GVariant             *value);
+void                            g_variant_builder_add                   (GVariantBuilder      *builder,
+                                                                         const gchar          *format_string,
+                                                                         ...);
+
 G_END_DECLS
 
 #endif /* __G_VARIANT_H__ */
diff --git a/glib/gvarianttype.c b/glib/gvarianttype.c
index 6581c55..1c1d158 100644
--- a/glib/gvarianttype.c
+++ b/glib/gvarianttype.c
@@ -960,6 +960,23 @@ g_variant_type_is_dict_entry (const GVariantType *type)
 }
 
 /**
+ * g_variant_type_is_variant:
+ * @type: a #GVariantType
+ * @returns: %TRUE if @type is the variant type
+ *
+ * Determines if the given @type is the variant type.
+ *
+ * Since 2.24
+ **/
+gboolean
+g_variant_type_is_variant (const GVariantType *type)
+{
+  g_return_val_if_fail (g_variant_type_check (type), FALSE);
+
+  return g_variant_type_peek_string (type)[0] == 'v';
+}
+
+/**
  * g_variant_type_hash:
  * @type: a #GVariantType
  * @returns: the hash value
diff --git a/glib/gvarianttype.h b/glib/gvarianttype.h
index 1160754..1a477d6 100644
--- a/glib/gvarianttype.h
+++ b/glib/gvarianttype.h
@@ -270,6 +270,7 @@ gboolean                        g_variant_type_is_maybe                 (const G
 gboolean                        g_variant_type_is_array                 (const GVariantType  *type);
 gboolean                        g_variant_type_is_tuple                 (const GVariantType  *type);
 gboolean                        g_variant_type_is_dict_entry            (const GVariantType  *type);
+gboolean                        g_variant_type_is_variant               (const GVariantType  *type);
 
 /* for hash tables */
 guint                           g_variant_type_hash                     (gconstpointer        type);



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