+ g_slice_free (GVariantBuilder, 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
+ *
+ * Ends the builder process and returns the constructed value.
+ *
+ * It is not permissible to use @builder in any way after this call
+ * except for reference counting operations (in the case of a
+ * heap-allocated #GVariantBuilder) or by reinitialising it with
+ * g_variant_builder_init() (in the case of stack-allocated).
+ *
+ * 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.
+ *
+ * Returns: (transfer none): a new, floating, #GVariant
+ *
+ * Since: 2.24
+ **/
+GVariant *
+g_variant_builder_end (GVariantBuilder *builder)
+{
+ GVariantType *my_type;
+ GVariant *value;
+
+ g_return_val_if_fail (is_valid_builder (builder), NULL);
+ g_return_val_if_fail (GVSB(builder)->offset >= GVSB(builder)->min_items,
+ NULL);
+ g_return_val_if_fail (!GVSB(builder)->uniform_item_types ||
+ GVSB(builder)->prev_item_type != NULL ||
+ g_variant_type_is_definite (GVSB(builder)->type),
+ NULL);
+
+ if (g_variant_type_is_definite (GVSB(builder)->type))
+ my_type = g_variant_type_copy (GVSB(builder)->type);
+
+ else if (g_variant_type_is_maybe (GVSB(builder)->type))
+ my_type = g_variant_make_maybe_type (GVSB(builder)->children[0]);
+
+ else if (g_variant_type_is_array (GVSB(builder)->type))
+ my_type = g_variant_make_array_type (GVSB(builder)->children[0]);
+
+ else if (g_variant_type_is_tuple (GVSB(builder)->type))
+ my_type = g_variant_make_tuple_type (GVSB(builder)->children,
+ GVSB(builder)->offset);
+
+ else if (g_variant_type_is_dict_entry (GVSB(builder)->type))
+ my_type = g_variant_make_dict_entry_type (GVSB(builder)->children[0],
+ GVSB(builder)->children[1]);
+ else
+ g_assert_not_reached ();
+
+ value = g_variant_new_from_children (my_type,
+ g_renew (GVariant *,
+ GVSB(builder)->children,
+ GVSB(builder)->offset),
+ GVSB(builder)->offset,
+ GVSB(builder)->trusted);
+ GVSB(builder)->children = NULL;
+ GVSB(builder)->offset = 0;
+
+ g_variant_builder_clear (builder);
+ g_variant_type_free (my_type);
+
+ return value;
+}
+
+/* GVariantDict {{{1 */
+
+/**
+ * GVariantDict:
+ *
+ * #GVariantDict is a mutable interface to #GVariant dictionaries.
+ *
+ * It can be used for doing a sequence of dictionary lookups in an
+ * efficient way on an existing #GVariant dictionary or it can be used
+ * to construct new dictionaries with a hashtable-like interface. It
+ * can also be used for taking existing dictionaries and modifying them
+ * in order to create new ones.
+ *
+ * #GVariantDict can only be used with %G_VARIANT_TYPE_VARDICT
+ * dictionaries.
+ *
+ * It is possible to use #GVariantDict allocated on the stack or on the
+ * heap. When using a stack-allocated #GVariantDict, you begin with a
+ * call to g_variant_dict_init() and free the resources with a call to
+ * g_variant_dict_clear().
+ *
+ * Heap-allocated #GVariantDict follows normal refcounting rules: you
+ * allocate it with g_variant_dict_new() and use g_variant_dict_ref()
+ * and g_variant_dict_unref().
+ *
+ * g_variant_dict_end() is used to convert the #GVariantDict back into a
+ * dictionary-type #GVariant. When used with stack-allocated instances,
+ * this also implicitly frees all associated memory, but for
+ * heap-allocated instances, you must still call g_variant_dict_unref()
+ * afterwards.
+ *
+ * You will typically want to use a heap-allocated #GVariantDict when
+ * you expose it as part of an API. For most other uses, the
+ * stack-allocated form will be more convenient.
+ *
+ * Consider the following two examples that do the same thing in each
+ * style: take an existing dictionary and look up the "count" uint32
+ * key, adding 1 to it if it is found, or returning an error if the
+ * key is not found. Each returns the new dictionary as a floating
+ * #GVariant.
+ *
+ * ## Using a stack-allocated GVariantDict
+ *
+ * |[<!-- language="C" -->
+ * GVariant *
+ * add_to_count (GVariant *orig,
+ * GError **error)
+ * {
+ * GVariantDict dict;
+ * guint32 count;
+ *
+ * g_variant_dict_init (&dict, orig);
+ * if (!g_variant_dict_lookup (&dict, "count", "u", &count))
+ * {
+ * g_set_error (...);
+ * g_variant_dict_clear (&dict);
+ * return NULL;
+ * }
+ *
+ * g_variant_dict_insert (&dict, "count", "u", count + 1);
+ *
+ * return g_variant_dict_end (&dict);
+ * }
+ * ]|
+ *
+ * ## Using heap-allocated GVariantDict
+ *
+ * |[<!-- language="C" -->
+ * GVariant *
+ * add_to_count (GVariant *orig,
+ * GError **error)
+ * {
+ * GVariantDict *dict;
+ * GVariant *result;
+ * guint32 count;
+ *
+ * dict = g_variant_dict_new (orig);
+ *
+ * if (g_variant_dict_lookup (dict, "count", "u", &count))
+ * {
+ * g_variant_dict_insert (dict, "count", "u", count + 1);
+ * result = g_variant_dict_end (dict);
+ * }
+ * else
+ * {
+ * g_set_error (...);
+ * result = NULL;
+ * }
+ *
+ * g_variant_dict_unref (dict);
+ *
+ * return result;
+ * }
+ * ]|
+ *
+ * Since: 2.40
+ **/
+struct stack_dict
+{
+ GHashTable *values;
+ gsize magic;
+};
+
+G_STATIC_ASSERT (sizeof (struct stack_dict) <= sizeof (GVariantDict));
+
+struct heap_dict
+{
+ struct stack_dict dict;
+ gint ref_count;
+ gsize magic;
+};
+
+#define GVSD(d) ((struct stack_dict *) (d))
+#define GVHD(d) ((struct heap_dict *) (d))
+#define GVSD_MAGIC ((gsize) 2579507750u)
+#define GVHD_MAGIC ((gsize) 2450270775u)
+#define is_valid_dict(d) (d != NULL && \
+ GVSD(d)->magic == GVSD_MAGIC)
+#define is_valid_heap_dict(d) (GVHD(d)->magic == GVHD_MAGIC)
+
+/**
+ * g_variant_dict_new:
+ * @from_asv: (allow-none): the #GVariant with which to initialise the
+ * dictionary
+ *
+ * Allocates and initialises a new #GVariantDict.
+ *
+ * You should call g_variant_dict_unref() on the return value when it
+ * is no longer needed. The memory will not be automatically freed by
+ * any other call.
+ *
+ * In some cases it may be easier to place a #GVariantDict directly on
+ * the stack of the calling function and initialise it with
+ * g_variant_dict_init(). This is particularly useful when you are
+ * using #GVariantDict to construct a #GVariant.
+ *
+ * Returns: (transfer full): a #GVariantDict
+ *
+ * Since: 2.40
+ **/
+GVariantDict *
+g_variant_dict_new (GVariant *from_asv)
+{
+ GVariantDict *dict;
+
+ dict = g_slice_alloc (sizeof (struct heap_dict));
+ g_variant_dict_init (dict, from_asv);
+ GVHD(dict)->magic = GVHD_MAGIC;
+ GVHD(dict)->ref_count = 1;
+
+ return dict;
+}
+
+/**
+ * g_variant_dict_init: (skip)
+ * @dict: a #GVariantDict
+ * @from_asv: (allow-none): the initial value for @dict
+ *
+ * Initialises a #GVariantDict structure.
+ *
+ * If @from_asv is given, it is used to initialise the dictionary.
+ *
+ * This function completely ignores the previous contents of @dict. On
+ * one hand this means that it is valid to pass in completely
+ * uninitialised memory. On the other hand, this means that if you are
+ * initialising over top of an existing #GVariantDict you need to first
+ * call g_variant_dict_clear() in order to avoid leaking memory.
+ *
+ * You must not call g_variant_dict_ref() or g_variant_dict_unref() on a
+ * #GVariantDict that was initialised with this function. If you ever
+ * pass a reference to a #GVariantDict outside of the control of your
+ * own code then you should assume that the person receiving that
+ * reference may try to use reference counting; you should use
+ * g_variant_dict_new() instead of this function.
+ *
+ * Since: 2.40
+ **/
+void
+g_variant_dict_init (GVariantDict *dict,
+ GVariant *from_asv)
+{
+ GVariantIter iter;
+ gchar *key;
+ GVariant *value;
+
+ GVSD(dict)->values = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
+ GVSD(dict)->magic = GVSD_MAGIC;
+
+ if (from_asv)
+ {
+ g_variant_iter_init (&iter, from_asv);
+ while (g_variant_iter_next (&iter, "{sv}", &key, &value))
+ g_hash_table_insert (GVSD(dict)->values, key, value);
+ }
+}
+
+/**
+ * g_variant_dict_lookup:
+ * @dict: a #GVariantDict
+ * @key: the key to lookup in the dictionary
+ * @format_string: a GVariant format string
+ * @...: the arguments to unpack the value into
+ *
+ * Looks up a value in a #GVariantDict.
+ *
+ * This function is a wrapper around g_variant_dict_lookup_value() and
+ * g_variant_get(). In the case that %NULL would have been returned,
+ * this function returns %FALSE. Otherwise, it unpacks the returned
+ * value and returns %TRUE.
+ *
+ * @format_string determines the C types that are used for unpacking the
+ * values and also determines if the values are copied or borrowed, see the
+ * section on [GVariant format strings][gvariant-format-strings-pointers].
+ *
+ * Returns: %TRUE if a value was unpacked
+ *
+ * Since: 2.40
+ **/
+gboolean
+g_variant_dict_lookup (GVariantDict *dict,
+ const gchar *key,
+ const gchar *format_string,
+ ...)
+{
+ GVariant *value;
+ va_list ap;
+
+ g_return_val_if_fail (is_valid_dict (dict), FALSE);
+ g_return_val_if_fail (key != NULL, FALSE);
+ g_return_val_if_fail (format_string != NULL, FALSE);
+
+ value = g_hash_table_lookup (GVSD(dict)->values, key);
+
+ if (value == NULL || !g_variant_check_format_string (value, format_string, FALSE))
+ return FALSE;
+
+ va_start (ap, format_string);
+ g_variant_get_va (value, format_string, NULL, &ap);
+ va_end (ap);
+
+ return TRUE;
+}
+
+/**
+ * g_variant_dict_lookup_value:
+ * @dict: a #GVariantDict
+ * @key: the key to lookup in the dictionary
+ * @expected_type: (allow-none): a #GVariantType, or %NULL
+ *
+ * Looks up a value in a #GVariantDict.
+ *
+ * If @key is not found in @dictionary, %NULL is returned.
+ *
+ * The @expected_type string specifies what type of value is expected.
+ * If the value associated with @key has a different type then %NULL is
+ * returned.
+ *
+ * If the key is found and the value has the correct type, it is
+ * returned. If @expected_type was specified then any non-%NULL return
+ * value will have this type.
+ *
+ * Returns: (transfer full): the value of the dictionary key, or %NULL
+ *
+ * Since: 2.40
+ **/
+GVariant *
+g_variant_dict_lookup_value (GVariantDict *dict,
+ const gchar *key,
+ const GVariantType *expected_type)
+{
+ GVariant *result;
+
+ g_return_val_if_fail (is_valid_dict (dict), NULL);
+ g_return_val_if_fail (key != NULL, NULL);
+
+ result = g_hash_table_lookup (GVSD(dict)->values, key);
+
+ if (result && (!expected_type || g_variant_is_of_type (result, expected_type)))
+ return g_variant_ref (result);
+
+ return NULL;
+}
+
+/**
+ * g_variant_dict_contains:
+ * @dict: a #GVariantDict
+ * @key: the key to lookup in the dictionary
+ *
+ * Checks if @key exists in @dict.
+ *
+ * Returns: %TRUE if @key is in @dict
+ *
+ * Since: 2.40
+ **/
+gboolean
+g_variant_dict_contains (GVariantDict *dict,
+ const gchar *key)
+{
+ g_return_val_if_fail (is_valid_dict (dict), FALSE);
+ g_return_val_if_fail (key != NULL, FALSE);
+
+ return g_hash_table_contains (GVSD(dict)->values, key);
+}
+
+/**
+ * g_variant_dict_insert:
+ * @dict: a #GVariantDict
+ * @key: the key to insert a value for
+ * @format_string: a #GVariant varargs format string
+ * @...: arguments, as per @format_string
+ *
+ * Inserts a value into a #GVariantDict.
+ *
+ * This call is a convenience wrapper that is exactly equivalent to
+ * calling g_variant_new() followed by g_variant_dict_insert_value().
+ *
+ * Since: 2.40
+ **/
+void
+g_variant_dict_insert (GVariantDict *dict,
+ const gchar *key,
+ const gchar *format_string,
+ ...)
+{
+ va_list ap;
+
+ g_return_if_fail (is_valid_dict (dict));
+ g_return_if_fail (key != NULL);
+ g_return_if_fail (format_string != NULL);
+
+ va_start (ap, format_string);
+ g_variant_dict_insert_value (dict, key, g_variant_new_va (format_string, NULL, &ap));
+ va_end (ap);
+}
+
+/**
+ * g_variant_dict_insert_value:
+ * @dict: a #GVariantDict
+ * @key: the key to insert a value for
+ * @value: the value to insert
+ *
+ * Inserts (or replaces) a key in a #GVariantDict.
+ *
+ * @value is consumed if it is floating.
+ *
+ * Since: 2.40
+ **/
+void
+g_variant_dict_insert_value (GVariantDict *dict,
+ const gchar *key,
+ GVariant *value)
+{
+ g_return_if_fail (is_valid_dict (dict));
+ g_return_if_fail (key != NULL);
+ g_return_if_fail (value != NULL);
+
+ g_hash_table_insert (GVSD(dict)->values, g_strdup (key), g_variant_ref_sink (value));