glib2/gdbus - arrays and g_variant_get() quirks
Simon McVittie
smcv at collabora.com
Tue Oct 10 15:53:17 UTC 2017
On Mon, 09 Oct 2017 at 23:35:38 +0200, David Sommerseth wrote:
> I'm getting quite puzzled when trying to extract an array using
> g_variant_get() ... and I don't quite follow why this happens.
This is a question about the GVariant API, not about D-Bus, so you
might get better results on a GLib/GNOME mailing list.
> Lets first look at this little and simple snippet:
>
> ---------------------------------------------------------------------
> GVariant *res = some_function_returning_int_array_via_dbus();
> printf("Format (res): %s\n", g_variant_get_type_string(res));
>
> GVariant *array = NULL;
> g_variant_get(res, "(*)", &array);
> printf("Format (array): %s\n", g_variant_get_type_string(array));
> ---------------------------------------------------------------------
>
> When running this little snippet the output is:
>
> Format (res): (au)
> Format (array): au
Right: if we use a pseudo-C++ notation, res is a
GVariant<tuple<array<uint32>>>, and array is a GVariant<array<uint32>>
representing the first (and only) element of that tuple.
> But I'm not really happy about the '(*)'. So I change that to say:
>
> g_variant_get(res, "(au)", &array);
You can't do this unless you change the type of 'array'. The format
string "(*)" expects a GVariant * argument, but the format string
"(au)" (or in fact "(aX)" for any X) expects a GVariantIter **.
See: https://developer.gnome.org/glib/stable/gvariant-format-strings.html
If you want both a GVariant * and type assertions, use "(@au)".
In general, g_variant_get() and g_variant_new() are designed for
convenience, rather than maximum possible consistency - the thought is
"if you have something that you know to be an array, clearly you are
going to want to iterate over it".
g_variant_get() with format string "(*)" or "(@au)" is effectively a
short-cut for calling g_variant_get_child_value() (and an assertion
about the type, in the case of "(@au)".
g_variant_get() with format string "(au)" is effectively a short-cut
for calling g_variant_get_child_value(), g_variant_iter_new() and
g_variant_iter_init().
> I do know that results from D-Bus are inside a "container", so the ()
> encapsulation is needed.
This is a true fact about the GDBus API for D-Bus, but it is not a
general fact about D-Bus. In generic D-Bus the hierarchy is:
message
header
message type
object path
interface
etc.
body, consisting of 0-many times:
parameter
In the GDBus API, the representation for a message body happens to be a
GVariant of type tuple, because that's a convenient way to encapsulate
0 or more GVariants.
In other D-Bus APIs (like libdbus, and I think also sd-bus) there is no
representation for a message body as separate from a message.
"Container" is a jargon term in the D-Bus and GVariant data-type models -
it means an array, a D-Bus struct or GVariant tuple (they're the same
thing), a variant, a dict-entry or a GVariant "maybe" type - so it's
best to avoid using that word with its generic meaning.
Regards,
smcv
More information about the dbus
mailing list