[gnome-builder] plugins/clang: avoid g_variant_lookup()/g_variant_get_child()



commit 519f99f227d6aeb987c42fced95ef9b00cc241ba
Author: Christian Hergert <chergert redhat com>
Date:   Fri Sep 2 17:20:06 2022 -0700

    plugins/clang: avoid g_variant_lookup()/g_variant_get_child()
    
    This uses variant-schema-compiler to avoid all of the reference heavy
    operations with GVariant. Since our usage of GVariant is generally around
    one large allocation/GVariant, and then cracking into regions within that
    GVariant, we can often forgo all of the intermediate structures and ref
    counting associated. We just need to reference the primary variant.
    
    This drops the overhead of gtk_source_completion_queued_update_cb() due
    to ide_clang_completion_provider_refilter() from 2.81% to .23% which is
    safely in the "this is fine to do without a worker thread" territory.
    
    The result set that was tested, is for a source file containing GTK and a
    number of accessory platform libraries in scope.

 src/plugins/clang/ide-clang-completion-item.c |  104 +-
 src/plugins/clang/ide-clang-completion-item.h |   43 +-
 src/plugins/clang/ide-clang-proposals.c       |  126 +--
 src/plugins/clang/proposals.c                 | 1257 +++++++++++++++++++++++++
 src/plugins/clang/proposals.gv                |    6 +
 src/plugins/clang/proposals.h                 |   61 ++
 6 files changed, 1466 insertions(+), 131 deletions(-)
---
diff --git a/src/plugins/clang/ide-clang-completion-item.c b/src/plugins/clang/ide-clang-completion-item.c
index 31aaed836..027642773 100644
--- a/src/plugins/clang/ide-clang-completion-item.c
+++ b/src/plugins/clang/ide-clang-completion-item.c
@@ -27,24 +27,33 @@
 
 #include "ide-clang-completion-item.h"
 
+#if G_GNUC_CHECK_VERSION(4,0)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
+#endif
+#include "proposals.c"
+#if G_GNUC_CHECK_VERSION(4,0)
+# pragma GCC diagnostic pop
+#endif
+
 G_DEFINE_FINAL_TYPE_WITH_CODE (IdeClangCompletionItem, ide_clang_completion_item, G_TYPE_OBJECT,
                                G_IMPLEMENT_INTERFACE (GTK_SOURCE_TYPE_COMPLETION_PROPOSAL, NULL))
 
 static void
 ide_clang_completion_item_do_init (IdeClangCompletionItem *self)
 {
-  g_autoptr(GVariant) result = NULL;
-  g_autoptr(GVariant) chunks = NULL;
   g_autoptr(GString) markup = NULL;
   enum CXCursorKind kind;
-  GVariantIter iter;
-  GVariant *chunk;
+  ChunksRef chunks;
+  VariantRef v;
+  gsize n_chunks;
 
   g_assert (IDE_IS_CLANG_COMPLETION_ITEM (self));
+  g_assert (self->params == NULL);
 
-  result = ide_clang_completion_item_get_result (self);
-
-  if (!g_variant_lookup (result, "kind", "u", &kind))
+  if (proposal_lookup (self->ref, "kind", NULL, &v))
+    kind = variant_get_uint32 (v);
+  else
     kind = 0;
 
   switch ((int)kind)
@@ -142,22 +151,27 @@ ide_clang_completion_item_do_init (IdeClangCompletionItem *self)
       break;
     }
 
-  if (!(chunks = g_variant_lookup_value (result, "chunks", NULL)))
+  if (!proposal_lookup (self->ref, "chunks", NULL, &v))
     return;
 
+  chunks = chunks_from_variant (v);
+  n_chunks = chunks_get_length (chunks);
   markup = g_string_new (NULL);
 
-  g_variant_iter_init (&iter, chunks);
-
-  while ((chunk = g_variant_iter_next_value (&iter)))
+  for (gsize i = 0; i < n_chunks; i++)
     {
-      const gchar *text;
+      ChunkRef chunk = chunks_get_at (chunks, i);
+      const char *text;
       enum CXCompletionChunkKind ckind;
 
-      if (!g_variant_lookup (chunk, "kind", "u", &ckind))
+      if (chunk_lookup (chunk, "kind", NULL, &v))
+        ckind = variant_get_uint32 (v);
+      else
         ckind = 0;
 
-      if (!g_variant_lookup (chunk, "text", "&s", &text))
+      if (chunk_lookup (chunk, "text", NULL, &v))
+        text = variant_get_string (v);
+      else
         text = NULL;
 
       switch ((int)ckind)
@@ -202,8 +216,6 @@ ide_clang_completion_item_do_init (IdeClangCompletionItem *self)
         default:
           break;
         }
-
-      g_variant_unref (chunk);
     }
 
   self->params = g_string_free (g_steal_pointer (&markup), FALSE);
