[glib/wip/gvariant-kdbus: 5/9] GVariant: support serialising to GVariantVectors



commit cd4009265e66dbf0248f473287234b616e8e30cc
Author: Ryan Lortie <desrt desrt ca>
Date:   Fri Nov 28 17:57:30 2014 -0500

    GVariant: support serialising to GVariantVectors
    
    Add code for serialising GVariant to GVariantVectors.
    
    Export that internally via the glib-private machanism so that we can use
    it from GDBus.

 glib/glib-private.c        |    4 +-
 glib/glib-private.h        |    7 ++
 glib/gvariant-core.c       |   56 +++++++++++++
 glib/gvariant-serialiser.c |  192 ++++++++++++++++++++++++++++++++++++++++++++
 glib/gvariant-serialiser.h |   11 +++
 5 files changed, 269 insertions(+), 1 deletions(-)
---
diff --git a/glib/glib-private.c b/glib/glib-private.c
index bbf879f..3c1dac6 100644
--- a/glib/glib-private.c
+++ b/glib/glib-private.c
@@ -44,7 +44,9 @@ glib__private__ (void)
     g_main_context_new_with_next_id,
 
     g_dir_open_with_errno,
-    g_dir_new_from_dirp
+    g_dir_new_from_dirp,
+
+    g_variant_to_vectors
   };
 
   return &table;
diff --git a/glib/glib-private.h b/glib/glib-private.h
index 0a28008..40509b6 100644
--- a/glib/glib-private.h
+++ b/glib/glib-private.h
@@ -20,6 +20,7 @@
 
 #include <glib.h>
 #include "gwakeup.h"
+#include "gvariant-vectors.h"
 
 #if defined(__GNUC__)
 # define _g_alignof(type) (__alignof__ (type))
@@ -30,6 +31,8 @@
 GMainContext *          g_get_worker_context            (void);
 gboolean                g_check_setuid                  (void);
 GMainContext *          g_main_context_new_with_next_id (guint next_id);
+void                    g_variant_to_vectors            (GVariant *value,
+                                                         GVariantVectors *vectors);
 
 #ifdef G_OS_WIN32
 gchar *_glib_get_dll_directory (void);
@@ -61,6 +64,10 @@ typedef struct {
                                                          guint        flags);
   GDir *                (* g_dir_new_from_dirp)         (gpointer dirp);
 
+  void                  (* g_variant_to_vectors)        (GVariant    *value,
+                                                         GVariantVectors *vectors);
+
+
   /* Add other private functions here, initialize them in glib-private.c */
 } GLibPrivateVTable;
 
diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c
index 4ab4238..45b876b 100644
--- a/glib/gvariant-core.c
+++ b/glib/gvariant-core.c
@@ -19,6 +19,7 @@
 #include "config.h"
 
 #include <glib/gvariant-core.h>
+#include "glib-private.h"
 
 #include <glib/gvariant-serialiser.h>
 #include <glib/gtestutils.h>
@@ -424,6 +425,61 @@ g_variant_ensure_serialised (GVariant *value)
     }
 }
 
