Re: glib2/gdbus - arrays and g_variant_get() quirks

Simon McVittie <smcv-ZGY8ohtN/[email protected]>
Newsgroups gmane.comp.freedesktop.dbus
Message-ID <[email protected]>
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
_______________________________________________
dbus mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dbus
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.