[glib] Add g_variant_lookup() and tests



commit 7fc6f8a1596b18a23e1570fc6716b34a137b76c6
Author: Ryan Lortie <desrt desrt ca>
Date:   Fri Nov 5 21:33:06 2010 -0400

    Add g_variant_lookup() and tests
    
    Convenience API for doing lookups in dictionaries where the key is a
    string or object path.

 docs/reference/glib/glib-sections.txt |    2 +
 glib/glib.symbols                     |    2 +
 glib/gvariant.c                       |  144 +++++++++++++++++++++++++++++++++
 glib/gvariant.h                       |    7 ++
 glib/tests/gvariant.c                 |   74 +++++++++++++++++
 5 files changed, 229 insertions(+), 0 deletions(-)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index d2f7422..dca0a98 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -3015,6 +3015,8 @@ g_variant_get_maybe
 g_variant_n_children
 g_variant_get_child_value
 g_variant_get_child
+g_variant_lookup_value
+g_variant_lookup
 g_variant_get_fixed_array
 
 <SUBSECTION>
diff --git a/glib/glib.symbols b/glib/glib.symbols
index 232e12a..73ec856 100644
--- a/glib/glib.symbols
+++ b/glib/glib.symbols
@@ -1880,6 +1880,8 @@ g_variant_get
 
 g_variant_builder_add
 g_variant_get_child
+g_variant_lookup_value
+g_variant_lookup
 g_variant_iter_next
 g_variant_iter_loop
 
diff --git a/glib/gvariant.c b/glib/gvariant.c
index e333597..5c8737f 100644
--- a/glib/gvariant.c
+++ b/glib/gvariant.c
@@ -899,6 +899,150 @@ g_variant_new_dict_entry (GVariant *key,
 }
 
 /**
+ * g_variant_lookup:
+ * @dictionary: a dictionary #GVariant
+ * @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 dictionary #GVariant.
+ *
+ * This function is a wrapper around g_variant_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.
+ *
+ * See g_variant_get() for information about @format_string.
+ *
+ * Returns: %TRUE if a value was unpacked
+ *
+ * Since: 2.28
+ */
+gboolean
+g_variant_lookup (GVariant    *dictionary,
+                  const gchar *key,
+                  const gchar *format_string,
+                  ...)
+{
+  GVariantType *type;
+  GVariant *value;
+
+  /* flatten */
+  g_variant_get_data (dictionary);
+
+  type = g_variant_format_string_scan_type (format_string, NULL, NULL);
+  value = g_variant_lookup_value (dictionary, key, type);
+  g_variant_type_free (type);
+
+  if (value)
+    {
+      va_list ap;
+
+      va_start (ap, format_string);
+      g_variant_get_va (value, format_string, NULL, &ap);
+      g_variant_unref (value);
+      va_end (ap);
+
+      return TRUE;
+    }
+
+  else
+    return FALSE;
+}
+
+/**
+ * g_variant_lookup:
+ * @dictionary: a dictionary #GVariant
+ * @key: the key to lookup in the dictionary
+ * @expected_type: a #GVariantType, or %NULL
+ *
+ * Looks up a value in a dictionary #GVariant.
+ *
+ * This function works with dictionaries of the type
+ * <literal>a{s*}</literal> (and equally well with type
+ * <literal>a{o*}</literal>, but we only further discuss the string case
+ * for sake of clarity).
+ *
+ * In the event that @dictionary has the type <literal>a{sv}</literal>,
+ * the @expected_type string specifies what type of value is expected to
+ * be inside of the variant.  If the value inside the variant has a
+ * different type then %NULL is returned.  In the event that @dictionary
+ * has a value type other than <literal>v</literal> then @expected_type
+ * must directly match the key type and it is used to unpack the value
+ * directly or an error occurs.
+ *
+ * In either case, if @key is not found in @dictionary, %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: the value of the dictionary key, or %NULL
+ *
+ * Since: 2.28
+ */
+GVariant *
+g_variant_lookup_value (GVariant           *dictionary,
+                        const gchar        *key,
+                        const GVariantType *expected_type)
+{
+  GVariantIter iter;
+  GVariant *entry;
+  GVariant *value;
+
+  g_return_val_if_fail (g_variant_is_of_type (dictionary,
+                                              G_VARIANT_TYPE ("a{s*}")) ||
+                        g_variant_is_of_type (dictionary,
+                                              G_VARIANT_TYPE ("a{o*}")),
+                        NULL);
+
+  g_variant_iter_init (&iter, dictionary);
+
+  while ((entry = g_variant_iter_next_value (&iter)))
+    {
+      GVariant *entry_key;
+      gboolean matches;
+
+      entry_key = g_variant_get_child_value (entry, 0);
+      matches = strcmp (g_variant_get_string (entry_key, NULL), key) == 0;
+      g_variant_unref (entry_key);
+
+      if (matches)
+        break;
+
+      g_variant_unref (entry);
+    }
+
+  if (entry == NULL)
+    return NULL;
+
+  value = g_variant_get_child_value (entry, 1);
+  g_variant_unref (entry);
+
+  if (g_variant_is_of_type (value, G_VARIANT_TYPE_VARIANT))
+    {
+      GVariant *tmp;
+
+      tmp = g_variant_get_variant (value);
+      g_variant_unref (value);
+
+      if (expected_type && !g_variant_is_of_type (tmp, expected_type))
+        {
+          g_variant_unref (tmp);
+          tmp = NULL;
+        }
+
+      value = tmp;
+    }
+
+  g_return_val_if_fail (expected_type == NULL || value == NULL ||
+                        g_variant_is_of_type (value, expected_type), NULL);
+
+  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
diff --git a/glib/gvariant.h b/glib/gvariant.h
index 528492b..9491c99 100644
--- a/glib/gvariant.h
+++ b/glib/gvariant.h
@@ -134,6 +134,13 @@ void                            g_variant_get_child                     (GVarian
                                                                          ...);
 GVariant *                      g_variant_get_child_value               (GVariant             *value,
                                                                          gsize                 index_);
+gboolean                        g_variant_lookup                        (GVariant             *value,
+                                                                         const gchar          *key,
+                                                                         const gchar          *format_string,
+                                                                         ...);
+GVariant *                      g_variant_lookup_value                  (GVariant             *value,
+                                                                         const gchar          *key,
+                                                                         const GVariantType   *type);
 gconstpointer                   g_variant_get_fixed_array               (GVariant             *value,
                                                                          gsize                *n_elements,
                                                                          gsize                 element_size);
diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
index 2c3c048..afbafd4 100644
--- a/glib/tests/gvariant.c
+++ b/glib/tests/gvariant.c
@@ -3897,6 +3897,78 @@ test_bytestring (void)
   g_variant_unref (untrusted_empty);
 }
 