@@ -259,40 +271,44 @@ ide_clang_completion_item_create_snippet (IdeClangCompletionItem *self,
                                           IdeFileSettings        *file_settings)
 {
   g_autoptr(GtkSourceSnippet) snippet = NULL;
-  g_autoptr(GVariant) result = NULL;
-  g_autoptr(GVariant) chunks = NULL;
   g_autoptr(GSettings) settings = NULL;
-  GVariantIter iter;
-  GVariant *vchunk;
   IdeSpacesStyle spaces = 0;
   guint tab_stop = 0;
+  ChunksRef chunks;
+  VariantRef v;
+  gsize n_chunks;
 
   g_assert (IDE_IS_CLANG_COMPLETION_ITEM (self));
   g_assert (!file_settings || IDE_IS_FILE_SETTINGS (file_settings));
 
   settings = g_settings_new ("org.gnome.builder.clang");
 
-  result = ide_clang_completion_item_get_result (self);
   snippet = gtk_source_snippet_new (NULL, NULL);
 
   if (file_settings != NULL)
     spaces = ide_file_settings_get_spaces_style (file_settings);
 
-  if (!(chunks = g_variant_lookup_value (result, "chunks", NULL)))
+  if (!proposal_lookup (self->ref, "chunks", NULL, &v))
     return NULL;
 
-  g_variant_iter_init (&iter, chunks);
+  chunks = chunks_from_variant (v);
+  n_chunks = chunks_get_length (chunks);
 
-  while ((vchunk = g_variant_iter_next_value (&iter)))
+  for (gsize i = 0; i < n_chunks; i++)
     {
+      ChunkRef chunk_ref = chunks_get_at (chunks, i);
       enum CXCompletionChunkKind kind;
       GtkSourceSnippetChunk *chunk;
-      const gchar *text;
+      const char *text;
 
-      if (!g_variant_lookup (vchunk, "kind", "u", &kind))
+      if (chunk_lookup (chunk_ref, "kind", NULL, &v))
+        kind = variant_get_uint32 (v);
+      else
         kind = 0;
 
-      if (!g_variant_lookup (vchunk, "text", "&s", &text))
+      if (chunk_lookup (chunk_ref, "text", NULL, &v))
+        text = variant_get_string (v);
+      else
         text = NULL;
 
       if (!g_settings_get_boolean (settings, "complete-parens"))
@@ -397,8 +413,6 @@ ide_clang_completion_item_create_snippet (IdeClangCompletionItem *self,
         default:
           break;
         }
-
-      g_variant_unref (vchunk);
     }
 
   return g_steal_pointer (&snippet);
@@ -449,30 +463,15 @@ ide_clang_completion_item_get_snippet (IdeClangCompletionItem *self,
   return ide_clang_completion_item_create_snippet (self, file_settings);
 }
 
-/**
- * ide_clang_completion_item_new:
- * @variant: the toplevel variant of all results
- * @index: the index of the item
- * @keyword: pointer to folded form of the text
- *
- * The @keyword parameter is not copied, it is expected to be valid
- * string found within @variant (and therefore associated with its
- * life-cycle).
- */
 IdeClangCompletionItem *
-ide_clang_completion_item_new (GVariant    *variant,
-                               guint        index,
-                               const gchar *keyword)
+ide_clang_completion_item_new (GVariant    *results,
+                               ProposalRef  ref)
 {
   IdeClangCompletionItem *ret;
 
-  g_assert (variant != NULL);
-  g_assert (keyword != NULL);
-
   ret = g_object_new (IDE_TYPE_CLANG_COMPLETION_ITEM, NULL);
-  ret->results = g_variant_ref (variant);
-  ret->index = index;
-  ret->typed_text = keyword;
+  ret->results = g_variant_ref (results);
+  ret->ref = ref;
 
   ide_clang_completion_item_do_init (ret);
 
@@ -515,11 +514,12 @@ ide_clang_completion_item_display (IdeClangCompletionItem  *self,
 
     case GTK_SOURCE_COMPLETION_COLUMN_COMMENT:
       {
-        g_autoptr(GVariant) result = ide_clang_completion_item_get_result (self);
-        const char *comment;
+        VariantRef v;
 
-        if (g_variant_lookup (result, "command", "&s", &comment))
-          gtk_source_completion_cell_set_text (cell, comment);
+        if (proposal_lookup (self->ref, "comment", NULL, &v))
+          gtk_source_completion_cell_set_text (cell, variant_get_string (v));
+        else
+          gtk_source_completion_cell_set_text (cell, NULL);
 
         break;
       }
diff --git a/src/plugins/clang/ide-clang-completion-item.h b/src/plugins/clang/ide-clang-completion-item.h
index 6cc239e1c..60f305210 100644
--- a/src/plugins/clang/ide-clang-completion-item.h
+++ b/src/plugins/clang/ide-clang-completion-item.h
@@ -23,6 +23,8 @@
 #include <libide-code.h>
 #include <libide-sourceview.h>
 
+#include "proposals.h"
+
 G_BEGIN_DECLS
 
 #define IDE_TYPE_CLANG_COMPLETION_ITEM (ide_clang_completion_item_get_type())
@@ -31,37 +33,32 @@ G_DECLARE_FINAL_TYPE (IdeClangCompletionItem, ide_clang_completion_item, IDE, CL
 
 struct _IdeClangCompletionItem
 {
-  GObject           parent_instance;
+  GObject        parent_instance;
 
-  guint             index;
-  guint             priority;
-  IdeSymbolKind     kind;
+  /* Owned reference to ensure @ref validity */
+  GVariant      *results;
 
-  /* Owned references */
-  gchar            *params;
-  GVariant         *results;
+  /* Updated during search/filter */
+  guint          priority;
 
-  /* Unowned references */
-  const gchar      *keyword;
-  const gchar      *return_type;
-  const gchar      *icon_name;
-  const gchar      *typed_text;
-};
+  /* Extracted from @ref */
+  IdeSymbolKind  kind;
 
-static inline GVariant *
-ide_clang_completion_item_get_result (const IdeClangCompletionItem *self)
-{
-  g_autoptr(GVariant) child = g_variant_get_child_value (self->results, self->index);
+  /* Raw access into @results */
+  ProposalRef    ref;
 
-  if (g_variant_is_of_type (child, G_VARIANT_TYPE_VARIANT))
-    return g_variant_get_variant (child);
+  /* Cached on first generation */
+  char          *params;
 
-  return g_steal_pointer (&child);
-}
+  /* Unowned references */
+  const char    *keyword;
+  const char    *return_type;
+  const char    *icon_name;
+  const char    *typed_text;
+};
 
 IdeClangCompletionItem *ide_clang_completion_item_new         (GVariant                *results,
-                                                               guint                    index,
-                                                               const gchar             *keyword);
+                                                               ProposalRef              ref);
 GtkSourceSnippet       *ide_clang_completion_item_get_snippet (IdeClangCompletionItem  *self,
                                                                IdeFileSettings         *file_settings);
 void                    ide_clang_completion_item_display     (IdeClangCompletionItem  *self,
diff --git a/src/plugins/clang/ide-clang-proposals.c b/src/plugins/clang/ide-clang-proposals.c
index debc3abaa..703d754ce 100644
--- a/src/plugins/clang/ide-clang-proposals.c
+++ b/src/plugins/clang/ide-clang-proposals.c
@@ -33,6 +33,16 @@
 #include "ide-clang-completion-item.h"
 #include "ide-clang-proposals.h"
 
+#if G_GNUC_CHECK_VERSION(4,0)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
+#endif
+#include "proposals.h"
+#include "proposals.c"
+#if G_GNUC_CHECK_VERSION(4,0)
+# pragma GCC diagnostic pop
+#endif
+
 struct _IdeClangProposals
 {
   GObject parent_instance;
@@ -57,6 +67,7 @@ struct _IdeClangProposals
    * The most recent GVariant we received from the peer.
    */
   GVariant *results;
+  ResultsRef results_ref;
 
   /*
    * Instead of inflating GObjects for each of our matches, we instead keep
@@ -120,10 +131,11 @@ typedef struct
 
 typedef struct
 {
-  guint index;
-  guint priority : 24;
-  gint kind : 8;
-  const gchar *keyword;
+  ProposalRef ref;
+  const char *keyword;
+  guint priority;
+  int kind : 8;
+  int padding : 24;
 } Item;
 
 enum {
@@ -163,6 +175,7 @@ ide_clang_proposals_finalize (GObject *object)
   g_clear_pointer (&self->filter, g_free);
   g_clear_pointer (&self->match_indexes, g_array_unref);
   g_clear_pointer (&self->results, g_variant_unref);
+  self->results_ref = (ResultsRef) { NULL, 0 };
 
   G_OBJECT_CLASS (ide_clang_proposals_parent_class)->finalize (object);
 }
@@ -320,6 +333,7 @@ ide_clang_proposals_do_refilter (IdeClangProposals *self,
                                  gboolean           fast_refilter)
 {
   g_autofree gchar *folded = NULL;
+  VariantRef v;
   guint old_len = 0;
   guint n_items;
 
@@ -335,17 +349,9 @@ ide_clang_proposals_do_refilter (IdeClangProposals *self,
       for (guint i = old_len; i > 0; i--)
         {
           Item *item = &g_array_index (self->match_indexes, Item, i - 1);
-          const gchar *keyword = item->keyword;
           guint priority;
 
-          if G_UNLIKELY (keyword == NULL)
-            {
-              g_autoptr(GVariant) child = g_variant_get_child_value (self->results, item->index);
-              if (!g_variant_lookup (child, "keyword", "&s", &keyword))
-                keyword = NULL;
-            }
-
-          if (keyword == NULL || !gtk_source_completion_fuzzy_match (keyword, folded, &priority))
+          if (item->keyword == NULL || !gtk_source_completion_fuzzy_match (item->keyword, folded, &priority))
             g_array_remove_index_fast (self->match_indexes, i - 1);
           else
             item->priority = priority;
@@ -361,56 +367,58 @@ ide_clang_proposals_do_refilter (IdeClangProposals *self,
   if (old_len > 0)
     g_array_remove_range (self->match_indexes, 0, old_len);
 
-  n_items = self->results ? g_variant_n_children (self->results) : 0;
+  if (self->results != NULL)
+    n_items = (guint)results_get_length (self->results_ref);
+  else
+    n_items = 0;
 
   if (self->filter == NULL || self->filter[0] == 0)
     {
+      g_array_set_size (self->match_indexes, n_items);
+
       for (guint i = 0; i < n_items; i++)
         {
-          Item item = { i, i, 0 };
-          g_array_append_val (self->match_indexes, item);
+          Item *item = &g_array_index (self->match_indexes, Item, i);
+
+          item->ref = results_get_at (self->results_ref, i);
+          item->priority = i;
+          item->kind = 0;
+
+          if (proposal_lookup (item->ref, "keyword", NULL, &v))
+            item->keyword = variant_get_string (v);
+          else
+            item->keyword = "";
         }
     }
   else if (self->results != NULL)
     {
-      GVariantIter iter;
-      GVariant *value;
-      guint index = 0;
+      guint pos = 0;
 
-      g_variant_iter_init (&iter, self->results);
+      g_array_set_size (self->match_indexes, n_items);
 
-      while ((value = g_variant_iter_next_value (&iter)))
+      for (guint i = 0; i < n_items; i++)
         {
-          const gchar *typed_text;
-
-          /*
-           * We get a typed_text pointer into the larger buffer, which is
-           * kept around for the lifetime of @variant (so that we don't need
-           * to copy more strings.
-           */
-
-          if (g_variant_lookup (value, "keyword", "&s", &typed_text))
-            {
-              Item item = { index, 0, 0, typed_text };
-              guint priority;
+          Item *item = &g_array_index (self->match_indexes, Item, pos);
 
-              if (gtk_source_completion_fuzzy_match (typed_text, folded, &priority))
-                {
-                  enum CXCursorKind kind = 0;
+          item->ref = results_get_at (self->results_ref, i);
 
-                  g_variant_lookup (value, "kind", "u", &kind);
+          if (proposal_lookup (item->ref, "keyword", NULL, &v))
+            item->keyword = variant_get_string (v);
+          else
+            continue;
 
-                  item.priority = priority;
-                  item.kind = kind_priority (kind);
-                  g_array_append_val (self->match_indexes, item);
-                }
-            }
+          if (!gtk_source_completion_fuzzy_match (item->keyword, folded, &item->priority))
+            continue;
 
-          g_variant_unref (value);
+          if (proposal_lookup (item->ref, "kind", NULL, &v))
+            item->kind = kind_priority (variant_get_uint32 (v));
+          else
+            item->kind = 0;
 
-          index++;
+          pos++;
         }
 
+      g_array_set_size (self->match_indexes, pos);
       g_array_sort (self->match_indexes, sort_by_priority);
     }
 
@@ -427,11 +435,18 @@ ide_clang_proposals_flush (IdeClangProposals *self,
   g_assert (IDE_IS_CLANG_PROPOSALS (self));
   g_assert (results != NULL || error != NULL);
 
-  if (results != self->results)
-    {
-      g_clear_pointer (&self->results, g_variant_unref);
-      self->results = results ? g_variant_ref (results) : NULL;
-    }
+  if (results != NULL)
+    g_variant_ref_sink (results);
+  g_clear_pointer (&self->results, g_variant_unref);
+  self->results = results;
+
+  if (results != NULL)
+    self->results_ref = results_from_gvariant (results);
+  else
+    self->results_ref = (ResultsRef) { NULL, 0 };
+
+  if (self->match_indexes->len > 0)
+    g_array_remove_range (self->match_indexes, 0, self->match_indexes->len);
 
   ide_clang_proposals_do_refilter (self, FALSE);
 
@@ -764,15 +779,14 @@ ide_clang_proposals_get_item (GListModel *model,
                               guint       position)
 {
   IdeClangProposals *self = IDE_CLANG_PROPOSALS (model);
-  Item *item = &g_array_index (self->match_indexes, Item, position);
-  g_autoptr(GVariant) child = g_variant_get_child_value (self->results, item->index);
-  const gchar *keyword = NULL;
 
-  /* Very unlikely, but I've seen it once from libclang, so protect against it */
-  if (!g_variant_lookup (child, "keyword", "&s", &keyword))
-    keyword = "";
+  if G_LIKELY (position < self->match_indexes->len)
+    {
+      Item *item = &g_array_index (self->match_indexes, Item, position);
+      return ide_clang_completion_item_new (self->results, item->ref);
+    }
 
-  return ide_clang_completion_item_new (self->results, item->index, keyword);
+  return NULL;
 }
 
 static void
diff --git a/src/plugins/clang/proposals.c b/src/plugins/clang/proposals.c
new file mode 100644
index 000000000..bfe369090
--- /dev/null
+++ b/src/plugins/clang/proposals.c
@@ -0,0 +1,1257 @@
+/* Make sure generated code works with older glib versions without g_memdup2 */
+static inline gpointer
+_memdup2(gconstpointer mem, gsize byte_size)
+{
+#if GLIB_CHECK_VERSION(2, 68, 0)
+    return g_memdup2(mem, byte_size);
+#else
+    gpointer new_mem;
+
+    if (mem && byte_size != 0) {
+        new_mem = g_malloc(byte_size);
+        memcpy(new_mem, mem, byte_size);
+    } else {
+        new_mem = NULL;
+    }
+
+    return new_mem;
+#endif
+}
+
+#define REF_READ_FRAME_OFFSET(_v, _index) ref_read_unaligned_le ((guchar*)((_v).base) + (_v).size - 
(offset_size * ((_index) + 1)), offset_size)
+#define REF_ALIGN(_offset, _align_to) ((_offset + _align_to - 1) & ~(gsize)(_align_to - 1))
+
+/* Note: clz is undefinded for 0, so never call this size == 0 */
+G_GNUC_CONST static inline guint
+ref_get_offset_size (gsize size)
+{
+#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__) && defined(__LP64__)
+  /* Instead of using a lookup table we use nibbles in a lookup word */
+  guint32 v = (guint32)0x88884421;
+  return (v >> (((__builtin_clzl(size) ^ 63) / 8) * 4)) & 0xf;
+#else
+  if (size > G_MAXUINT16)
+    {
+      if (size > G_MAXUINT32)
+        return 8;
+      else
+        return 4;
+    }
+  else
+    {
+      if (size > G_MAXUINT8)
+         return 2;
+      else
+         return 1;
+    }
+#endif
+}
+
+G_GNUC_PURE static inline guint64
+ref_read_unaligned_le (guchar *bytes, guint   size)
+{
+  union
+  {
+    guchar bytes[8];
+    guint64 integer;
+  } tmpvalue;
+
+  tmpvalue.integer = 0;
+  /* we unroll the size checks here so that memcpy gets constant args */
+  if (size >= 4)
+    {
+      if (size == 8)
+        memcpy (&tmpvalue.bytes, bytes, 8);
+      else
+        memcpy (&tmpvalue.bytes, bytes, 4);
+    }
+  else
+    {
+      if (size == 2)
+        memcpy (&tmpvalue.bytes, bytes, 2);
+      else
+        memcpy (&tmpvalue.bytes, bytes, 1);
+    }
+
+  return GUINT64_FROM_LE (tmpvalue.integer);
+}
+
+static inline void
+__gstring_append_double (GString *string, double d)
+{
+  gchar buffer[100];
+  gint i;
+
+  g_ascii_dtostr (buffer, sizeof buffer, d);
+  for (i = 0; buffer[i]; i++)
+    if (buffer[i] == '.' || buffer[i] == 'e' ||
+        buffer[i] == 'n' || buffer[i] == 'N')
+      break;
+
+  /* if there is no '.' or 'e' in the float then add one */
+  if (buffer[i] == '\0')
+    {
+      buffer[i++] = '.';
+      buffer[i++] = '0';
+      buffer[i++] = '\0';
+    }
+   g_string_append (string, buffer);
+}
+
+static inline void
+__gstring_append_string (GString *string, const char *str)
+{
+  gunichar quote = strchr (str, '\'') ? '"' : '\'';
+
+  g_string_append_c (string, quote);
+  while (*str)
+    {
+      gunichar c = g_utf8_get_char (str);
+
+      if (c == quote || c == '\\')
+        g_string_append_c (string, '\\');
+
+      if (g_unichar_isprint (c))
+        g_string_append_unichar (string, c);
+      else
+        {
+          g_string_append_c (string, '\\');
+          if (c < 0x10000)
+            switch (c)
+              {
+              case '\a':
+                g_string_append_c (string, 'a');
+                break;
+
+              case '\b':
+                g_string_append_c (string, 'b');
+                break;
+
+              case '\f':
+                g_string_append_c (string, 'f');
+                break;
+
+              case '\n':
+                g_string_append_c (string, 'n');
+                break;
+
+              case '\r':
+                g_string_append_c (string, 'r');
+                break;
+
+              case '\t':
+                g_string_append_c (string, 't');
+                break;
+
+              case '\v':
+                g_string_append_c (string, 'v');
+                break;
+
+              default:
+                g_string_append_printf (string, "u%04x", c);
+                break;
+              }
+           else
+             g_string_append_printf (string, "U%08x", c);
+        }
+
+      str = g_utf8_next_char (str);
+    }
+
+  g_string_append_c (string, quote);
+}
+
+/************** VariantRef *******************/
+
+static inline Ref
+variant_get_child (VariantRef v, const GVariantType **out_type)
+{
+  if (v.size)
+    {
+      guchar *base = (guchar *)v.base;
+      gsize size = v.size - 1;
+
+      /* find '\0' character */
+      while (size > 0 && base[size] != 0)
+        size--;
+
+      /* ensure we didn't just hit the start of the string */
+      if (base[size] == 0)
+       {
+          const char *type_string = (char *) base + size + 1;
+          const char *limit = (char *)base + v.size;
+          const char *end;
+
+          if (g_variant_type_string_scan (type_string, limit, &end) && end == limit)
+            {
+              if (out_type)
+                *out_type = (const GVariantType *)type_string;
+              return (Ref) { v.base, size };
+            }
+       }
+    }
+  if (out_type)
+    *out_type = G_VARIANT_TYPE_UNIT;
+  return  (Ref) { "\0", 1 };
+}
+
+static inline const GVariantType *
+variant_get_type (VariantRef v)
+{
+  if (v.size)
+    {
+      guchar *base = (guchar *)v.base;
+      gsize size = v.size - 1;
+
+      /* find '\0' character */
+      while (size > 0 && base[size] != 0)
+        size--;
+
+      /* ensure we didn't just hit the start of the string */
+      if (base[size] == 0)
+       {
+          const char *type_string = (char *) base + size + 1;
+          const char *limit = (char *)base + v.size;
+          const char *end;
+
+          if (g_variant_type_string_scan (type_string, limit, &end) && end == limit)
+             return (const GVariantType *)type_string;
+       }
+    }
+  return  G_VARIANT_TYPE_UNIT;
+}
+
+static inline gboolean
+variant_is_type (VariantRef v, const GVariantType *type)
+{
+   return g_variant_type_equal (variant_get_type (v), type);
+}
+
+static inline VariantRef
+variant_from_gvariant (GVariant *v)
+{
+  g_assert (g_variant_type_equal (g_variant_get_type (v), G_VARIANT_TYPE_VARIANT));
+  return (VariantRef) { g_variant_get_data (v), g_variant_get_size (v) };
+}
+
+static inline VariantRef
+variant_from_bytes (GBytes *b)
+{
+  return (VariantRef) { g_bytes_get_data (b, NULL), g_bytes_get_size (b) };
+}
+
+static inline VariantRef
+variant_from_data (gconstpointer data, gsize size)
+{
+  return (VariantRef) { data, size };
+}
+
+static inline GVariant *
+variant_dup_to_gvariant (VariantRef v)
+{
+  guint8 *duped = _memdup2 (v.base, v.size);
+  return g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, duped, v.size, TRUE, g_free, duped);
+}
+
+static inline GVariant *
+variant_to_gvariant (VariantRef v,
+                              GDestroyNotify      notify,
+                              gpointer            user_data)
+{
+  return g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, v.base, v.size, TRUE, notify, user_data);
+}
+
+static inline GVariant *
+variant_to_owned_gvariant (VariantRef v,
+                                     GVariant *base)
+{
+  return variant_to_gvariant (v, (GDestroyNotify)g_variant_unref, g_variant_ref (base));
+}
+
+static inline GVariant *
+variant_peek_as_variant (VariantRef v)
+{
+  return g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, v.base, v.size, TRUE, NULL, NULL);
+}
+
+static inline VariantRef
+variant_from_variant (VariantRef v)
+{
+  const GVariantType  *type;
+  Ref child = variant_get_child (v, &type);
+  g_assert (g_variant_type_equal(type, G_VARIANT_TYPE_VARIANT));
+  return variant_from_data (child.base, child.size);
+}
+
+static inline GVariant *
+variant_dup_child_to_gvariant (VariantRef v)
+{
+  const GVariantType  *type;
+  Ref child = variant_get_child (v, &type);
+  guint8 *duped = _memdup2 (child.base, child.size);
+  return g_variant_new_from_data (type, duped, child.size, TRUE, g_free, duped);
+}
+
+static inline GVariant *
+variant_peek_child_as_variant (VariantRef v)
+{
+  const GVariantType  *type;
+  Ref child = variant_get_child (v, &type);
+  return g_variant_new_from_data (type, child.base, child.size, TRUE, NULL, NULL);
+}
+
+static inline GString *
+variant_format (VariantRef v, GString *s, gboolean type_annotate)
+{
+#ifdef DEEP_VARIANT_FORMAT
+  GVariant *gv = variant_peek_as_variant (v);
+  return g_variant_print_string (gv, s, TRUE);
+#else
+  const GVariantType  *type = variant_get_type (v);
+  g_string_append_printf (s, "<@%.*s>", (int)g_variant_type_get_string_length (type), (const char *)type);
+  return s;
+#endif
+}
+
+static inline char *
+variant_print (VariantRef v, gboolean type_annotate)
+{
+  GString *s = g_string_new ("");
+  variant_format (v, s, type_annotate);
+  return g_string_free (s, FALSE);
+}
+static inline gboolean
+variant_get_boolean (VariantRef v)
+{
+  return (gboolean)*((guint8 *)v.base);
+}
+static inline guint8
+variant_get_byte (VariantRef v)
+{
+  return (guint8)*((guint8 *)v.base);
+}
+static inline gint16
+variant_get_int16 (VariantRef v)
+{
+  return (gint16)*((gint16 *)v.base);
+}
+static inline guint16
+variant_get_uint16 (VariantRef v)
+{
+  return (guint16)*((guint16 *)v.base);
+}
+static inline gint32
+variant_get_int32 (VariantRef v)
+{
+  return (gint32)*((gint32 *)v.base);
+}
+static inline guint32
+variant_get_uint32 (VariantRef v)
+{
+  return (guint32)*((guint32 *)v.base);
+}
+static inline gint64
+variant_get_int64 (VariantRef v)
+{
+  return (gint64)*((gint64 *)v.base);
+}
+static inline guint64
+variant_get_uint64 (VariantRef v)
+{
+  return (guint64)*((guint64 *)v.base);
+}
+static inline guint32
+variant_get_handle (VariantRef v)
+{
+  return (guint32)*((guint32 *)v.base);
+}
+static inline double
+variant_get_double (VariantRef v)
+{
+  return (double)*((double *)v.base);
+}
+static inline const char *
+variant_get_string (VariantRef v)
+{
+  return (const char *)v.base;
+}
+static inline const char *
+variant_get_objectpath (VariantRef v)
+{
+  return (const char *)v.base;
+}
+static inline const char *
+variant_get_signature (VariantRef v)
+{
+  return (const char *)v.base;
+}
+
+/************** Proposal *******************/
+
+static inline ProposalRef
+proposal_from_gvariant (GVariant *v)
+{
+  g_assert (g_variant_type_equal (g_variant_get_type (v), PROPOSAL_TYPESTRING));
+  return (ProposalRef) { g_variant_get_data (v), g_variant_get_size (v) };
+}
+
+static inline ProposalRef
+proposal_from_bytes (GBytes *b)
+{
+  return (ProposalRef) { g_bytes_get_data (b, NULL), g_bytes_get_size (b) };
+}
+
+static inline ProposalRef
+proposal_from_data (gconstpointer data, gsize size)
+{
+  return (ProposalRef) { data, size };
+}
+
+static inline GVariant *
+proposal_dup_to_gvariant (ProposalRef v)
+{
+  guint8 *duped = _memdup2 (v.base, v.size);
+  return g_variant_new_from_data (PROPOSAL_TYPEFORMAT, duped, v.size, TRUE, g_free, duped);
+}
+
+static inline GVariant *
+proposal_to_gvariant (ProposalRef v,
+                             GDestroyNotify      notify,
+                             gpointer            user_data)
+{
+  return g_variant_new_from_data (PROPOSAL_TYPEFORMAT, v.base, v.size, TRUE, notify, user_data);
+}
+
+static inline GVariant *
+proposal_to_owned_gvariant (ProposalRef v, GVariant *base)
+{
+  return proposal_to_gvariant (v, (GDestroyNotify)g_variant_unref, g_variant_ref (base));
+}
+
+static inline GVariant *
+proposal_peek_as_gvariant (ProposalRef v)
+{
+  return g_variant_new_from_data (PROPOSAL_TYPEFORMAT, v.base, v.size, TRUE, NULL, NULL);
+}
+
+static inline ProposalRef
+proposal_from_variant (VariantRef v)
+{
+  const GVariantType  *type;
+  Ref child = variant_get_child (v, &type);
+  g_assert (g_variant_type_equal(type, PROPOSAL_TYPESTRING));
+  return proposal_from_data (child.base, child.size);
+}
+
+
+static inline gsize
+proposal_get_length (ProposalRef v)
+{
+  if (v.size == 0)
+    return 0;
+  guint offset_size = ref_get_offset_size (v.size);
+  gsize last_end = REF_READ_FRAME_OFFSET(v, 0);
+  gsize offsets_array_size;
+  if (last_end > v.size)
+    return 0;
+  offsets_array_size = v.size - last_end;
+  if (offsets_array_size % offset_size != 0)
+    return 0;
+  gsize length = offsets_array_size / offset_size;
+  return length;
+}
+
+static inline ProposalEntryRef
+proposal_get_at (ProposalRef v, gsize index)
+{
+  ProposalEntryRef res;
+  guint offset_size = ref_get_offset_size (v.size);
+  gsize last_end = REF_READ_FRAME_OFFSET(v, 0);
+  gsize len = (v.size - last_end) / offset_size;
+  gsize start = (index > 0) ? REF_ALIGN(REF_READ_FRAME_OFFSET(v, len - index), 8) : 0;
+  gsize end = REF_READ_FRAME_OFFSET(v, len - index - 1);
+  g_assert (start <= end);
+  g_assert (end <= last_end);
+  res = (ProposalEntryRef) { ((const char *)v.base) + start, end - start };
+  return res;
+}
+
+static inline const char *
+proposal_entry_get_key (ProposalEntryRef v)
+{
+  guint offset_size = ref_get_offset_size (v.size);
+  G_GNUC_UNUSED gsize end = REF_READ_FRAME_OFFSET(v, 0);
+  const char *base = (const char *)v.base;
+  g_assert (end < v.size);
+  g_assert (base[end-1] == 0);
+  return base;
+}
+
+static inline VariantRef
+proposal_entry_get_value (ProposalEntryRef v)
+{
+  guint offset_size = ref_get_offset_size (v.size);
+  gsize end = REF_READ_FRAME_OFFSET(v, 0);
+  gsize offset = REF_ALIGN(end, 8);
+  g_assert (offset <= v.size);
+  return (VariantRef) { (char *)v.base + offset, (v.size - offset_size) - offset };
+}
+
+static inline gboolean
+proposal_lookup (ProposalRef v, const char * key, gsize *index_out, VariantRef *out)
+{
+  const char * canonical_key = key;
+  if (v.size == 0)
+    return FALSE;
+  guint offset_size = ref_get_offset_size (v.size);
+  gsize last_end = REF_READ_FRAME_OFFSET(v, 0);
+  if (last_end > v.size)
+    return FALSE;
+  gsize offsets_array_size = v.size - last_end;
+  if (offsets_array_size % offset_size != 0)
+    return FALSE;
+  gsize len = offsets_array_size / offset_size;
+  gsize start = 0;
+  gsize i;
+
+  for (i = 0; i < len; i++)
+    {
+      gsize end = REF_READ_FRAME_OFFSET(v, len - i - 1);
+      ProposalEntryRef e = { ((const guchar *)v.base) + start, end - start };
+      g_assert (start <= end);
+      g_assert (end <= last_end);
+      const char * e_key = proposal_entry_get_key (e);
+      if (strcmp(canonical_key, e_key) == 0)
+        {
+           if (index_out)
+             *index_out = i;
+           if (out)
+             *out = proposal_entry_get_value (e);
+           return TRUE;
+        }
+      start = REF_ALIGN(end, 8);
+    }
+    return FALSE;
+}
+
+static inline gboolean
+proposal_lookup_boolean (ProposalRef v, const char * key, gboolean default_value)
+{
+   VariantRef value_v;
+
+  if (proposal_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 'b')
+    return variant_get_boolean (value_v);
+  return default_value;
+}
+
+static inline guint8
+proposal_lookup_byte (ProposalRef v, const char * key, guint8 default_value)
+{
+   VariantRef value_v;
+
+  if (proposal_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 'y')
+    return variant_get_byte (value_v);
+  return default_value;
+}
+
+static inline gint16
+proposal_lookup_int16 (ProposalRef v, const char * key, gint16 default_value)
+{
+   VariantRef value_v;
+
+  if (proposal_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 'n')
+    return variant_get_int16 (value_v);
+  return default_value;
+}
+
+static inline guint16
+proposal_lookup_uint16 (ProposalRef v, const char * key, guint16 default_value)
+{
+   VariantRef value_v;
+
+  if (proposal_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 'q')
+    return variant_get_uint16 (value_v);
+  return default_value;
+}
+
+static inline gint32
+proposal_lookup_int32 (ProposalRef v, const char * key, gint32 default_value)
+{
+   VariantRef value_v;
+
+  if (proposal_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 'i')
+    return variant_get_int32 (value_v);
+  return default_value;
+}
+
+static inline guint32
+proposal_lookup_uint32 (ProposalRef v, const char * key, guint32 default_value)
+{
+   VariantRef value_v;
+
+  if (proposal_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 'u')
+    return variant_get_uint32 (value_v);
+  return default_value;
+}
+
+static inline gint64
+proposal_lookup_int64 (ProposalRef v, const char * key, gint64 default_value)
+{
+   VariantRef value_v;
+
+  if (proposal_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 'x')
+    return variant_get_int64 (value_v);
+  return default_value;
+}
+
+static inline guint64
+proposal_lookup_uint64 (ProposalRef v, const char * key, guint64 default_value)
+{
+   VariantRef value_v;
+
+  if (proposal_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 't')
+    return variant_get_uint64 (value_v);
+  return default_value;
+}
+
+static inline guint32
+proposal_lookup_handle (ProposalRef v, const char * key, guint32 default_value)
+{
+   VariantRef value_v;
+
+  if (proposal_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 'h')
+    return variant_get_handle (value_v);
+  return default_value;
+}
+
+static inline double
+proposal_lookup_double (ProposalRef v, const char * key, double default_value)
+{
+   VariantRef value_v;
+
+  if (proposal_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 'd')
+    return variant_get_double (value_v);
+  return default_value;
+}
+
+static inline const char *
+proposal_lookup_string (ProposalRef v, const char * key, const char * default_value)
+{
+   VariantRef value_v;
+
+  if (proposal_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 's')
+    return variant_get_string (value_v);
+  return default_value;
+}
+
+static inline const char *
+proposal_lookup_objectpath (ProposalRef v, const char * key, const char * default_value)
+{
+   VariantRef value_v;
+
+  if (proposal_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 'o')
+    return variant_get_objectpath (value_v);
+  return default_value;
+}
+
+static inline const char *
+proposal_lookup_signature (ProposalRef v, const char * key, const char * default_value)
+{
+   VariantRef value_v;
+
+  if (proposal_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 'g')
+    return variant_get_signature (value_v);
+  return default_value;
+}
+
+static inline GString *
+proposal_format (ProposalRef v, GString *s, gboolean type_annotate)
+{
+  gsize len = proposal_get_length (v);
+  gsize i;
+
+  if (len == 0 && type_annotate)
+    g_string_append_printf (s, "@%s ", PROPOSAL_TYPESTRING);
+
+  g_string_append_c (s, '{');
+  for (i = 0; i < len; i++)
+    {
+      ProposalEntryRef entry = proposal_get_at (v, i);
+      if (i != 0)
+        g_string_append (s, ", ");
+      __gstring_append_string (s, proposal_entry_get_key (entry));
+      g_string_append (s, ": ");
+      variant_format (proposal_entry_get_value (entry), s, type_annotate);
+    }
+  g_string_append_c (s, '}');
+  return s;
+}
+
+static inline char *
+proposal_print (ProposalRef v, gboolean type_annotate)
+{
+  GString *s = g_string_new ("");
+  proposal_format (v, s, type_annotate);
+  return g_string_free (s, FALSE);
+}
+
+/************** Results *******************/
+
+static inline ResultsRef
+results_from_gvariant (GVariant *v)
+{
+  g_assert (g_variant_type_equal (g_variant_get_type (v), RESULTS_TYPESTRING));
+  return (ResultsRef) { g_variant_get_data (v), g_variant_get_size (v) };
+}
+
+static inline ResultsRef
+results_from_bytes (GBytes *b)
+{
+  return (ResultsRef) { g_bytes_get_data (b, NULL), g_bytes_get_size (b) };
+}
+
+static inline ResultsRef
+results_from_data (gconstpointer data, gsize size)
+{
+  return (ResultsRef) { data, size };
+}
+
+static inline GVariant *
+results_dup_to_gvariant (ResultsRef v)
+{
+  guint8 *duped = _memdup2 (v.base, v.size);
+  return g_variant_new_from_data (RESULTS_TYPEFORMAT, duped, v.size, TRUE, g_free, duped);
+}
+
+static inline GVariant *
+results_to_gvariant (ResultsRef v,
+                             GDestroyNotify      notify,
+                             gpointer            user_data)
+{
+  return g_variant_new_from_data (RESULTS_TYPEFORMAT, v.base, v.size, TRUE, notify, user_data);
+}
+
+static inline GVariant *
+results_to_owned_gvariant (ResultsRef v, GVariant *base)
+{
+  return results_to_gvariant (v, (GDestroyNotify)g_variant_unref, g_variant_ref (base));
+}
+
+static inline GVariant *
+results_peek_as_gvariant (ResultsRef v)
+{
+  return g_variant_new_from_data (RESULTS_TYPEFORMAT, v.base, v.size, TRUE, NULL, NULL);
+}
+
+static inline ResultsRef
+results_from_variant (VariantRef v)
+{
+  const GVariantType  *type;
+  Ref child = variant_get_child (v, &type);
+  g_assert (g_variant_type_equal(type, RESULTS_TYPESTRING));
+  return results_from_data (child.base, child.size);
+}
+
+static inline gsize
+results_get_length (ResultsRef v)
+{
+  if (v.size == 0)
+    return 0;
+  guint offset_size = ref_get_offset_size (v.size);
+  gsize last_end = REF_READ_FRAME_OFFSET(v, 0);
+  gsize offsets_array_size;
+  if (last_end > v.size)
+    return 0;
+  offsets_array_size = v.size - last_end;
+  if (offsets_array_size % offset_size != 0)
+    return 0;
+  gsize length  = offsets_array_size / offset_size;
+  return length;
+}
+
+static inline ProposalRef
+results_get_at (ResultsRef v, gsize index)
+{
+  guint offset_size = ref_get_offset_size (v.size);
+  gsize last_end = REF_READ_FRAME_OFFSET(v, 0);
+  gsize len = (v.size - last_end) / offset_size;
+  gsize start = (index > 0) ? REF_ALIGN(REF_READ_FRAME_OFFSET(v, len - index), 8) : 0;
+  G_GNUC_UNUSED gsize end = REF_READ_FRAME_OFFSET(v, len - index - 1);
+  g_assert (start <= end);
+  g_assert (end <= last_end);
+  return (ProposalRef) { ((const char *)v.base) + start, end - start };
+}
+
+static inline GString *
+results_format (ResultsRef v, GString *s, gboolean type_annotate)
+{
+  gsize len = results_get_length (v);
+  gsize i;
+  if (len == 0 && type_annotate)
+    g_string_append_printf (s, "@%s ", RESULTS_TYPESTRING);
+  g_string_append_c (s, '[');
+  for (i = 0; i < len; i++)
+    {
+      if (i != 0)
+        g_string_append (s, ", ");
+      proposal_format (results_get_at (v, i), s, ((i == 0) ? type_annotate : FALSE));
+    }
+  g_string_append_c (s, ']');
+  return s;
+}
+
+static inline char *
+results_print (ResultsRef v, gboolean type_annotate)
+{
+  GString *s = g_string_new ("");
+  results_format (v, s, type_annotate);
+  return g_string_free (s, FALSE);
+}
+
+/************** Chunk *******************/
+
+static inline ChunkRef
+chunk_from_gvariant (GVariant *v)
+{
+  g_assert (g_variant_type_equal (g_variant_get_type (v), CHUNK_TYPESTRING));
+  return (ChunkRef) { g_variant_get_data (v), g_variant_get_size (v) };
+}
+
+static inline ChunkRef
+chunk_from_bytes (GBytes *b)
+{
+  return (ChunkRef) { g_bytes_get_data (b, NULL), g_bytes_get_size (b) };
+}
+
+static inline ChunkRef
+chunk_from_data (gconstpointer data, gsize size)
+{
+  return (ChunkRef) { data, size };
+}
+
+static inline GVariant *
+chunk_dup_to_gvariant (ChunkRef v)
+{
+  guint8 *duped = _memdup2 (v.base, v.size);
+  return g_variant_new_from_data (CHUNK_TYPEFORMAT, duped, v.size, TRUE, g_free, duped);
+}
+
+static inline GVariant *
+chunk_to_gvariant (ChunkRef v,
+                             GDestroyNotify      notify,
+                             gpointer            user_data)
+{
+  return g_variant_new_from_data (CHUNK_TYPEFORMAT, v.base, v.size, TRUE, notify, user_data);
+}
+
+static inline GVariant *
+chunk_to_owned_gvariant (ChunkRef v, GVariant *base)
+{
+  return chunk_to_gvariant (v, (GDestroyNotify)g_variant_unref, g_variant_ref (base));
+}
+
+static inline GVariant *
+chunk_peek_as_gvariant (ChunkRef v)
+{
+  return g_variant_new_from_data (CHUNK_TYPEFORMAT, v.base, v.size, TRUE, NULL, NULL);
+}
+
+static inline ChunkRef
+chunk_from_variant (VariantRef v)
+{
+  const GVariantType  *type;
+  Ref child = variant_get_child (v, &type);
+  g_assert (g_variant_type_equal(type, CHUNK_TYPESTRING));
+  return chunk_from_data (child.base, child.size);
+}
+
+
+static inline gsize
+chunk_get_length (ChunkRef v)
+{
+  if (v.size == 0)
+    return 0;
+  guint offset_size = ref_get_offset_size (v.size);
+  gsize last_end = REF_READ_FRAME_OFFSET(v, 0);
+  gsize offsets_array_size;
+  if (last_end > v.size)
+    return 0;
+  offsets_array_size = v.size - last_end;
+  if (offsets_array_size % offset_size != 0)
+    return 0;
+  gsize length = offsets_array_size / offset_size;
+  return length;
+}
+
+static inline ChunkEntryRef
+chunk_get_at (ChunkRef v, gsize index)
+{
+  ChunkEntryRef res;
+  guint offset_size = ref_get_offset_size (v.size);
+  gsize last_end = REF_READ_FRAME_OFFSET(v, 0);
+  gsize len = (v.size - last_end) / offset_size;
+  gsize start = (index > 0) ? REF_ALIGN(REF_READ_FRAME_OFFSET(v, len - index), 8) : 0;
+  gsize end = REF_READ_FRAME_OFFSET(v, len - index - 1);
+  g_assert (start <= end);
+  g_assert (end <= last_end);
+  res = (ChunkEntryRef) { ((const char *)v.base) + start, end - start };
+  return res;
+}
+
+static inline const char *
+chunk_entry_get_key (ChunkEntryRef v)
+{
+  guint offset_size = ref_get_offset_size (v.size);
+  G_GNUC_UNUSED gsize end = REF_READ_FRAME_OFFSET(v, 0);
+  const char *base = (const char *)v.base;
+  g_assert (end < v.size);
+  g_assert (base[end-1] == 0);
+  return base;
+}
+
+static inline VariantRef
+chunk_entry_get_value (ChunkEntryRef v)
+{
+  guint offset_size = ref_get_offset_size (v.size);
+  gsize end = REF_READ_FRAME_OFFSET(v, 0);
+  gsize offset = REF_ALIGN(end, 8);
+  g_assert (offset <= v.size);
+  return (VariantRef) { (char *)v.base + offset, (v.size - offset_size) - offset };
+}
+
+static inline gboolean
+chunk_lookup (ChunkRef v, const char * key, gsize *index_out, VariantRef *out)
+{
+  const char * canonical_key = key;
+  if (v.size == 0)
+    return FALSE;
+  guint offset_size = ref_get_offset_size (v.size);
+  gsize last_end = REF_READ_FRAME_OFFSET(v, 0);
+  if (last_end > v.size)
+    return FALSE;
+  gsize offsets_array_size = v.size - last_end;
+  if (offsets_array_size % offset_size != 0)
+    return FALSE;
+  gsize len = offsets_array_size / offset_size;
+  gsize start = 0;
+  gsize i;
+
+  for (i = 0; i < len; i++)
+    {
+      gsize end = REF_READ_FRAME_OFFSET(v, len - i - 1);
+      ChunkEntryRef e = { ((const guchar *)v.base) + start, end - start };
+      g_assert (start <= end);
+      g_assert (end <= last_end);
+      const char * e_key = chunk_entry_get_key (e);
+      if (strcmp(canonical_key, e_key) == 0)
+        {
+           if (index_out)
+             *index_out = i;
+           if (out)
+             *out = chunk_entry_get_value (e);
+           return TRUE;
+        }
+      start = REF_ALIGN(end, 8);
+    }
+    return FALSE;
+}
+
+static inline gboolean
+chunk_lookup_boolean (ChunkRef v, const char * key, gboolean default_value)
+{
+   VariantRef value_v;
+
+  if (chunk_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 'b')
+    return variant_get_boolean (value_v);
+  return default_value;
+}
+
+static inline guint8
+chunk_lookup_byte (ChunkRef v, const char * key, guint8 default_value)
+{
+   VariantRef value_v;
+
+  if (chunk_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 'y')
+    return variant_get_byte (value_v);
+  return default_value;
+}
+
+static inline gint16
+chunk_lookup_int16 (ChunkRef v, const char * key, gint16 default_value)
+{
+   VariantRef value_v;
+
+  if (chunk_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 'n')
+    return variant_get_int16 (value_v);
+  return default_value;
+}
+
+static inline guint16
+chunk_lookup_uint16 (ChunkRef v, const char * key, guint16 default_value)
+{
+   VariantRef value_v;
+
+  if (chunk_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 'q')
+    return variant_get_uint16 (value_v);
+  return default_value;
+}
+
+static inline gint32
+chunk_lookup_int32 (ChunkRef v, const char * key, gint32 default_value)
+{
+   VariantRef value_v;
+
+  if (chunk_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 'i')
+    return variant_get_int32 (value_v);
+  return default_value;
+}
+
+static inline guint32
+chunk_lookup_uint32 (ChunkRef v, const char * key, guint32 default_value)
+{
+   VariantRef value_v;
+
+  if (chunk_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 'u')
+    return variant_get_uint32 (value_v);
+  return default_value;
+}
+
+static inline gint64
+chunk_lookup_int64 (ChunkRef v, const char * key, gint64 default_value)
+{
+   VariantRef value_v;
+
+  if (chunk_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 'x')
+    return variant_get_int64 (value_v);
+  return default_value;
+}
+
+static inline guint64
+chunk_lookup_uint64 (ChunkRef v, const char * key, guint64 default_value)
+{
+   VariantRef value_v;
+
+  if (chunk_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 't')
+    return variant_get_uint64 (value_v);
+  return default_value;
+}
+
+static inline guint32
+chunk_lookup_handle (ChunkRef v, const char * key, guint32 default_value)
+{
+   VariantRef value_v;
+
+  if (chunk_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 'h')
+    return variant_get_handle (value_v);
+  return default_value;
+}
+
+static inline double
+chunk_lookup_double (ChunkRef v, const char * key, double default_value)
+{
+   VariantRef value_v;
+
+  if (chunk_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 'd')
+    return variant_get_double (value_v);
+  return default_value;
+}
+
+static inline const char *
+chunk_lookup_string (ChunkRef v, const char * key, const char * default_value)
+{
+   VariantRef value_v;
+
+  if (chunk_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 's')
+    return variant_get_string (value_v);
+  return default_value;
+}
+
+static inline const char *
+chunk_lookup_objectpath (ChunkRef v, const char * key, const char * default_value)
+{
+   VariantRef value_v;
+
+  if (chunk_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 'o')
+    return variant_get_objectpath (value_v);
+  return default_value;
+}
+
+static inline const char *
+chunk_lookup_signature (ChunkRef v, const char * key, const char * default_value)
+{
+   VariantRef value_v;
+
+  if (chunk_lookup (v, key, NULL, &value_v) &&
+      *(const char *)variant_get_type (value_v) == 'g')
+    return variant_get_signature (value_v);
+  return default_value;
+}
+
+static inline GString *
+chunk_format (ChunkRef v, GString *s, gboolean type_annotate)
+{
+  gsize len = chunk_get_length (v);
+  gsize i;
+
+  if (len == 0 && type_annotate)
+    g_string_append_printf (s, "@%s ", CHUNK_TYPESTRING);
+
+  g_string_append_c (s, '{');
+  for (i = 0; i < len; i++)
+    {
+      ChunkEntryRef entry = chunk_get_at (v, i);
+      if (i != 0)
+        g_string_append (s, ", ");
+      __gstring_append_string (s, chunk_entry_get_key (entry));
+      g_string_append (s, ": ");
+      variant_format (chunk_entry_get_value (entry), s, type_annotate);
+    }
+  g_string_append_c (s, '}');
+  return s;
+}
+
+static inline char *
+chunk_print (ChunkRef v, gboolean type_annotate)
+{
+  GString *s = g_string_new ("");
+  chunk_format (v, s, type_annotate);
+  return g_string_free (s, FALSE);
+}
+
+/************** Chunks *******************/
+
+static inline ChunksRef
+chunks_from_gvariant (GVariant *v)
+{
+  g_assert (g_variant_type_equal (g_variant_get_type (v), CHUNKS_TYPESTRING));
+  return (ChunksRef) { g_variant_get_data (v), g_variant_get_size (v) };
+}
+
+static inline ChunksRef
+chunks_from_bytes (GBytes *b)
+{
+  return (ChunksRef) { g_bytes_get_data (b, NULL), g_bytes_get_size (b) };
+}
+
+static inline ChunksRef
+chunks_from_data (gconstpointer data, gsize size)
+{
+  return (ChunksRef) { data, size };
+}
+
+static inline GVariant *
+chunks_dup_to_gvariant (ChunksRef v)
+{
+  guint8 *duped = _memdup2 (v.base, v.size);
+  return g_variant_new_from_data (CHUNKS_TYPEFORMAT, duped, v.size, TRUE, g_free, duped);
+}
+
+static inline GVariant *
+chunks_to_gvariant (ChunksRef v,
+                             GDestroyNotify      notify,
+                             gpointer            user_data)
+{
+  return g_variant_new_from_data (CHUNKS_TYPEFORMAT, v.base, v.size, TRUE, notify, user_data);
+}
+
+static inline GVariant *
+chunks_to_owned_gvariant (ChunksRef v, GVariant *base)
+{
+  return chunks_to_gvariant (v, (GDestroyNotify)g_variant_unref, g_variant_ref (base));
+}
+
+static inline GVariant *
+chunks_peek_as_gvariant (ChunksRef v)
+{
+  return g_variant_new_from_data (CHUNKS_TYPEFORMAT, v.base, v.size, TRUE, NULL, NULL);
+}
+
+static inline ChunksRef
+chunks_from_variant (VariantRef v)
+{
+  const GVariantType  *type;
+  Ref child = variant_get_child (v, &type);
+  g_assert (g_variant_type_equal(type, CHUNKS_TYPESTRING));
+  return chunks_from_data (child.base, child.size);
+}
+
+static inline gsize
+chunks_get_length (ChunksRef v)
+{
+  if (v.size == 0)
+    return 0;
+  guint offset_size = ref_get_offset_size (v.size);
+  gsize last_end = REF_READ_FRAME_OFFSET(v, 0);
+  gsize offsets_array_size;
+  if (last_end > v.size)
+    return 0;
+  offsets_array_size = v.size - last_end;
+  if (offsets_array_size % offset_size != 0)
+    return 0;
+  gsize length  = offsets_array_size / offset_size;
+  return length;
+}
+
+static inline ChunkRef
+chunks_get_at (ChunksRef v, gsize index)
+{
+  guint offset_size = ref_get_offset_size (v.size);
+  gsize last_end = REF_READ_FRAME_OFFSET(v, 0);
+  gsize len = (v.size - last_end) / offset_size;
+  gsize start = (index > 0) ? REF_ALIGN(REF_READ_FRAME_OFFSET(v, len - index), 8) : 0;
+  G_GNUC_UNUSED gsize end = REF_READ_FRAME_OFFSET(v, len - index - 1);
+  g_assert (start <= end);
+  g_assert (end <= last_end);
+  return (ChunkRef) { ((const char *)v.base) + start, end - start };
+}
+
+static inline GString *
+chunks_format (ChunksRef v, GString *s, gboolean type_annotate)
+{
+  gsize len = chunks_get_length (v);
+  gsize i;
+  if (len == 0 && type_annotate)
+    g_string_append_printf (s, "@%s ", CHUNKS_TYPESTRING);
+  g_string_append_c (s, '[');
+  for (i = 0; i < len; i++)
+    {
+      if (i != 0)
+        g_string_append (s, ", ");
+      chunk_format (chunks_get_at (v, i), s, ((i == 0) ? type_annotate : FALSE));
+    }
+  g_string_append_c (s, ']');
+  return s;
+}
+
+static inline char *
+chunks_print (ChunksRef v, gboolean type_annotate)
+{
+  GString *s = g_string_new ("");
+  chunks_format (v, s, type_annotate);
+  return g_string_free (s, FALSE);
+}
diff --git a/src/plugins/clang/proposals.gv b/src/plugins/clang/proposals.gv
new file mode 100755
index 000000000..da70fde1c
--- /dev/null
+++ b/src/plugins/clang/proposals.gv
@@ -0,0 +1,6 @@
+// ../../../build-aux/variant-schema-compiler --outfile=proposals.c --outfile-header=proposals.h proposals.gv
+
+type Proposal [string]variant;
+type Results []Proposal;
+type Chunk [string]variant;
+type Chunks []Chunk;
diff --git a/src/plugins/clang/proposals.h b/src/plugins/clang/proposals.h
new file mode 100644
index 000000000..98be2247b
--- /dev/null
+++ b/src/plugins/clang/proposals.h
@@ -0,0 +1,61 @@
+#ifndef ____PROPOSALS_GV__H__
+#define ____PROPOSALS_GV__H__
+/* generated code for proposals.gv */
+#include <string.h>
+#include <glib.h>
+
+/********** Basic types *****************/
+
+typedef struct {
+ gconstpointer base;
+ gsize size;
+} Ref;
+
+typedef struct {
+ gconstpointer base;
+ gsize size;
+} VariantRef;
+
+#define PROPOSAL_TYPESTRING "a{sv}"
+#define PROPOSAL_TYPEFORMAT ((const GVariantType *) PROPOSAL_TYPESTRING)
+
+typedef struct {
+ gconstpointer base;
+ gsize size;
+} ProposalRef;
+
+typedef struct {
+ gconstpointer base;
+ gsize size;
+} ProposalEntryRef;
+
+#define RESULTS_TYPESTRING "aa{sv}"
+#define RESULTS_TYPEFORMAT ((const GVariantType *) RESULTS_TYPESTRING)
+
+typedef struct {
+ gconstpointer base;
+ gsize size;
+} ResultsRef;
+
+#define CHUNK_TYPESTRING "a{sv}"
+#define CHUNK_TYPEFORMAT ((const GVariantType *) CHUNK_TYPESTRING)
+
+typedef struct {
+ gconstpointer base;
+ gsize size;
+} ChunkRef;
+
+typedef struct {
+ gconstpointer base;
+ gsize size;
+} ChunkEntryRef;
+
+#define CHUNKS_TYPESTRING "aa{sv}"
+#define CHUNKS_TYPEFORMAT ((const GVariantType *) CHUNKS_TYPESTRING)
+
+typedef struct {
+ gconstpointer base;
+ gsize size;
+} ChunksRef;
+
+#endif


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