+/* Now we have the code to recursively serialise a GVariant into a
+ * GVariantVectors structure.
+ *
+ * We want to do this in cases where the GVariant contains large chunks
+ * of serialised data in order to avoid having to copy this data.
+ *
+ * This generally works the same as normal serialising (co-recursion
+ * with the serialiser) but instead of using a callback we just hard-code
+ * the callback with the name g_variant_callback_write_to_vectors().
+ *
+ * This is a private API that will be used by GDBus.
+ */
+gsize
+g_variant_callback_write_to_vectors (GVariantVectors   *vectors,
+                                     gpointer           data,
+                                     GVariantTypeInfo **type_info)
+{
+  GVariant *value = data;
+
+  if (g_variant_lock_in_tree_form (value))
+    {
+      g_variant_serialiser_write_to_vectors (vectors, value->type_info, value->size,
+                                             (gpointer *) value->contents.tree.children,
+                                             value->contents.tree.n_children);
+
+      g_variant_unlock (value);
+    }
+  else
+    g_variant_vectors_append_gbytes (vectors, value->contents.serialised.bytes,
+                                     value->contents.serialised.data, value->size);
+
+  if (type_info)
+    *type_info = value->type_info;
+
+  return value->size;
+}
+
+/* < private >
+ * g_variant_serialise_to_vectors:
+ * @value: a #GVariant
+ * @vectors: (out): the result
+ *
+ * Serialises @value into @vectors.
+ *
+ * The caller must free @vectors.
+ */
+void
+g_variant_to_vectors (GVariant        *value,
+                      GVariantVectors *vectors)
+{
+  g_variant_vectors_init (vectors);
+
+  g_variant_callback_write_to_vectors (vectors, value, NULL);
+}
+
 /* < private >
  * g_variant_alloc:
  * @type: the type of the new instance
diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c
index 5df7fc3..c25a7be 100644
--- a/glib/gvariant-serialiser.c
+++ b/glib/gvariant-serialiser.c
@@ -292,6 +292,19 @@ gvs_fixed_sized_maybe_serialise (GVariantSerialised        value,
     }
 }
 
+static gsize
+gvs_fixed_sized_maybe_write_to_vectors (GVariantVectors  *vectors,
+                                        GVariantTypeInfo *type_info,
+                                        gsize             size,
+                                        const gpointer   *children,
+                                        gsize             n_children)
+{
+  if (!n_children)
+    return 0;
+
+  return g_variant_callback_write_to_vectors (vectors, children[0], NULL);
+}
+
 static gboolean
 gvs_fixed_sized_maybe_is_normal (GVariantSerialised value)
 {
@@ -384,6 +397,20 @@ gvs_variable_sized_maybe_serialise (GVariantSerialised        value,
     }
 }
 
+static void
+gvs_variable_sized_maybe_write_to_vectors (GVariantVectors  *vectors,
+                                           GVariantTypeInfo *type_info,
+                                           gsize             size,
+                                           const gpointer   *children,
+                                           gsize             n_children)
+{
+  if (n_children)
+    {
+      g_variant_callback_write_to_vectors (vectors, children[0], NULL);
+      g_variant_vectors_append_copy (vectors, "", 1);
+    }
+}
+
 static gboolean
 gvs_variable_sized_maybe_is_normal (GVariantSerialised value)
 {
@@ -482,6 +509,19 @@ gvs_fixed_sized_array_serialise (GVariantSerialised        value,
     }
 }
 
+static void
+gvs_fixed_sized_array_write_to_vectors (GVariantVectors  *vectors,
+                                        GVariantTypeInfo *type_info,
+                                        gsize             size,
+                                        const gpointer   *children,
+                                        gsize             n_children)
+{
+  gsize i;
+
+  for (i = 0; i < n_children; i++)
+    g_variant_callback_write_to_vectors (vectors, children[i], NULL);
+}
+
 static gboolean
 gvs_fixed_sized_array_is_normal (GVariantSerialised value)
 {
@@ -747,6 +787,38 @@ gvs_variable_sized_array_serialise (GVariantSerialised        value,
     }
 }
 
+static void
+gvs_variable_sized_array_write_to_vectors (GVariantVectors  *vectors,
+                                           GVariantTypeInfo *type_info,
+                                           gsize             size,
+                                           const gpointer   *children,
+                                           gsize             n_children)
+{
+  guint offset_key;
+  guint alignment;
+  gsize offset;
+  gsize i;
+
+  if (n_children == 0)
+    return;
+
+  offset_key = g_variant_vectors_reserve_offsets (vectors, n_children, gvs_get_offset_size (size));
+  g_variant_type_info_query (type_info, &alignment, NULL);
+  offset = 0;
+
+  for (i = 0; i < n_children; i++)
+    {
+      if ((-offset) & alignment)
+        offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment);
+
+      offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL);
+
+      g_variant_vectors_write_to_offsets (vectors, i, offset, offset_key);
+    }
+
+  g_variant_vectors_commit_offsets (vectors, offset_key);
+}
+
 static gboolean
 gvs_variable_sized_array_is_normal (GVariantSerialised value)
 {
@@ -1014,6 +1086,95 @@ gvs_tuple_serialise (GVariantSerialised        value,
     value.data[offset++] = '\0';
 }
 
+
+static void
+gvs_tuple_write_to_vectors (GVariantVectors  *vectors,
+                            GVariantTypeInfo *type_info,
+                            gsize             size,
+                            const gpointer   *children,
+                            gsize             n_children)
+{
+  const GVariantMemberInfo *member_info = NULL;
+  gsize fixed_size;
+  gsize offset;
+  gsize i;
+
+  if (n_children == 0)
+    {
+      g_variant_vectors_append_copy (vectors, "", 1);
+      return;
+    }
+
+  g_variant_type_info_query (type_info, NULL, &fixed_size);
+  offset = 0;
+
+  if (!fixed_size)
+    {
+      gsize n_offsets;
+
+      member_info = g_variant_type_info_member_info (type_info, n_children - 1);
+      n_offsets = member_info->i + 1;
+
+      if (n_offsets)
+        {
+          gsize offset_key = 0;
+
+          offset_key = g_variant_vectors_reserve_offsets (vectors, n_offsets, gvs_get_offset_size (size));
+
+          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, NULL);
+
+              if ((-offset) & alignment)
+                offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment);
+
+              offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL);
+
+              if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET)
+                g_variant_vectors_write_to_offsets (vectors, --n_offsets, offset, offset_key);
+            }
+
+          g_variant_vectors_commit_offsets (vectors, offset_key);
+        }
+      else
+        {
+          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, NULL);
+
+              if ((-offset) & alignment)
+                offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment);
+
+              offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL);
+            }
+        }
+    }
+  else
+    {
+      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, NULL);
+
+          if ((-offset) & alignment)
+            offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment);
+
+          offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL);
+        }
+
+      g_assert (fixed_size - offset < 8);
+      g_variant_vectors_append_pad (vectors, fixed_size - offset);
+    }
+}
+
 static gboolean
 gvs_tuple_is_normal (GVariantSerialised value)
 {
@@ -1226,6 +1387,23 @@ gvs_variant_serialise (GVariantSerialised        value,
   memcpy (value.data + child.size + 1, type_string, strlen (type_string));
 }
 
+static void
+gvs_variant_write_to_vectors (GVariantVectors  *vectors,
+                              GVariantTypeInfo *type_info,
+                              gsize             size,
+                              const gpointer   *children,
+                              gsize             n_children)
+{
+  GVariantTypeInfo *child_type_info;
+  const gchar *type_string;
+
+  g_variant_callback_write_to_vectors (vectors, children[0], &child_type_info);
+  type_string = g_variant_type_info_get_type_string (child_type_info);
+
+  g_variant_vectors_append_copy (vectors, "", 1);
+  g_variant_vectors_append_copy (vectors, type_string, strlen (type_string));
+}
+
 static inline gboolean
 gvs_variant_is_normal (GVariantSerialised value)
 {
@@ -1435,7 +1613,21 @@ g_variant_serialiser_needed_size (GVariantTypeInfo         *type_info,
 
                   return gvs_/**/,/**/_needed_size (type_info, gvs_filler,
                                                     children, n_children);
