[glib/gvariant: 9/27] serialiser WIP



commit 7512d2fe7b0d264409acf315ba381d8d1f63bc74
Author: Ryan Lortie <desrt desrt ca>
Date:   Wed Feb 3 15:10:22 2010 -0500

    serialiser WIP

 glib/Makefile.am           |    2 -
 glib/gvariant-core.c       |   20 +-
 glib/gvariant-markup.c     |    1 +
 glib/gvariant-serialiser.c | 1282 +++++++++++++-------------------------------
 glib/gvariant-valist.c     |    1 +
 5 files changed, 390 insertions(+), 916 deletions(-)
---
diff --git a/glib/Makefile.am b/glib/Makefile.am
index 7699829..63e6704 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -182,8 +182,6 @@ libglib_2_0_la_SOURCES = 	\
 	gvarianttypeinfo.h	\
 	gvarianttypeinfo.c	\
 	gvarianttype.c		\
-	gvarianttypeinfo.h	\
-	gvarianttypeinfo.c	\
 	gvariant-util.c		\
 	gvariant-valist.c	\
 	gdebug.h		\
diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c
index d2e0fe1..561986f 100644
--- a/glib/gvariant-core.c
+++ b/glib/gvariant-core.c
@@ -239,7 +239,7 @@ g_variant_enable_serialised (GVariant *value)
   children = value->contents.tree.children;
   n_children = value->contents.tree.n_children;
 
-  gvs.type = value->type;
+  gvs.type_info = value->type;
   gvs.size = value->size;
   gvs.data = g_slice_alloc (gvs.size);
 