+static void
+test_lookup_value (void)
+{
+  struct {
+    const gchar *dict, *key, *value;
+  } cases[] = {
+    { "@a{ss} {'x':  'y'}",   "x",  "'y'" },
+    { "@a{ss} {'x':  'y'}",   "y"         },
+    { "@a{os} {'/x': 'y'}",   "/x", "'y'" },
+    { "@a{os} {'/x': 'y'}",   "/y"        },
+    { "@a{sv} {'x':  <'y'>}", "x",  "'y'" },
+    { "@a{sv} {'x':  <5>}",   "x",  "5"   },
+    { "@a{sv} {'x':  <'y'>}", "y"         }
+  };
+  gint i;
+
+  for (i = 0; i < G_N_ELEMENTS (cases); i++)
+    {
+      GVariant *dictionary;
+      GVariant *value;
+      gchar *p;
+      
+      dictionary = g_variant_parse (NULL, cases[i].dict, NULL, NULL, NULL);
+      value = g_variant_lookup_value (dictionary, cases[i].key, NULL);
+      g_variant_unref (dictionary);
+
+      if (value == NULL && cases[i].value == NULL)
+        continue;
+
+      g_assert (value && cases[i].value);
+      p = g_variant_print (value, FALSE);
+      g_assert_cmpstr (cases[i].value, ==, p);
+      g_variant_unref (value);
+      g_free (p);
+    }
+}
+
+static void
+test_lookup (void)
+{
+  const gchar *str;
+  GVariant *dict;
+  gboolean ok;
+  gint num;
+
+  dict = g_variant_parse (NULL,
+                          "{'a': <5>, 'b': <'c'>}",
+                          NULL, NULL, NULL);
+
+  ok = g_variant_lookup (dict, "a", "i", &num);
+  g_assert (ok);
+  g_assert_cmpint (num, ==, 5);
+
+  ok = g_variant_lookup (dict, "a", "&s", &str);
+  g_assert (!ok);
+
+  ok = g_variant_lookup (dict, "q", "&s", &str);
+  g_assert (!ok);
+
+  ok = g_variant_lookup (dict, "b", "i", &num);
+  g_assert (!ok);
+
+  ok = g_variant_lookup (dict, "b", "&s", &str);
+  g_assert (ok);
+  g_assert_cmpstr (str, ==, "c");
+
+  ok = g_variant_lookup (dict, "q", "&s", &str);
+  g_assert (!ok);
+
+  g_variant_unref (dict);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -3937,6 +4009,8 @@ main (int argc, char **argv)
   g_test_add_func ("/gvariant/parse-positional", test_parse_positional);
   g_test_add_func ("/gvariant/floating", test_floating);
   g_test_add_func ("/gvariant/bytestring", test_bytestring);
+  g_test_add_func ("/gvariant/lookup-value", test_lookup_value);
+  g_test_add_func ("/gvariant/lookup", test_lookup);
 
   return g_test_run ();
 }



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