[glibmm] Glib::Variant: Improved support for D-Bus object paths and signatures



commit 94ceeee931b852296861e9a2d21a9b34a88dff54
Author: Kjell Ahlstedt <kjellahlstedt gmail com>
Date:   Wed Aug 16 09:04:36 2017 +0200

    Glib::Variant: Improved support for D-Bus object paths and signatures
    
    * glib/glibmm/filelist.am: Add variantdbusstring.h and variantdbusstring.cc.
    * glib/glibmm/variantdbusstring.[cc|h]: New files. String classes meant
    only for Variants with D-Bus object paths or D-Bus signatures.
    * glib/src/variant.[ccg|hg]: Add specializations for
    Variant<Glib::DBusObjectPathString>, Variant<Glib::DBusSignatureString>
    and Variant<std::vector<Glib::DBusObjectPathString>>.
    * glib/src/varianttype.[ccg|hg]: Add VARIANT_TYPE_OBJECT_PATH_ARRAY.
    * tests/glibmm_variant/main.cc: Add test_object_path().
    
    Make it possible to create a composite Variant containing variant type
    o (D-Bus object path) or g (D-Bus signature). Bug 785700

 glib/glibmm/filelist.am          |    2 +
 glib/glibmm/variantdbusstring.cc |   17 ++++
 glib/glibmm/variantdbusstring.h  |   64 ++++++++++++++
 glib/src/variant.ccg             |  138 ++++++++++++++++++++++++++++++
 glib/src/variant.hg              |  171 ++++++++++++++++++++++++++++++++++++--
 glib/src/varianttype.ccg         |    2 +
 glib/src/varianttype.hg          |    2 +
 tests/glibmm_variant/main.cc     |   55 ++++++++++++-
 8 files changed, 440 insertions(+), 11 deletions(-)
---
diff --git a/glib/glibmm/filelist.am b/glib/glibmm/filelist.am
index d0aeaf0..0218b17 100644
--- a/glib/glibmm/filelist.am
+++ b/glib/glibmm/filelist.am
@@ -33,6 +33,7 @@ glibmm_files_extra_cc =                       \
        utility.cc                      \
        value.cc                        \
        value_custom.cc                 \
+       variantdbusstring.cc \
        vectorutils.cc                  \
        wrap.cc
 
@@ -70,6 +71,7 @@ glibmm_files_extra_h =                        \
        utility.h                       \
        value.h                         \
        value_custom.h                  \
+       variantdbusstring.h \
        vectorutils.h                   \
        wrap.h                          \
        wrap_init.h
