Web lists-archives.com

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@xxxxxxxxx> wrote:
>
> Does anyone have any pointers?
>
> Thank you.
>
> On Fri, Feb 22, 2019 at 11:58 AM Mitko Haralanov <voidtrance@xxxxxxxxx> 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.
_______________________________________________
gtk-list mailing list
gtk-list@xxxxxxxxx
https://mail.gnome.org/mailman/listinfo/gtk-list