+                 )
+  g_assert_not_reached ();
+}
+
 
+void
+g_variant_serialiser_write_to_vectors (GVariantVectors  *vectors,
+                                       GVariantTypeInfo *type_info,
+                                       gsize             size,
+                                       const gpointer   *children,
+                                       gsize             n_children)
+{
+  DISPATCH_CASES (type_info,
+                  gvs_/**/,/**/_write_to_vectors (vectors, type_info, size, children, n_children);
+                  return;
                  )
   g_assert_not_reached ();
 }
diff --git a/glib/gvariant-serialiser.h b/glib/gvariant-serialiser.h
index 2be3299..a558da0 100644
--- a/glib/gvariant-serialiser.h
+++ b/glib/gvariant-serialiser.h
@@ -22,6 +22,7 @@
 #define __G_VARIANT_SERIALISER_H__
 
 #include "gvarianttypeinfo.h"
+#include "gvariant-vectors.h"
 
 typedef struct
 {
@@ -70,4 +71,14 @@ GLIB_AVAILABLE_IN_ALL
 gboolean                        g_variant_serialiser_is_signature       (gconstpointer             data,
                                                                          gsize                     size);
 
+
+gsize                           g_variant_callback_write_to_vectors     (GVariantVectors          *vectors,
+                                                                         gpointer                  data,
+                                                                         GVariantTypeInfo        
**type_info);
+void                            g_variant_serialiser_write_to_vectors   (GVariantVectors          *items,
+                                                                         GVariantTypeInfo         *type_info,
+                                                                         gsize                     size,
+                                                                         const gpointer           *children,
+                                                                         gsize                     
n_children);
+
 #endif /* __G_VARIANT_SERIALISER_H__ */


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