Re: Using GVariantBuilder with complex structures



Answering my own question in case anyone else can benefit from the information.

The code that I ended up with in order to encode the described
structure is the following:

void add_elem(GVariantBuilder *builder, struct tree_entry *elem)
{
        GVariantBuilder *new, *child_builder, *children;
        GVariant *new_dict, *new_array, *search;
        GList *item;

        /* This is the new dictionary that will be inserted into the
         * 'children' array of the parent. The parent could be a regular
         * element of the master list since both are using an array of
         * dictionaries for the "children". */
        new = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
        /* This is the dictionary that will contain the child information.
         * It only has one key - the id of the current element. */
        child_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
        /* Construct and add the 'search' type information tuple to the
         * current element's dictionary. */
        search = g_variant_new("(us)", elem->search.type, elem->search.term);
        g_variant_builder_add(child_builder, "{sv}", "search", search);
        /* Construct the 'children' array for the child element. This is
         * effectively the same as what we are doing for the master array. */
        children = g_variant_builder_new(G_VARIANT_TYPE("aa{sv}"));
        for (item = elem->children; item; item = item->next)
                add_elem(children, item->data);
        new_array = g_variant_builder_end(children);
        g_variant_builder_unref(children);
        /* Add the 'children' array to the current element dictionary. */
        g_variant_builder_add(child_builder, "{sv}", "children", new_array);
        new_dict = g_variant_builder_end(child_builder);
        g_variant_builder_unref(child_builder);
        /* Insert the new child into the top level dictionary describing the
         * current element. */
        g_variant_builder_add(new, "{sv}", elem->id, new_dict);
        /* Insert this element into the parent's 'children' array. */
        g_variant_builder_add(builder, "a{sv}", new);
}

        builder = g_variant_builder_new(G_VARIANT_TYPE("aa{sv}"));
        add_elem(builder, &root);
        dict = g_variant_builder_end(builder);


On Tue, Feb 26, 2019 at 7:49 AM Mitko Haralanov <voidtrance gmail com> wrote:

Does anyone have any pointers?

Thank you.

On Fri, Feb 22, 2019 at 11:58 AM Mitko Haralanov <voidtrance gmail com> wrote:

Hi,

I've been trying to figure out how to use GVariantBuilder to build a
complex structure with little success. The type of structure that I
would like to build is meant to partially encode a GtkTreeModel
structure. So, I thought that I could use GVariantBuilder to build a
structure of nested dictionaries.

The structure roughly follows this model:
[
  {
    "id": { "key1": (<int>, <string>, ...), "children": [
                          { "id2" : { "key1" : (<int>, <string>, ...),
"children" : []},
                          { "id3" : { "key1" : (<int>, <string>, ...),
"children" : [
                              { ... }
                              ]}
                          ]}},
  { "id" : ...}
]

This type of encoding can naturally be done with recursion and using
multiple GVariantBuilder's to add to the correct parent. However, I am
having difficulty with getting the formatting strings correct. As it
turns out, GLib insist on every dictionary entry being statically
typed meaning that the values for both "key1" and "children" has to be
of the same type. That seems to leave only 'v' as a valid format. So,
I have the following code (only important parts are pasted, not a
complete program):

struct tree_entry_search {
        uint32_t type;
        const char *term;
};

struct tree_entry {
        const char *id;
        struct tree_entry_search search;
        GList *children;
};

void add_elem(GVariantBuilder *builder, struct tree_entry *elem)
{
        GVariantBuilder *new, *child_builder;
        GVariant *new_dict, *new_array, *search;
        GList *item;

        new = g_variant_builder_new(G_VARIANT_TYPE_DICTIONARY);
        search = g_variant_new("(us)", elem->search.type, elem->search.term);
        g_variant_builder_add(new, "{sv}", "search", search);
        child_builder = g_variant_builder_new(G_VARIANT_TYPE("av"));
        for (item = elem->children; item; item = item->next)
                add_elem(child_builder, item->data);
        new_array = g_variant_builder_end(child_builder);
        g_variant_builder_unref(child_builder);
        g_variant_builder_add(new, "{sv}", "children", new_array);
        new_dict = g_variant_builder_end(new);
        g_variant_builder_unref(new);
        g_variant_builder_add(builder, "{sv}", elem->id, new_dict);
}

int main(void) {
        ...
        /* Build up a fake tree. */
        root.id = g_strdup("uid1");
        root.search.type = 1;
        root.search.term = g_strdup("term1");
        elem = g_new0(struct tree_entry, 1);
        elem->id = g_strdup("uid2");
        elem->search.type = 2;
        elem->search.term = g_strdup("term2");
        root.children = g_list_append(root.children, elem);
        elem = g_new0(struct tree_entry, 1);
        elem->id = g_strdup("uid3");
        elem->search.type = 2;
        elem->search.term = g_strdup("term3");
        root.children = g_list_append(root.children, elem);
        child = g_new0(struct tree_entry, 1);
        child->id = g_strdup("uid4");
        child->search.type = 3;
        child->search.term = g_strdup("term4");
        elem->children = g_list_append(elem->children, child);

        builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
        add_elem(builder, &root);
        dict = g_variant_builder_end(builder);
        dictionary = g_variant_print(dict, TRUE);
        printf("%s\n", dictionary);
        ...
}

But when I compile the above and run it, I get the following errors
when the tree is more than one level deep:

(process:3873): GLib-CRITICAL **: 11:44:03.826:
g_variant_builder_add_value: assertion '!GVSB(builder)->expected_type
|| g_variant_is_of_type (value, GVSB(builder)->expected_type)' failed

(process:3873): GLib-CRITICAL **: 11:44:03.827:
g_variant_builder_add_value: assertion '!GVSB(builder)->expected_type
|| g_variant_is_of_type (value, GVSB(builder)->expected_type)' failed

(process:3873): GLib-CRITICAL **: 11:44:03.827:
g_variant_builder_add_value: assertion '!GVSB(builder)->expected_type
|| g_variant_is_of_type (value, GVSB(builder)->expected_type)' failed

What's the correct way to specify the builder and variant types so I
can build the nested dictionary structure?

Thank you for the help.


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