Add g_variant_lookup() and tests

Convenience API for doing lookups in dictionaries where the key is a
string or object path.
This commit is contained in:
Ryan Lortie 2010-11-05 21:33:06 -04:00
parent 57b4b7099f
commit 7fc6f8a159
5 changed files with 229 additions and 0 deletions

View File

@ -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>

View File

@ -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

View File

@ -898,6 +898,150 @@ g_variant_new_dict_entry (GVariant *key,
return value;
}
/**
* 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

View File

@ -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);

View File

@ -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 ();
}