diff --git a/glib/glibmm/variantdbusstring.cc b/glib/glibmm/variantdbusstring.cc
new file mode 100644
index 0000000..e8ad5ce
--- /dev/null
+++ b/glib/glibmm/variantdbusstring.cc
@@ -0,0 +1,17 @@
+/* Copyright (C) 2017 The glibmm Development Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glibmm/variantdbusstring.h>
diff --git a/glib/glibmm/variantdbusstring.h b/glib/glibmm/variantdbusstring.h
new file mode 100644
index 0000000..f6a6e75
--- /dev/null
+++ b/glib/glibmm/variantdbusstring.h
@@ -0,0 +1,64 @@
+#ifndef _GLIBMM_VARIANT_DBUS_STRING_H
+#define _GLIBMM_VARIANT_DBUS_STRING_H
+/* Copyright (C) 2017 The glibmm Development Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glibmm/ustring.h>
+
+namespace Glib
+{
+
+/** String class for D-Bus object paths in Glib::Variant.
+ *
+ * Use it if you want to create a Glib::Variant with D-Bus object paths.
+ *
+ * @code
+ * using opstring_with_string_t =
+ *   std::map<Glib::DBusObjectPathString, Glib::Variant<Glib::ustring>>;
+ * opstring_with_string_t map1;
+ * map1["/map1/path1"] = Glib::Variant<Glib::ustring>::create("value1");
+ * auto variant1 = Glib::Variant<opstring_with_string_t>::create(map1);
+ * @endcode
+ *
+ * @newin{2,54}
+ * @ingroup Variant
+*/
+class DBusObjectPathString : public Glib::ustring
+{
+public:
+  using Glib::ustring::ustring;
+};
+
+/** String class for D-Bus signatures in Glib::Variant.
+ *
+ * Use it if you want to create a Glib::Variant with a D-Bus signature.
+ *
+ * @code
+ * auto variant = Glib::Variant<Glib::DBusSignatureString>::create("s");
+ * @endcode
+ *
+ * @newin{2,54}
+ * @ingroup Variant
+*/
+class DBusSignatureString : public Glib::ustring
+{
+public:
+  using Glib::ustring::ustring;
+};
+
+} // namespace Glib
+
+#endif /* _GLIBMM_VARIANT_DBUS_STRING_H */
diff --git a/glib/src/variant.ccg b/glib/src/variant.ccg
index 9e59319..fd0cb22 100644
--- a/glib/src/variant.ccg
+++ b/glib/src/variant.ccg
@@ -324,6 +324,70 @@ Variant<Glib::ustring>::get() const
   return convert_const_gchar_ptr_to_ustring(g_variant_get_string(gobject_, nullptr));
 }
 
+/*--------------------Variant<Glib::DBusObjectPathString>---------------------*/
+
+Variant<Glib::DBusObjectPathString>::Variant() : VariantStringBase()
+{
+}
+
+Variant<Glib::DBusObjectPathString>::Variant(GVariant* castitem, bool take_a_reference)
+: VariantStringBase(castitem, take_a_reference)
+{
+}
+
+// static
+const VariantType&
+Variant<Glib::DBusObjectPathString>::variant_type()
+{
+  return VARIANT_TYPE_OBJECT_PATH;
+}
+
+Variant<Glib::DBusObjectPathString>
+Variant<Glib::DBusObjectPathString>::create(const Glib::DBusObjectPathString& data)
+{
+  auto result = Variant<CppType>(g_variant_new_object_path(data.c_str()));
+  return result;
+}
+
+Glib::DBusObjectPathString
+Variant<Glib::DBusObjectPathString>::get() const
+{
+  const char* s = g_variant_get_string(gobject_, nullptr);
+  return s ? CppType(s) : CppType();
+}
+
+/*--------------------Variant<Glib::DBusSignatureString>---------------------*/
+
+Variant<Glib::DBusSignatureString>::Variant() : VariantStringBase()
+{
+}
+
+Variant<Glib::DBusSignatureString>::Variant(GVariant* castitem, bool take_a_reference)
+: VariantStringBase(castitem, take_a_reference)
+{
+}
+
+// static
+const VariantType&
+Variant<Glib::DBusSignatureString>::variant_type()
+{
+  return VARIANT_TYPE_SIGNATURE;
+}
+
+Variant<Glib::DBusSignatureString>
+Variant<Glib::DBusSignatureString>::create(const Glib::DBusSignatureString& data)
+{
+  auto result = Variant<CppType>(g_variant_new_signature(data.c_str()));
+  return result;
+}
+
+Glib::DBusSignatureString
+Variant<Glib::DBusSignatureString>::get() const
+{
+  const char* s = g_variant_get_string(gobject_, nullptr);
+  return s ? CppType(s) : CppType();
+}
+
 /*--------------------Variant<std::string>---------------------*/
 
 Variant<std::string>::Variant() : VariantStringBase()
@@ -442,6 +506,80 @@ Variant<type_vec_ustring>::get_iter() const
   return VariantContainerBase::get_iter(variant_type());
 }
 