@@ -267,7 +267,7 @@ g_variant_enable_became_native (GVariant *value)
 {
   GVariantSerialised gvs;
 
-  gvs.type = value->type;
+  gvs.type_info = value->type;
   gvs.size = value->size;
   gvs.data = value->contents.serialised.data;
 
@@ -287,7 +287,7 @@ g_variant_enable_became_trusted (GVariant *value)
 {
   GVariantSerialised gvs;
 
-  gvs.type = value->type;
+  gvs.type_info = value->type;
   gvs.data = value->contents.serialised.data;
   gvs.size = value->size;
 
@@ -752,13 +752,13 @@ g_variant_fill_gvs (GVariantSerialised *serialised,
 
   g_variant_require_conditions (value, CONDITION_SIZE_VALID);
 
-  if (serialised->type == NULL)
-    serialised->type = value->type;
+  if (serialised->type_info == NULL)
+    serialised->type_info = value->type;
 
   if (serialised->size == 0)
     serialised->size = value->size;
 
-  g_assert (serialised->type == value->type);
+  g_assert (serialised->type_info == value->type);
   g_assert (serialised->size == value->size);
 
   if (serialised->data && serialised->size)
@@ -985,9 +985,9 @@ g_variant_get_child_value (GVariant *value,
       gvs = g_variant_get_gvs (value, &source);
       gvs = g_variant_serialised_get_child (gvs, index);
 
-      child = g_variant_alloc (gvs.type, CONDITION_SERIALISED |
-                                         CONDITION_SIZE_KNOWN);
-      child->type = gvs.type;
+      child = g_variant_alloc (gvs.type_info,
+                               CONDITION_SERIALISED | CONDITION_SIZE_KNOWN);
+      child->type = gvs.type_info;
       child->contents.serialised.source = source;
       child->contents.serialised.data = gvs.data;
       child->size = gvs.size;
@@ -1117,7 +1117,7 @@ g_variant_store (GVariant *value,
       GVariant **children;
       gsize n_children;
 
-      gvs.type = value->type;
+      gvs.type_info = value->type;
       gvs.data = data;
       gvs.size = value->size;
 
diff --git a/glib/gvariant-markup.c b/glib/gvariant-markup.c
index df0f27b..0abec4c 100644
--- a/glib/gvariant-markup.c
+++ b/glib/gvariant-markup.c
@@ -19,6 +19,7 @@
 
 #include <glib/gtestutils.h>
 #include <glib/gmessages.h>
+#include <glib/gstrfuncs.h>
 #include <glib/gvariant.h>
 
 #include <string.h>
diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c
index 796fc37..68e4480 100644
--- a/glib/gvariant-serialiser.c
+++ b/glib/gvariant-serialiser.c
@@ -53,7 +53,7 @@
  * value must be taken to be "Nothing".
  */
 
-static inline gsize
+static gsize
 gvs_fixed_sized_maybe_n_children (GVariantSerialised value)
 {
   gsize element_fixed_size;
@@ -64,7 +64,7 @@ gvs_fixed_sized_maybe_n_children (GVariantSerialised value)
   return (element_fixed_size == value.size) ? 1 : 0;
 }
 
-static inline GVariantSerialised
+static GVariantSerialised
 gvs_fixed_sized_maybe_get_child (GVariantSerialised value,
                                  gsize              index_)
 {
@@ -72,11 +72,12 @@ gvs_fixed_sized_maybe_get_child (GVariantSerialised value,
    * container, so just update the type.
    */
   value.type_info = g_variant_type_info_element (value.type_info);
+  g_variant_type_info_ref (value.type_info);
 
   return value;
 }
 
-static inline gsize
+static gsize
 gvs_fixed_sized_maybe_needed_size (GVariantTypeInfo         *type_info,
                                    GVariantSerialisedFiller  gvs_filler,
                                    const gpointer           *children,
@@ -95,7 +96,7 @@ gvs_fixed_sized_maybe_needed_size (GVariantTypeInfo         *type_info,
     return 0;
 }
 
-static inline void
+static void
 gvs_fixed_sized_maybe_serialise (GVariantSerialised        value,
                                  GVariantSerialisedFiller  gvs_filler,
                                  const gpointer           *children,
@@ -109,7 +110,7 @@ gvs_fixed_sized_maybe_serialise (GVariantSerialised        value,
     }
 }
 
-static inline gboolean
+static gboolean
 gvs_fixed_sized_maybe_is_normal (GVariantSerialised value)
 {
   if (value.size > 0)
@@ -123,7 +124,7 @@ gvs_fixed_sized_maybe_is_normal (GVariantSerialised value)
         return FALSE;
 
       /* proper element size: "Just".  recurse to the child. */
-      value = gvs_fixed_sized_maybe_get_child (value, 0);
+      value.type_info = g_variant_type_info_element (value.type_info);
 
       return g_variant_serialised_is_normal (value);
     }
@@ -145,18 +146,19 @@ gvs_fixed_sized_maybe_is_normal (GVariantSerialised value)
  * serialised ata of the child value.
  */
 
-static inline gsize
+static gsize
 gvs_variable_sized_maybe_n_children (GVariantSerialised value)
 {
   return (value.size > 0) ? 1 : 0;
 }
 
-static inline GVariantSerialised
+static GVariantSerialised
 gvs_variable_sized_maybe_get_child (GVariantSerialised value,
                                     gsize              index_)
 {
   /* remove the padding byte and update the type. */
   value.type_info = g_variant_type_info_element (value.type_info);
+  g_variant_type_info_ref (value.type_info);
   value.size--;
 
   /* if it's zero-sized then it may as well be NULL */
@@ -166,7 +168,7 @@ gvs_variable_sized_maybe_get_child (GVariantSerialised value,
   return value;
 }
 
-static inline gsize
+static gsize
 gvs_variable_sized_maybe_needed_size (GVariantTypeInfo         *type_info,
                                       GVariantSerialisedFiller  gvs_filler,
                                       const gpointer           *children,
@@ -184,7 +186,7 @@ gvs_variable_sized_maybe_needed_size (GVariantTypeInfo         *type_info,
     return 0;
 }
 
-static inline void
+static void
 gvs_variable_sized_maybe_serialise (GVariantSerialised        value,
                                     GVariantSerialisedFiller  gvs_filler,
                                     const gpointer           *children,
@@ -200,11 +202,19 @@ gvs_variable_sized_maybe_serialise (GVariantSerialised        value,
     }
 }
 
-static inline gboolean
+static gboolean
 gvs_variable_sized_maybe_is_normal (GVariantSerialised value)
 {
-         /* Nothing */        /* Just */
-  return (value.size == 0) || (value.data[value.size - 1] == '\0');
+  if (value.size == 0)
+    return TRUE;
+
+  if (value.data[value.size - 1] != '\0')
+    return FALSE;
+
+  value.type_info = g_variant_type_info_element (value.type_info);
+  value.size--;
+
+  return g_variant_serialised_is_normal (value);
 }
 
 /* Arrays {{{1
@@ -229,7 +239,7 @@ gvs_variable_sized_maybe_is_normal (GVariantSerialised value)
  * array must be taken as being empty.
  */
 
-static inline gsize
+static gsize
 gvs_fixed_sized_array_n_children (GVariantSerialised value)
 {
   gsize element_fixed_size;
@@ -243,7 +253,7 @@ gvs_fixed_sized_array_n_children (GVariantSerialised value)
   return 0;
 }
 
-static inline GVariantSerialised
+static GVariantSerialised
 gvs_fixed_sized_array_get_child (GVariantSerialised value,
                                  gsize              index_)
 {
@@ -252,11 +262,12 @@ gvs_fixed_sized_array_get_child (GVariantSerialised value,
   child.type_info = g_variant_type_info_element (value.type_info);
   g_variant_type_info_query (child.type_info, NULL, &child.size);
   child.data = value.data + (child.size * index_);
+  g_variant_type_info_ref (child.type_info);
 
   return child;
 }
 
-static inline gsize
+static gsize
 gvs_fixed_sized_array_needed_size (GVariantTypeInfo         *type_info,
                                    GVariantSerialisedFiller  gvs_filler,
                                    const gpointer           *children,
@@ -269,7 +280,7 @@ gvs_fixed_sized_array_needed_size (GVariantTypeInfo         *type_info,
   return element_fixed_size * n_children;
 }
 
-static inline void
+static void
 gvs_fixed_sized_array_serialise (GVariantSerialised        value,
                                  GVariantSerialisedFiller  gvs_filler,
                                  const gpointer           *children,
@@ -289,7 +300,7 @@ gvs_fixed_sized_array_serialise (GVariantSerialised        value,
     }
 }
 
-static inline gboolean
+static gboolean
 gvs_fixed_sized_array_is_normal (GVariantSerialised value)
 {
   GVariantSerialised child = {  };
@@ -388,136 +399,115 @@ gvs_write_unaligned_le (guchar *bytes,
   memcpy (bytes, &tmpvalue.bytes, size);
 }
 
-/* This is an optimisation.
- *
- * We could just as easily have a function that returns '1', '2', '4' or
- * '8' depending on how large the serialised data is and use that value,
- * but it would be slower.
- *
- * GCC will make many operations much faster if it knows that they are
- * being performed by a constant power of 2.  These include
- * multiplication, division and memcpy() -- all of which are used during
- * the deserialisation.
- *
- * By using this macro, we spell it out to GCC that within each case,
- * the offset size will be a constant, and a power of two.  It will
- * optimise accordingly.
- */
-#define OFFSET_SIZE_CASES(value_size, var_name, code) \
-  if (value_size > G_MAXUINT32) { const guint var_name = 8; code } \
-  if (value_size > G_MAXUINT16) { const guint var_name = 4; code } \
-  if (value_size > G_MAXUINT8)  { const guint var_name = 2; code } \
-  if (value_size > 0)           { const guint var_name = 1; code }
+static guint
+gvs_get_offset_size (gsize size)
+{
+  if (size > G_MAXUINT32)
+    return 8;
 
-static inline gsize
+  else if (size > G_MAXUINT16)
+    return 4;
+
+  else if (size > G_MAXUINT8)
+    return 2;
+
+  else if (size > 0)
+    return 1;
+
+  return 0;
+}
+
+static gsize
+gvs_calculate_total_size (gsize body_size,
+                          gsize offsets)
+{
+  if (body_size + 0 * offsets <= 0)
+    return body_size + 0 * offsets;
+
+  if (body_size + 1 * offsets <= G_MAXUINT8)
+    return body_size + 1 * offsets;
+
+  if (body_size + 2 * offsets <= G_MAXUINT16)
+    return body_size + 2 * offsets;
+
+  if (body_size + 4 * offsets <= G_MAXUINT32)
+    return body_size + 4 * offsets;
+
+  return body_size + 8 * offsets;
+}
+
+static gsize
 gvs_variable_sized_array_n_children (GVariantSerialised value)
 {
   gsize offsets_array_size;
+  gsize offset_size;
   gsize last_end;
 
-  OFFSET_SIZE_CASES (value.size, OFFSET_SIZE,
-    {
-      last_end = gvs_read_unaligned_le (value.data + value.size -
-                                        OFFSET_SIZE, OFFSET_SIZE);
+  if (value.size == 0)
+    return 0;
 
-      if (last_end > value.size)
-        return 0;
+  offset_size = gvs_get_offset_size (value.size);
 
-      offsets_array_size = value.size - last_end;
+  last_end = gvs_read_unaligned_le (value.data + value.size -
+                                    offset_size, offset_size);
 
-      if (offsets_array_size % OFFSET_SIZE)
-        return 0;
+  if (last_end > value.size)
+    return 0;
 
-      return offsets_array_size / OFFSET_SIZE;
-    }
-  )
+  offsets_array_size = value.size - last_end;
 
-  else
+  if (offsets_array_size % offset_size)
     return 0;
+
+  return offsets_array_size / offset_size;
 }
 
-static inline GVariantSerialised
+static GVariantSerialised
 gvs_variable_sized_array_get_child (GVariantSerialised value,
                                     gsize              index_)
 {
-  GVariantSerialised child;
-  guint alignment;
+  GVariantSerialised child = {  };
+  gsize offset_size;
+  gsize last_end;
   gsize start;
   gsize end;
 
-  OFFSET_SIZE_CASES (value.size, OFFSET_SIZE,
-    {
-      gsize last_end;
+  child.type_info = g_variant_type_info_element (value.type_info);
+  g_variant_type_info_ref (child.type_info);
 
-      last_end = gvs_read_unaligned_le (value.data + value.size -
-                                        OFFSET_SIZE, OFFSET_SIZE);
+  offset_size = gvs_get_offset_size (value.size);
 
-      if (index_ > 0)
-        start = gvs_read_unaligned_le (value.data + last_end +
-                                       (OFFSET_SIZE * (index_ - 1)),
-                                       OFFSET_SIZE);
-      else
-        start = 0;
+  last_end = gvs_read_unaligned_le (value.data + value.size -
+                                    offset_size, offset_size);
 
-      end = gvs_read_unaligned_le (value.data + last_end +
-                                   (OFFSET_SIZE * index_),
-                                   OFFSET_SIZE);
-    }
-  )
+  if (index_ > 0)
+    {
+      guint alignment;
+
+      start = gvs_read_unaligned_le (value.data + last_end +
+                                     (offset_size * (index_ - 1)),
+                                     offset_size);
 
+      g_variant_type_info_query (child.type_info, &alignment, NULL);
+      start += (-start) & alignment;
+    }
   else
-    g_assert_not_reached ();
+    start = 0;
 
-  child.type_info = g_variant_type_info_element (value.type_info);
-  g_variant_type_info_query (child.type_info, &alignment, NULL);
+  end = gvs_read_unaligned_le (value.data + last_end +
+                               (offset_size * index_),
+                               offset_size);
 
-  start += (-start) & alignment;
   if (start < end && end <= value.size)
     {
       child.data = value.data + start;
       child.size = end - start;
     }
-  else
-    {
-      child.data = NULL;
-      child.size = 0;
-    }
 
   return child;
 }
 
 static gsize
-gvs_determine_size (gsize body_size,
-                    gsize offsets)
-{
-  if (body_size + 0 * offsets <= 0)
-    return body_size + 0 * offsets;
-
-  if (body_size + 1 * offsets <= G_MAXUINT8)
-    return body_size + 1 * offsets;
-
-  if (body_size + 2 * offsets <= G_MAXUINT16)
-    return body_size + 2 * offsets;
-
-  if (body_size + 4 * offsets <= G_MAXUINT32)
-    return body_size + 4 * offsets;
-
-  return body_size + 8 * offsets;
-}
-
-static guint
-gvfs_get_offset_size (gsize size)
-{
-  OFFSET_SIZE_CASES (size, OFFSET_SIZE,
-    {
-      return OFFSET_SIZE;
-    }
-  )
-  else
-    return 0;
-}
-
-static inline gsize
 gvs_variable_sized_array_needed_size (GVariantTypeInfo         *type_info,
                                       GVariantSerialisedFiller  gvs_filler,
                                       const gpointer           *children,
@@ -538,47 +528,44 @@ gvs_variable_sized_array_needed_size (GVariantTypeInfo         *type_info,
       offset += child.size;
     }
 
-  return gvs_determine_size (offset, n_children);
+  return gvs_calculate_total_size (offset, n_children);
 }
 
-static inline void
+static void
 gvs_variable_sized_array_serialise (GVariantSerialised        value,
                                     GVariantSerialisedFiller  gvs_filler,
                                     const gpointer           *children,
                                     gsize                     n_children)
 {
+  guchar *offset_ptr;
+  gsize offset_size;
   guint alignment;
   gsize offset;
+  gsize i;
 
   g_variant_type_info_query (value.type_info, &alignment, NULL);
+  offset_size = gvs_get_offset_size (value.size);
   offset = 0;
 
-  OFFSET_SIZE_CASES (value.size, OFFSET_SIZE,
-    {
-      guchar *offset_ptr;
-      gsize i;
+  offset_ptr = value.data + value.size - offset_size * n_children;
 
-      offset_ptr = value.data + value.size - OFFSET_SIZE * n_children;
-
-      for (i = 0; i < n_children; i++)
-        {
-          GVariantSerialised child = {  };
+  for (i = 0; i < n_children; i++)
+    {
+      GVariantSerialised child = {  };
 
-          while (offset & alignment)
-            value.data[offset++] = '\0';
+      while (offset & alignment)
+        value.data[offset++] = '\0';
 
-          child.data = value.data + offset;
-          gvs_filler (&child, children[i]);
-          offset += child.size;
+      child.data = value.data + offset;
+      gvs_filler (&child, children[i]);
+      offset += child.size;
 
-          gvs_write_unaligned_le (offset_ptr, offset, OFFSET_SIZE);
-          offset_ptr += OFFSET_SIZE;
-        }
+      gvs_write_unaligned_le (offset_ptr, offset, offset_size);
+      offset_ptr += offset_size;
     }
-  )
 }
 
-static inline gboolean
+static gboolean
 gvs_variable_sized_array_is_normal (GVariantSerialised value)
 {
   GVariantSerialised child = {  };
@@ -594,7 +581,7 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value)
   if (value.size == 0)
     return TRUE;
 
-  offset_size = gvfs_get_offset_size (value.size);
+  offset_size = gvs_get_offset_size (value.size);
   last_end = gvs_read_unaligned_le (value.data + value.size -
                                     offset_size, offset_size);
 
@@ -643,291 +630,320 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value)
     }
 
   g_assert (offset == last_end);
+
+  return TRUE;
 }
 
-/* Tuples {{{1 */
+/* Tuples {{{1
+ *
+ * Since tuples can contain a mix of variable- and fixed-sized items,
+ * they are, in terms of serialisation, a hybrid of variable-sized and
+ * fixed-sized arrays.
+ *
+ * Offsets are only stored for variable-sized items.  Also, since the
+ * number of items in a tuple is known from its type, we are able to
+ * know exactly how many offsets to expect in the serialised data (and
+ * therefore how much space is taken up by the offset array).  This
+ * means that we know where the end of the serialised data for the last
+ * item is -- we can just subtract the size of the offset array from the
+ * total size of the tuple.  For this reason, the last item in the tuple
+ * doesn't need an offset stored.
+ *
+ * Most of the "heavy lifting" here is handled by the GVariantTypeInfo
+ * for the tuple.  See the notes in gvarianttypeinfo.h.
+ */
 
-static inline gsize
+static gsize
 gvs_tuple_n_children (GVariantSerialised value)
 {
   return g_variant_type_info_n_members (value.type_info);
 }
 
-static inline GVariantSerialised
+static GVariantSerialised
 gvs_tuple_get_child (GVariantSerialised value,
                      gsize              index_)
 {
   const GVariantMemberInfo *member_info;
-  gsize fixed_size;
+  GVariantSerialised child = {  };
+  gsize offset_size;
   gsize start, end;
 
-  member_info = g_variant_type_info_member (value.type_info, index_);
-  g_variant_type_info_query (member_info->type_info, NULL, &fixed_size);
+  member_info = g_variant_type_info_member_info (value.type_info, index_);
+  child.type_info = g_variant_type_info_ref (member_info->type_info);
+  offset_size = gvs_get_offset_size (value.size);
+
+  if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET)
+    {
+      if (offset_size * (member_info->i + 2) > value.size)
+        return child;
+    }
+  else
+    {
+      if (offset_size * (member_info->i + 1) > value.size)
+        return child;
+    }
 
-  /* XXX handle 'i' */
-  start = 0;
+  if (member_info->i + 1)
+    start = gvs_read_unaligned_le (value.data + value.size -
+                                   offset_size * (member_info->i + 1),
+                                   offset_size);
 
   start += member_info->a;
   start &= member_info->b;
   start |= member_info->c;
 
-  if (fixed_size)
-    child.size = fixed_size;
+  if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_LAST)
+    end = value.size - offset_size * (member_info->i + 1);
 
-  else
+  else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED)
+    {
+      gsize fixed_size;
+
+      g_variant_type_info_query (child.type_info, NULL, &fixed_size);
+      end = start + fixed_size;
+    }
+
+  else /* G_VARIANT_MEMEBER_ENDING_OFFSET */
+    end = gvs_read_unaligned_le (value.data + value.size -
+                                 offset_size * (member_info->i + 2),
+                                 offset_size);
+
+  if (start < end && end <= value.size)
     {
+      child.data = value.data + start;
+      child.size = end - start;
+    }
+
+  return child;
 }
 
-static inline gsize
+static gsize
 gvs_tuple_needed_size (GVariantTypeInfo         *type_info,
                        GVariantSerialisedFiller  gvs_filler,
                        const gpointer           *children,
                        gsize                     n_children)
 {
+  const GVariantMemberInfo *member_info = NULL;
+  gsize fixed_size;
+  gsize offset;
+  gsize i;
+
+  g_variant_type_info_query (type_info, NULL, &fixed_size);
+
+  if (fixed_size)
+    return fixed_size;
+
+  offset = 0;
+
+  for (i = 0; i < n_children; i++)
+    {
+      guint alignment;
+
+      member_info = g_variant_type_info_member_info (type_info, i);
+      g_variant_type_info_query (member_info->type_info,
+                                 &alignment, &fixed_size);
+      offset += (-offset) & alignment;
+
+      if (fixed_size)
+        offset += fixed_size;
+      else
+        {
+          GVariantSerialised child = {  };
+
+          gvs_filler (&child, children[i]);
+          offset += child.size;
+        }
+    }
+
+  return gvs_calculate_total_size (offset, member_info->i + 1);
 }
 
-static inline void
+static void
 gvs_tuple_serialise (GVariantSerialised        value,
                      GVariantSerialisedFiller  gvs_filler,
                      const gpointer           *children,
                      gsize                     n_children)
 {
+  gsize offset_size;
+  gsize offset;
+  gsize i;
+
+  offset_size = gvs_get_offset_size (value.size);
+  offset = 0;
+
+  for (i = 0; i < n_children; i++)
+    {
+      const GVariantMemberInfo *member_info;
+      GVariantSerialised child = {  };
+      guint alignment;
+
+      member_info = g_variant_type_info_member_info (value.type_info, i);
+      g_variant_type_info_query (member_info->type_info, &alignment, NULL);
+
+      while (offset & alignment)
+        value.data[offset++] = '\0';
+
+      child.data = value.data + offset;
+      gvs_filler (&child, children[i]);
+      offset += child.size;
+
+      if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET)
+        gvs_write_unaligned_le (value.data + value.size -
+                                offset_size * (member_info->i + 1),
+                                offset, offset_size);
+    }
+
+  while (offset < value.size)
+    value.data[offset++] = '\0';
 }
 
-static inline gboolean
+static gboolean
 gvs_tuple_is_normal (GVariantSerialised value)
 {
+  return TRUE;
 }
 
-tuple stuff
-
 /* Variants {{{1 */
 
 static inline gsize
-gvs_tuple_n_children (GVariantSerialised value)
+gvs_variant_n_children (GVariantSerialised value)
 {
+  return 1;
 }
 
 static inline GVariantSerialised
-gvs_tuple_get_child (GVariantSerialised value,
-                                 gsize              index_)
+gvs_variant_get_child (GVariantSerialised value,
+                       gsize              index_)
 {
-}
-
-static inline gsize
-gvs_tuple_needed_size (GVariantTypeInfo         *type_info,
-                                   GVariantSerialisedFiller  gvs_filler,
-                                   const gpointer           *children,
-                                   gsize                     n_children)
-{
-}
+  GVariantSerialised child = {  };
 
-static inline void
-gvs_tuple_serialise (GVariantSerialised        value,
-                                 GVariantSerialisedFiller  gvs_filler,
-                                 const gpointer           *children,
-                                 gsize                     n_children)
-{
-}
+  /* NOTE: not O(1) and impossible for it to be... */
+  if (value.size)
+    {
 
-static inline gboolean
-gvs_tuple_is_normal (GVariantSerialised value)
-{
-}
+      /* find '\0' character */
+      for (child.size = value.size - 1; child.size; child.size--)
+        if (value.data[child.size] == '\0')
+          break;
 
+      /* ensure we didn't just hit the start of the string */
+      if (value.data[child.size] == '\0')
+        {
+          const gchar *type_string = (gchar *) &value.data[child.size + 1];
+          const gchar *limit = (gchar *) &value.data[value.size];
+          const gchar *end;
 
-variants
+          if (g_variant_type_string_scan (type_string, limit, &end) &&
+              end == limit)
+            {
+              const GVariantType *type = (GVariantType *) type_string;
 
-/* Unsorted {{{1 */
+              if (g_variant_type_is_definite (type))
+                {
+                  gsize fixed_size;
 
+                  child.type_info = g_variant_type_info_get (type);
 
-static gsize
-g_variant_serialiser_determine_size (gsize    content_end,
-                                     gsize    offsets,
-                                     gboolean non_zero)
-{
-  if (!non_zero && content_end == 0)
-    return 0;
+                  g_variant_type_info_query (child.type_info,
+                                             NULL, &fixed_size);
 
-  if (content_end + offsets <= G_MAXUINT8)
-    return content_end + offsets;
+                  if (!fixed_size || fixed_size == child.size)
+                    return child;
 
-  if (content_end + offsets * 2 <= G_MAXUINT16)
-    return content_end + offsets * 2;
+                  g_variant_type_info_unref (child.type_info);
+                }
+            }
+        }
+    }
 
-  if (content_end + offsets * 4 <= G_MAXUINT32)
-    return content_end + offsets * 4;
+  child.type_info = g_variant_type_info_get (G_VARIANT_TYPE_UNIT);
+  child.data = NULL;
+  child.size = 1;
 
-  return content_end + offsets * 8;
+  return child;
 }
 
-static guint
-g_variant_serialiser_offset_size (GVariantSerialised container)
+static inline gsize
+gvs_variant_needed_size (GVariantTypeInfo         *type_info,
+                         GVariantSerialisedFiller  gvs_filler,
+                         const gpointer           *children,
+                         gsize                     n_children)
 {
-  if (container.size == 0)
-    return 0;
-
-  if (container.size <= G_MAXUINT8)
-    return 1;
-
-  if (container.size <= G_MAXUINT16)
-    return 2;
+  GVariantSerialised child = {  };
+  const gchar *type_string;
 
-  if (container.size <= G_MAXUINT32)
-    return 4;
+  gvs_filler (&child, children[0]);
+  type_string = g_variant_type_info_get_type_string (child.type_info);
 
-  return 8;
+  return child.size + 1 + strlen (type_string);
 }
 
-#define do_case(_ofs_size, body) \
-  {                                                             \
-    guint offset_size = (_ofs_size);                            \
-    body                                                        \
-  }
-
-#define check_case(max, _ofs_size, body) \
-  if (container.size <= max)                                    \
-    do_case (_ofs_size, body)
-
-#define check_cases(init_val, zero_case, else_case, use_val) \
-  G_STMT_START {                                                \
-    guchar *bytes;                                              \
-    union                                                       \
-    {                                                           \
-      guchar bytes[GLIB_SIZEOF_SIZE_T];                         \
-      gsize integer;                                            \
-    } tmpvalue;                                                 \
-                                                                \
-    bytes = container.data + container.size;                    \
-    tmpvalue.integer = init_val;                                \
-                                                                \
-    if (container.size == 0) { zero_case }                      \
-    else check_case (G_MAXUINT8, 1, else_case)                  \
-    else check_case (G_MAXUINT16, 2, else_case)                 \
-    else check_case (G_MAXUINT32, 4, else_case)                 \
-    else do_case (8, else_case)                                 \
-    use_val;                                                    \
-  } G_STMT_END
-
-static gboolean
-g_variant_serialiser_dereference (GVariantSerialised container,
-                                  gsize              index,
-                                  gsize             *result)
+static inline void
+gvs_variant_serialise (GVariantSerialised        value,
+                       GVariantSerialisedFiller  gvs_filler,
+                       const gpointer           *children,
+                       gsize                     n_children)
 {
-  check_cases (0,,
-               {
-                 if (index >= container.size / offset_size)
-                   return FALSE;
+  GVariantSerialised child = {  };
+  const gchar *type_string;
 
-                 bytes -= (index + 1) * offset_size;
-                 memcpy (tmpvalue.bytes, bytes, offset_size);
-               },
-               *result = GSIZE_TO_LE (tmpvalue.integer));
+  child.data = value.data;
 
-  return G_LIKELY (*result <= container.size);
+  gvs_filler (&child, children[0]);
+  type_string = g_variant_type_info_get_type_string (child.type_info);
+  value.data[child.size] = '\0';
+  memcpy (value.data + child.size + 1, type_string, strlen (type_string));
 }
 
-static gboolean
-g_variant_serialiser_array_length (GVariantSerialised  container,
-                                   gsize              *length_ret)
+static inline gboolean
+gvs_variant_is_normal (GVariantSerialised value)
 {
-  gsize divider;
-
-  check_cases (0, g_assert_not_reached ();,
-               {
-                 bytes -= offset_size;
-                 memcpy (tmpvalue.bytes, bytes, offset_size);
-                 divider = offset_size;
-               },
-               {
-                 gsize length;
-
-                 length = GSIZE_TO_LE (tmpvalue.integer);
-
-                 if (length > container.size)
-                   return FALSE;
-
-                 length = container.size - length;
-                 if G_UNLIKELY (length % divider != 0)
-                   return FALSE;
+  GVariantSerialised child;
+  gboolean normal;
 
-                 *length_ret = length / divider;
-               });
+  child = gvs_variant_get_child (value, 0);
+  normal = g_variant_serialised_is_normal (child);
+  g_variant_type_info_unref (child.type_info);
 
-  return TRUE;
+  return normal;
 }
 
+/* Dispatch {{{1 */
+#define DISPATCH_FIXED(type_info, call) \
+  {                                                     \
+    gsize fixed_size;                                   \
+                                                        \
+    g_variant_type_info_query_element (type_info, NULL, \
+                                       &fixed_size);    \
+                                                        \
+    if (fixed_size)                                     \
+      return gvs_fixed_sized_ ## call;                  \
+    else                                                \
+      return gvs_variable_sized_ ## call;               \
+  }
+
+#define DISPATCH_CASES(type_info, call) \
+  switch (g_variant_type_info_get_type_char (type_info))\
+    {                                                   \
+      case G_VARIANT_TYPE_INFO_CHAR_MAYBE:              \
+        DISPATCH_FIXED (type_info, maybe_ ## call)      \
+                                                        \
+      case G_VARIANT_TYPE_INFO_CHAR_ARRAY:              \
+        DISPATCH_FIXED (type_info, array_ ## call)      \
+                                                        \
+      case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY:         \
+      case G_VARIANT_TYPE_INFO_CHAR_TUPLE:              \
+        return gvs_tuple_ ## call;                      \
+                                                        \
+      case G_VARIANT_TYPE_INFO_CHAR_VARIANT:            \
+        return gvs_variant_ ## call;                    \
+    }
 
 gsize
-g_variant_serialised_n_children (GVariantSerialised container)
+g_variant_serialised_n_children (GVariantSerialised serialised)
 {
-  g_variant_serialised_assert_invariant (container);
-
-  switch (g_variant_type_info_get_type_char (container.type))
-    {
-    case G_VARIANT_TYPE_INFO_CHAR_VARIANT:
-      return 1;
-
-    case G_VARIANT_TYPE_INFO_CHAR_TUPLE:
-      return g_variant_type_info_n_members (container.type);
-
-    case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY:
-      return 2;
-
-    case G_VARIANT_TYPE_INFO_CHAR_MAYBE:
-      {
-        gsize size;
-
-        if (container.size == 0)
-          return 0;
-
-        g_variant_type_info_query_element (container.type, NULL, &size);
-
-        if (size && size != container.size)
-          break;
-
-        return 1;
-      }
-
-    case G_VARIANT_TYPE_INFO_CHAR_ARRAY:
-      {
-        gsize fixed_size;
-
-        /* an array with a length of zero always has a size of zero.
-         * an array with a size of zero always has a length of zero.
-         */
-        if (container.size == 0)
-          return 0;
-
-        g_variant_type_info_query_element (container.type, NULL, &fixed_size);
-
-        if (!fixed_size)
-          /* case where array contains variable-sized elements
-           * or fixed-size elements of size 0 (treated as variable)
-           */
-          {
-            gsize length;
-
-            if G_UNLIKELY (!g_variant_serialiser_array_length (container, &length))
-              break;
-
-            return length;
-         }
-        else
-          /* case where array contains fixed-sized elements */
-          {
-            if G_UNLIKELY (container.size % fixed_size > 0)
-              break;
-
-            return container.size / fixed_size;
-          }
-      }
-
-    default:
-      g_assert_not_reached ();
-  }
-
-  return 0;
+  DISPATCH_CASES (serialised.type_info, n_children (serialised))
+  g_assert_not_reached ();
 }
 
 /*
@@ -947,587 +963,40 @@ g_variant_serialised_n_children (GVariantSerialised container)
  * This function will never return .size == 0 and .data != NULL.
  */
 GVariantSerialised
-g_variant_serialised_get_child (GVariantSerialised container,
-                                gsize              index)
+g_variant_serialised_get_child (GVariantSerialised serialised,
+                                gsize              index_)
 {
-  g_variant_serialised_assert_invariant (container);
-
-  switch (g_variant_type_info_get_type_char (container.type))
-  {
-    case G_VARIANT_TYPE_INFO_CHAR_VARIANT:
-      {
-        GVariantSerialised child = { NULL, container.data, container.size };
-
-        if G_UNLIKELY (index > 0)
-          break;
-
-        /* find '\0' character */
-        while (child.size && container.data[--child.size]);
-
-        /* the loop can finish for two reasons.
-         * 1) we found a '\0'.   ((good.))
-         * 2) we hit the start.  ((only good if there's a '\0' there))
-         */
-        if (container.size && container.data[child.size] == '\0')
-          {
-            gchar *str = (gchar *) container.data + child.size + 1;
-
-            /* in the case that we're accessing a shared memory buffer,
-             * someone could change the  string under us and cause us
-             * to access out-of-bounds memory.
-             *
-             * if we carefully make our own copy then we avoid that.
-             */
-            str = g_strndup (str, container.size - child.size - 1);
-            if (g_variant_type_string_is_valid (str))
-              {
-                const GVariantType *type = G_VARIANT_TYPE (str);
-
-                if (g_variant_type_is_definite (type))
-                  child.type = g_variant_type_info_get (type);
-              }
-
-            g_free (str);
-          }
-
-        if G_UNLIKELY (child.type == NULL)
-          {
-            child.type = g_variant_type_info_get (G_VARIANT_TYPE_UNIT);
-            child.data = NULL;
-            child.size = 1;
-
-            return child;
-          }
-
-        {
-          gsize fixed_size;
-
-          g_variant_type_info_query (child.type, NULL, &fixed_size);
-
-          if G_UNLIKELY (fixed_size && child.size != fixed_size)
-            {
-              child.size = fixed_size;
-              child.data = NULL;
-            }
-        }
-
-        if (child.size == 0)
-          child.data = NULL;
-
-        return child;
-      }
-
-    case G_VARIANT_TYPE_INFO_CHAR_MAYBE:
-      {
-        GVariantSerialised child;
-        gsize fixed_size;
-
-        child.type = g_variant_type_info_element (container.type);
-        g_variant_type_info_ref (child.type);
-        child.data = container.data;
-
-        if G_UNLIKELY (container.size == 0 || index > 0)
-          break;
-
-        g_variant_type_info_query (child.type, NULL, &fixed_size);
-
-        if (fixed_size)
-          {
-            /* if this doesn't match then we are considered
-             * 'Nothing', so there is no child to get...
-             */
-            if G_UNLIKELY (container.size != fixed_size)
-              break;
-
-            /* fixed size: child fills entire container */
-            child.size = container.size;
-          }
-        else
-          /* variable size: remove trailing '\0' marker */
-          child.size = container.size - 1;
-
-        return child;
-      }
-
-    case G_VARIANT_TYPE_INFO_CHAR_ARRAY:
-      {
-        GVariantSerialised child;
-        gsize fixed_size;
-        guint alignment;
-
-        child.type = g_variant_type_info_element (container.type);
-        g_variant_type_info_ref (child.type);
-
-        g_variant_type_info_query (child.type, &alignment, &fixed_size);
-
-        if (fixed_size)
-          {
-            if G_UNLIKELY (container.size % fixed_size != 0 ||
-                           fixed_size * (index + 1) > container.size)
-              break;
-
-            child.data = container.data + fixed_size * index;
-            child.size = fixed_size;
-
-            return child;
-          }
-
-        else
-          {
-            gsize boundary = 0, start = 0, end = 0;
-            guint offset_size;
-
-            offset_size = g_variant_serialiser_offset_size (container);
-            memcpy (&boundary,
-                    container.data + container.size - offset_size,
-                    offset_size);
-            boundary = GSIZE_FROM_LE (boundary);
-
-            if G_UNLIKELY (boundary > container.size ||
-                          (container.size - boundary) % offset_size ||
-                          boundary + index * offset_size >= container.size)
-              break;
-
-            if (index)
-              {
-                memcpy (&start,
-                        container.data + boundary + (index - 1) * offset_size,
-                        offset_size);
-                start = GSIZE_FROM_LE (start);
-              }
-
-            memcpy (&end,
-                    container.data + boundary + index * offset_size,
-                    offset_size);
-            end = GSIZE_FROM_LE (end);
-
-            start += (-start) & alignment;
-
-            if (start < end && end <= container.size)
-              {
-                child.data = container.data + start;
-                child.size = end - start;
-              }
-            else
-              {
-                child.data = NULL;
-                child.size = 0;
-              }
-          }
-
-        return child;
-      }
-
-    case G_VARIANT_TYPE_INFO_CHAR_TUPLE:
-    case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY:
-      {
-        const GVariantMemberInfo *info;
-        GVariantSerialised child;
-        gsize start = 0, end = 0;
-        gsize n_children;
-        guint offset_size;
-
-        offset_size = g_variant_serialiser_offset_size (container);
-        n_children = g_variant_type_info_n_members (container.type);
-        info = g_variant_type_info_member_info (container.type, index);
-        if (info == NULL)
-          break;
-
-        child.type = g_variant_type_info_ref (info->type);
-        g_variant_type_info_query (info->type, NULL, &child.size);
-        child.data = NULL;
-
-        if (info->i != -1l)
-          {
-            if (offset_size * (info->i + 1) > container.size)
-              return child;
-
-            memcpy (&start,
-                    container.data + container.size - offset_size * (info->i + 1),
-                    offset_size);
-            start = GSIZE_FROM_LE (start);
-          }
-
-        start += info->a;
-        start &= info->b;
-        start |= info->c;
-
-        if (child.size)
-          {
-            if (start + child.size <= container.size)
-              child.data = container.data + start;
-
-            return child;
-          }
-
-        if (index == n_children - 1)
-          end = container.size - offset_size * (info->i + 1);
-        else
-          {
-            if (offset_size * (info->i + 2) > container.size)
-              return child;
-
-            memcpy (&end,
-                    container.data + container.size - offset_size * (info->i + 2),
-                    offset_size);
-            end = GSIZE_FROM_LE (end);
-          }
-
-        if (start < end && end <= container.size)
-          {
-            child.data = container.data + start;
-            child.size = end - start;
-          }
-
-        return child;
-      }
-
-    default:
+  if G_LIKELY (index_ < g_variant_serialised_n_children (serialised))
+    {
+      DISPATCH_CASES (serialised.type_info, get_child (serialised, index_))
       g_assert_not_reached ();
-  }
+    }
 
   g_error ("Attempt to access item %"G_GSIZE_FORMAT
            " in a container with only %"G_GSIZE_FORMAT" items",
-           index, g_variant_serialised_n_children (container));
+           index_, g_variant_serialised_n_children (serialised));
 }
 
 void
-g_variant_serialiser_serialise (GVariantSerialised        container,
+g_variant_serialiser_serialise (GVariantSerialised        serialised,
                                 GVariantSerialisedFiller  gvs_filler,
                                 const gpointer           *children,
                                 gsize                     n_children)
 {
-  switch (g_variant_type_info_get_type_char (container.type))
-  {
-    case G_VARIANT_TYPE_INFO_CHAR_VARIANT:
-      {
-        GVariantSerialised child = { NULL, container.data, 0 };
-        const gchar *type_string;
-        gsize type_length;
-
-        g_assert_cmpint (n_children, ==, 1);
-
-        /* write the data for the child.
-         * side effect: child.type and child.size are set
-         */
-        gvs_filler (&child, children[0]);
-
-        type_string = g_variant_type_info_get_type_string (child.type);
-        type_length = strlen (type_string);
-
-        /* write the separator byte */
-        container.data[child.size] = '\0';
-
-        /* and the type string */
-        memcpy (container.data + child.size + 1, type_string, type_length);
-
-        /* make sure that it all adds up */
-        g_assert_cmpint (child.size + 1 + type_length, ==, container.size);
-
-        return;
-      }
-
-    case G_VARIANT_TYPE_INFO_CHAR_MAYBE:
-      {
-        g_assert_cmpint (n_children, ==, (container.size > 0));
-
-        if (n_children)
-          {
-            GVariantSerialised child = { NULL, container.data, 0 };
-            gsize fixed_size;
-
-            child.type = g_variant_type_info_element (container.type);
-            g_variant_type_info_query (child.type, NULL, &fixed_size);
-
-            /* write the data for the child.
-             * side effect: asserts child.type matches
-             * also: sets child.size
-             */
-            gvs_filler (&child, children[0]);
-
-            if (fixed_size)
-              /* for all fixed sized children, double check */
-              g_assert_cmpint (fixed_size, ==, child.size);
-            else
-              /* for variable-width children, add a pad byte */
-              container.data[child.size++] = '\0';
-
-            g_assert_cmpint (child.size, ==, container.size);
-          }
-
-        return;
-      }
-
-    case G_VARIANT_TYPE_INFO_CHAR_ARRAY:
-      {
-        g_assert_cmpint ((n_children > 0), ==, (container.size > 0));
-
-        if (n_children)
-          {
-            GVariantSerialised child = { NULL, container.data, 0 };
-            gsize offset, offsets_boundary, offset_ptr;
-            guint offset_size, align;
-            gsize fixed_size;
-
-            child.type = g_variant_type_info_element (container.type);
-            g_variant_type_info_query (child.type, &align, &fixed_size);
-            offset_size = g_variant_serialiser_offset_size (container);
-
-            if (!fixed_size)
-              offsets_boundary = container.size - offset_size * n_children;
-            else
-              offsets_boundary = container.size;
-            offset_ptr = offsets_boundary;
-
-            offset = 0;
-            while (n_children--)
-              {
-                child.size = 0;
-                child.data = container.data + offset + ((-offset) & align);
-                gvs_filler (&child, *children++);
-                while (child.size &&& container.data[offset] != child.data)
-                  container.data[offset++] = '\0';
-                offset += child.size;
-
-                if (!fixed_size)
-                  {
-                    gsize le_offset = GSIZE_TO_LE (offset);
-
-                    memcpy (&container.data[offset_ptr],
-                            &le_offset, offset_size);
-                    offset_ptr += offset_size;
-                  }
-              }
-
-            g_assert (offset_ptr == container.size &&
-                      offset == offsets_boundary);
-          }
-
-        return;
-      }
-
-    case G_VARIANT_TYPE_INFO_CHAR_TUPLE:
-    case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY:
-      {
-        if (n_children)
-          {
-            gsize offset, offsets_boundary, offset_ptr;
-            const GVariantMemberInfo *info;
-            guint offset_size, align;
-            gsize fixed_size;
-            gboolean fixed;
-
-            info = g_variant_type_info_member_info (container.type, 0);
-            offset_size = g_variant_serialiser_offset_size (container);
-
-            offset = 0;
-            fixed = TRUE;
-            offsets_boundary = offset_ptr = container.size;
-            offsets_boundary -= (info[n_children - 1].i + 1) * offset_size;
-
-            while (n_children--)
-              {
-                GVariantSerialised child = { info++->type };
-
-                g_variant_type_info_query (child.type, &align, &fixed_size);
-                child.data = container.data + offset + ((-offset) & align);
-                gvs_filler (&child, *children++);
-
-                while (child.size &&& container.data[offset] != child.data)
-                  container.data[offset++] = '\0';
-                offset += child.size;
-
-                if (!fixed_size)
-                  {
-                    fixed = FALSE;
-
-                    if (n_children)
-                      {
-                        gsize le_offset = GSIZE_TO_LE (offset);
-
-                        offset_ptr -= offset_size;
-                        memcpy (&container.data[offset_ptr],
-                                &le_offset, offset_size);
-                      }
-                  }
-              }
-
-            g_variant_type_info_query (container.type, &align, &fixed_size);
-
-            if (fixed)
-              {
-                while (offset & align)
-                  container.data[offset++] = '\0';
-
-                g_assert_cmpint (offsets_boundary, ==, container.size);
-                g_assert_cmpint (offset, ==, fixed_size);
-              }
-            else
-              g_assert_cmpint (fixed_size, ==, 0);
-
-            g_assert_cmpint (offset, ==, offsets_boundary);
-            g_assert_cmpint (offset_ptr, ==, offsets_boundary);
-          }
-        else
-          {
-            /* () */
-            g_assert_cmpint (container.size, ==, 1);
-            container.data[0] = '\0';
-          }
-
-        return;
-      }
-
-    default:
-      g_assert_not_reached ();
-  }
+  DISPATCH_CASES (serialised.type_info,
+                   serialise (serialised, gvs_filler, children, n_children))
+  g_assert_not_reached ();
 }
 
 gsize
-g_variant_serialiser_needed_size (GVariantTypeInfo         *type,
+g_variant_serialiser_needed_size (GVariantTypeInfo         *type_info,
                                   GVariantSerialisedFiller  gvs_filler,
                                   const gpointer           *children,
                                   gsize                     n_children)
 {
-  switch (g_variant_type_info_get_type_char (type))
-  {
-    case G_VARIANT_TYPE_INFO_CHAR_VARIANT:
-      {
-        GVariantSerialised child = {};
-        const gchar *type_string;
-
-        g_assert_cmpint (n_children, ==, 1);
-        gvs_filler (&child, children[0]);
-
-        type_string = g_variant_type_info_get_type_string (child.type);
-
-        return child.size + 1 + strlen (type_string);
-      }
-
-    case G_VARIANT_TYPE_INFO_CHAR_MAYBE:
-      {
-        GVariantSerialised child = { g_variant_type_info_element (type) };
-        gsize fixed_size;
-
-        g_assert_cmpint (n_children, <=, 1);
-
-        if (n_children == 0)
-          return 0;
-
-        gvs_filler (&child, children[0]);
-        g_variant_type_info_query (child.type, NULL, &fixed_size);
-
-        if (fixed_size)
-          /* double check */
-          g_assert (child.size == fixed_size);
-        else
-          /* room for the padding byte */
-          child.size++;
-
-        return child.size;
-      }
-
-    case G_VARIANT_TYPE_INFO_CHAR_ARRAY:
-      {
-        GVariantTypeInfo *elem_type;
-        gsize fixed_size;
-        guint alignment;
-
-        if (n_children == 0)
-          return 0;
-
-        elem_type = g_variant_type_info_element (type);
-        g_variant_type_info_query (elem_type, &alignment, &fixed_size);
-
-        if (!fixed_size)
-          {
-            gsize offset;
-            gsize i;
-
-            offset = 0;
-
-            for (i = 0; i < n_children; i++)
-              {
-                GVariantSerialised child = {};
-
-                gvs_filler (&child, children[i]);
-                g_assert (child.type == elem_type);
-
-                if (child.size)
-                  offset += (-offset) & alignment;
-                offset += child.size;
-              }
-
-            return g_variant_serialiser_determine_size (offset,
-                                                        n_children,
-                                                        TRUE);
-          }
-        else
-          return fixed_size * n_children;
-      }
-
-    case G_VARIANT_TYPE_INFO_CHAR_TUPLE:
-    case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY:
-      {
-        gsize n_offsets;
-        gsize offset;
-        gsize i;
-
-        g_assert_cmpint (g_variant_type_info_n_members (type), ==, n_children);
-
-        {
-          gsize fixed_size;
-
-          g_variant_type_info_query (type, NULL, &fixed_size);
-
-          if (fixed_size)
-            return fixed_size;
-        }
-
-        n_offsets = 0;
-        offset = 0;
-
-        for (i = 0; i < n_children; i++)
-          {
-            GVariantSerialised child = {};
-            const GVariantMemberInfo *info;
-            guint alignment;
-            gsize fixed_size;
-
-            info = g_variant_type_info_member_info (type, i);
-            gvs_filler (&child, children[i]);
-            g_assert (child.type == info->type);
-
-            g_variant_type_info_query (info->type, &alignment, &fixed_size);
-
-            if (!fixed_size)
-              {
-                if (child.size)
-                  {
-                    offset += (-offset) & alignment;
-                    offset += child.size;
-                  }
-
-                if (i != n_children - 1)
-                  n_offsets++;
-              }
-            else
-              {
-                offset += (-offset) & alignment;
-                offset += fixed_size;
-              }
-          }
-
-          /* no need to pad fixed-sized tuples here because
-           * fixed sized tuples are taken care of directly.
-           */
-
-        return g_variant_serialiser_determine_size (offset, n_offsets, FALSE);
-      }
-
-    default:
-      g_assert_not_reached ();
-  }
+  DISPATCH_CASES (type_info,
+                   needed_size (type_info, gvs_filler, children, n_children))
+  g_assert_not_reached ();
 }
 
 void
@@ -1542,7 +1011,7 @@ g_variant_serialised_byteswap (GVariantSerialised value)
   /* the types we potentially need to byteswap are
    * exactly those with alignment requirements.
    */
-  g_variant_type_info_query (value.type, &alignment, &fixed_size);
+  g_variant_type_info_query (value.type_info, &alignment, &fixed_size);
   if (!alignment)
     return;
 
@@ -1611,10 +1080,10 @@ g_variant_serialised_assert_invariant (GVariantSerialised value)
   gsize fixed_size;
   guint alignment;
 
-  g_assert (value.type != NULL);
+  g_assert (value.type_info != NULL);
   g_assert_cmpint ((value.data == NULL), <=, (value.size == 0));
 
-  g_variant_type_info_query (value.type, &alignment, &fixed_size);
+  g_variant_type_info_query (value.type_info, &alignment, &fixed_size);
 
   g_assert_cmpint (((gsize) value.data) & alignment, ==, 0);
   if (fixed_size)
@@ -1622,11 +1091,15 @@ g_variant_serialised_assert_invariant (GVariantSerialised value)
 }
 
 gboolean
-g_variant_serialised_is_normal (GVariantSerialised value)
+g_variant_serialised_is_normal (GVariantSerialised serialised)
 {
+  DISPATCH_CASES (serialised.type_info, is_normal (serialised))
+
+  return TRUE;
+#if 0
 #define fail return FALSE
 //#define fail g_assert_not_reached ()
-  switch (g_variant_type_info_get_type_char (value.type))
+  switch (g_variant_type_info_get_type_char (value.type_info))
   {
     case G_VARIANT_TYPE_INFO_CHAR_BYTE:
     case G_VARIANT_TYPE_INFO_CHAR_INT16:
@@ -1964,6 +1437,7 @@ g_variant_serialised_is_normal (GVariantSerialised value)
     default:
       g_assert_not_reached ();
   }
+#endif
 }
 
 #define __G_VARIANT_SERIALISER_C__
diff --git a/glib/gvariant-valist.c b/glib/gvariant-valist.c
index 91e409b..b5ce6d3 100644
--- a/glib/gvariant-valist.c
+++ b/glib/gvariant-valist.c
@@ -21,6 +21,7 @@
 
 #include <glib/gtestutils.h>
 #include <glib/gmessages.h>
+#include <glib/gstrfuncs.h>
 #include <string.h>
 
 #include "galias.h"



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