+/*--------------------Variant<std::vector<Glib::DBusObjectPathString>>---------------------*/
+
+using type_vec_opstring = std::vector<Glib::DBusObjectPathString>;
+
+Variant<type_vec_opstring>::Variant() : VariantContainerBase()
+{
+}
+
+Variant<type_vec_opstring>::Variant(GVariant* castitem, bool take_a_reference)
+: VariantContainerBase(castitem, take_a_reference)
+{
+}
+
+// static
+const VariantType&
+Variant<type_vec_opstring>::variant_type()
+{
+  return VARIANT_TYPE_OBJECT_PATH_ARRAY;
+}
+
+// static
+Variant<type_vec_opstring>
+Variant<type_vec_opstring>::create(const type_vec_opstring& data)
+{
+  // Get the variant type of the elements.
+  VariantType element_variant_type = Variant<CppType>::variant_type();
+
+  // Get the variant type of the array.
+  VariantType array_variant_type = Variant<type_vec_opstring>::variant_type();
+
+  // Create a GVariantBuilder to build the array.
+  GVariantBuilder* builder = g_variant_builder_new(array_variant_type.gobj());
+
+  // Add the elements of the vector into the builder.
+  for (const auto& str : data)
+    g_variant_builder_add(builder, element_variant_type.get_string().c_str(), str.c_str());
+
+  // Create the variant using the builder.
+  auto result =
+    Variant<type_vec_opstring>(g_variant_new(array_variant_type.get_string().c_str(), builder));
+
+  g_variant_builder_unref(builder);
+
+  return result;
+}
+
+Glib::DBusObjectPathString
+Variant<type_vec_opstring>::get_child(gsize index) const
+{
+  if (index >= get_n_children())
+    throw std::out_of_range(
+      "Variant< std::vector<Glib::DBusObjectPathString> >::get_child(): Index out of bounds.");
+
+  GVariant* gvariant = g_variant_get_child_value(const_cast<GVariant*>(gobj()), index);
+
+  return Glib::Variant<CppType>(gvariant).get();
+}
+
+type_vec_opstring
+Variant<type_vec_opstring>::get() const
+{
+  gsize n_children = 0;
+  const gchar** children = g_variant_get_objv(const_cast<GVariant*>(gobj()), &n_children);
+  type_vec_opstring result = type_vec_opstring(children, children+n_children);
+  g_free(children);
+  return result;
+}
+
+VariantIter
+Variant<type_vec_opstring>::get_iter() const
+{
+  return VariantContainerBase::get_iter(variant_type());
+}
+
 /*--------------------Variant< std::vector<std::string> >---------------------*/
 
 using type_vec_string = std::vector<std::string>;
diff --git a/glib/src/variant.hg b/glib/src/variant.hg
index 74a14f7..0824ce2 100644
--- a/glib/src/variant.hg
+++ b/glib/src/variant.hg
@@ -20,6 +20,7 @@ _DEFS(glibmm,glib)
 #include <glibmmconfig.h>
 #include <glibmm/varianttype.h>
 #include <glibmm/variantiter.h>
+#include <glibmm/variantdbusstring.h>
 #include <glibmm/refptr.h>
 #include <glibmm/ustring.h>
 #include <glibmm/error.h>
@@ -288,12 +289,12 @@ public:
    */
   explicit VariantStringBase(GVariant* castitem,  bool take_a_reference = false);
 
-  /** Creates a D-Bus object path variant with the contents of @a string. @a
-   * string must be a valid D-Bus object path. Use is_object_path() if unsure.
+  /** Creates a D-Bus object path variant with the contents of @a object_path.
+   * @a object_path must be a valid D-Bus object path. Use is_object_path() if unsure.
    *
-   * @param output A location in which to store the new object path variant
+   * @param[out] output A location in which to store the new object path variant
    * instance.
-   * @param object_path A normal nul-terminated string.
+   * @param object_path An object path string.
    * @newin{2,28}
    */
   static void create_object_path(VariantStringBase& output,
@@ -302,12 +303,12 @@ public:
 
   _WRAP_METHOD(static bool is_object_path(const std::string& string), g_variant_is_object_path)
 
-  /** Creates a D-Bus type signature variant with the contents of @a string. @a
-   * string must be a valid D-Bus type signature. Use is_signature() if unsure.
+  /** Creates a D-Bus type signature variant with the contents of @a signature.
+   * @a signature must be a valid D-Bus type signature. Use is_signature() if unsure.
    *
-   * @param output A location in which to store the new signature variant
+   * @param[out] output A location in which to store the new signature variant
    * instance.
-   * @param signature A normal nul-terminated string.
+   * @param signature A signature string.
    * @newin{2,28}
    */
   static void create_signature(VariantStringBase& output,
@@ -568,6 +569,98 @@ public:
   _IGNORE(g_variant_get_string, g_variant_dup_string)
 };
 
+/** Specialization of Variant containing a Glib::DBusObjectPathString,
+ * for variants of type object path.
+ * @newin{2,54}
+ * @ingroup Variant
+ */
+template<>
+class Variant<Glib::DBusObjectPathString> : public VariantStringBase
+{
+  // Trick gmmproc into thinking this is derived from GVariant to wrap some methods.
+  _CLASS_GENERIC(Variant<Glib::DBusObjectPathString>, GVariant)
+public:
+  using CType = char*;
+  using CppType = Glib::DBusObjectPathString;
+
+  /// Default constructor.
+  Variant();
+
+  /** GVariant constructor.
+   * @param castitem The GVariant to wrap.
+   * @param take_a_reference Whether to take an extra reference of the
+   * GVariant or not (not taking one could destroy the GVariant with the
+   * wrapper).
+   */
+  explicit Variant(GVariant* castitem,  bool take_a_reference = false);
+
+  /** Gets the VariantType.
+   * @return The VariantType.
+   * @newin{2,54}
+   */
+  static const VariantType& variant_type() G_GNUC_CONST;
+
+  /** Creates a new Variant<Glib::DBusObjectPathString>.
+   * @param data The value of the new Variant.
+   * @return The new Variant.
+   * @newin{2,54}
+   */
+  static Variant<CppType> create(const CppType& data);
+
+  //We can't use WRAP_METHOD() here because g_variant_get_string() takes an extra length parameter.
+  /** Gets the contents of the Variant.
+   * @return The contents of the Variant.
+   * @newin{2,54}
+   */
+  CppType get() const;
+};
+
+/** Specialization of Variant containing a Glib::DBusSignatureString,
+ * for variants of type signature.
+ * @newin{2,54}
+ * @ingroup Variant
+ */
+template<>
+class Variant<Glib::DBusSignatureString> : public VariantStringBase
+{
+  // Trick gmmproc into thinking this is derived from GVariant to wrap some methods.
+  _CLASS_GENERIC(Variant<Glib::DBusSignatureString>, GVariant)
+public:
+  using CType = char*;
+  using CppType = Glib::DBusSignatureString;
+
+  /// Default constructor.
+  Variant();
+
+  /** GVariant constructor.
+   * @param castitem The GVariant to wrap.
+   * @param take_a_reference Whether to take an extra reference of the
+   * GVariant or not (not taking one could destroy the GVariant with the
+   * wrapper).
+   */
+  explicit Variant(GVariant* castitem,  bool take_a_reference = false);
+
+  /** Gets the VariantType.
+   * @return The VariantType.
+   * @newin{2,54}
+   */
+  static const VariantType& variant_type() G_GNUC_CONST;
+
+  /** Creates a new Variant<Glib::DBusSignatureString>.
+   * @param data The value of the new Variant.
+   * @return The new Variant.
+   * @newin{2,54}
+   */
+  static Variant<CppType> create(const CppType& data);
+
+  //We can't use WRAP_METHOD() here because g_variant_get_string() takes an extra length parameter.
+  /** Gets the contents of the Variant.
+   * @return The contents of the Variant.
+   * @newin{2,54}
+   */
+  CppType get() const;
+};
+
 /** Specialization of Variant containing a std::string, for variants of type
  * bytestring, string, object path, or signature.
  * See also Variant<Glib::ustring> for UTF-8 strings.
@@ -794,6 +887,68 @@ public:
   VariantIter get_iter() const;
 };
 
+/** Specialization of Variant containing an array of D-Bus object paths.
+ *
+ * @newin{2,54}
+ * @ingroup Variant
+ */
+template<>
+class Variant<std::vector<Glib::DBusObjectPathString>> : public VariantContainerBase
+{
+public:
+  using CppType = Glib::DBusObjectPathString;
+  using CppContainerType = std::vector<Glib::DBusObjectPathString>;
+
+  /// Default constructor.
+  Variant();
+
+  /** GVariant constructor.
+   * @param castitem The GVariant to wrap.
+   * @param take_a_reference Whether to take an extra reference of the
+   * GVariant or not (not taking one could destroy the GVariant with the
+   * wrapper).
+   */
+  explicit Variant(GVariant* castitem, bool take_a_reference = false);
+
+  /** Gets the VariantType.
+   * @return The VariantType.
+   * @newin{2,54}
+   */
+  static const VariantType& variant_type() G_GNUC_CONST;
+
+  /** Creates a new Variant from an array of strings.
+   * @param data The array to use for creation.
+   * @return The new Variant.
+   * @newin{2,54}
+   */
+  static Variant<CppContainerType> create(const CppContainerType& data);
+
+  /** Gets a specific element of the string array.  It is an error if @a index
+   * is greater than the number of child items in the container.  See
+   * VariantContainerBase::get_n_children().
+   *
+   * This function is O(1).
+   *
+   * @param index The index of the element.
+   * @return The element at index @a index.
+   * @throw std::out_of_range
+   * @newin{2,54}
+   */
+  CppType get_child(gsize index) const;
+
+  /** Gets the string vector of the Variant.
+   * @return The vector.
+   * @newin{2,54}
+   */
+  CppContainerType get() const;
+
+  /** Gets a VariantIter of the Variant.
+   * @return the VariantIter.
+   * @newin{2,54}
+   */
+  VariantIter get_iter() const;
+};
+
 /** Specialization of Variant containing an array of non-UTF-8 strings
  * (byte string arrays).
  * @newin{2,28}
diff --git a/glib/src/varianttype.ccg b/glib/src/varianttype.ccg
index d4032c1..1bac94d 100644
--- a/glib/src/varianttype.ccg
+++ b/glib/src/varianttype.ccg
@@ -113,6 +113,8 @@ const VariantType VARIANT_TYPE_DICTIONARY(G_VARIANT_TYPE_DICTIONARY);
 
 const VariantType VARIANT_TYPE_STRING_ARRAY(G_VARIANT_TYPE_STRING_ARRAY);
 
+const VariantType VARIANT_TYPE_OBJECT_PATH_ARRAY(G_VARIANT_TYPE_OBJECT_PATH_ARRAY);
+
 const VariantType VARIANT_TYPE_BYTESTRING(G_VARIANT_TYPE_BYTESTRING);
 
 const VariantType VARIANT_TYPE_BYTESTRING_ARRAY(G_VARIANT_TYPE_BYTESTRING_ARRAY);
diff --git a/glib/src/varianttype.hg b/glib/src/varianttype.hg
index 509eaa6..de8b970 100644
--- a/glib/src/varianttype.hg
+++ b/glib/src/varianttype.hg
@@ -238,6 +238,8 @@ extern const VariantType VARIANT_TYPE_DICTIONARY;
 
 extern const VariantType VARIANT_TYPE_STRING_ARRAY;
 
+extern const VariantType VARIANT_TYPE_OBJECT_PATH_ARRAY;
+
 extern const VariantType VARIANT_TYPE_BYTESTRING;
 
 extern const VariantType VARIANT_TYPE_BYTESTRING_ARRAY;
diff --git a/tests/glibmm_variant/main.cc b/tests/glibmm_variant/main.cc
index 4d3c2c7..0836ec2 100644
--- a/tests/glibmm_variant/main.cc
+++ b/tests/glibmm_variant/main.cc
@@ -14,7 +14,7 @@ static void test_dynamic_cast();
 namespace
 {
 
-int test_tuple()
+bool test_tuple()
 {
   using TupleType = std::tuple<guint16, Glib::ustring, bool>;
   using MapType = std::map<guint16, TupleType>;
@@ -70,7 +70,54 @@ int test_tuple()
   ostr << "Extracted tuple2: (" << q4 << ", " << s4 << ", " << b4 << ")" << std::endl;
   result_ok &= q4 == q2 && s4 == s2 && b4 == b2;
 
-  return result_ok ? EXIT_SUCCESS : EXIT_FAILURE;
+  return result_ok;
+}
+
+bool test_object_path()
+{
+  bool result_ok = true;
+
+  // Object path vector
+  std::vector<Glib::DBusObjectPathString> vec1 {"/object/path1", "/object/path_two", "/object/pathIII" };
+  auto variantvec1 = Glib::Variant<std::vector<Glib::DBusObjectPathString>>::create(vec1);
+
+  auto vec2 = variantvec1.get();
+  ostr << "Extracted object paths: " << vec2[0] << ", " << vec2[1] << ", " << vec2[2] << std::endl;
+
+  for (std::size_t i = 0; i < vec1.size(); ++i)
+    result_ok &= vec1[i] == vec2[i];
+
+  // Complicated structure of variant type a{oa{sa{sv}}}
+  // Glib::Variant<std::map<Glib::DBusObjectPathString, std::map<Glib::ustring, std::map<Glib::ustring, 
Glib::VariantBase>>>>
+  using three_leveled_map =
+    std::map<Glib::DBusObjectPathString, std::map<Glib::ustring, std::map<Glib::ustring, 
Glib::VariantBase>>>;
+
+  // Create the map
+  std::map<Glib::ustring, Glib::VariantBase> map1;
+  map1["map1_1"] = Glib::Variant<Glib::ustring>::create("value1");
+  std::map<Glib::ustring, std::map<Glib::ustring, Glib::VariantBase>> map2;
+  map2["map2_1"] = map1;
+  three_leveled_map map3;
+  map3["/map3/path1"] = map2;
+  // Create the corresponding Variant and check its type
+  auto variantmap = Glib::Variant<three_leveled_map>::create(map3);
+  ostr << "variantmap.get_type_string() = " << variantmap.get_type_string() << std::endl;
+  result_ok &= variantmap.get_type_string() == "a{oa{sa{sv}}}";
+  // Extract the map and check that the stored value remains.
+  auto map4 = variantmap.get();
+  auto variant1 = map4["/map3/path1"]["map2_1"]["map1_1"];
+  ostr << "variant1.get_type_string() = " << variant1.get_type_string() << std::endl;
+  auto variantstring = Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring>>(variant1);
+  if (variantstring && variantstring.get_type_string() == "s")
+  {
+    ostr << "Extracted map value: " << variantstring.get() << std::endl;
+    result_ok &= variantstring.get() == "value1";
+  }
+  else
+  {
+    result_ok = false;
+  }
+  return result_ok;
 }
 
 } // anonymous namespace
@@ -227,7 +274,9 @@ main(int, char**)
   test_variant_floating();
   test_dynamic_cast();
 
-  return test_tuple();
+  bool result_ok = test_tuple();
+  result_ok &= test_object_path();
+  return result_ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
 // Test casting of multiple types to a ustring:


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