summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjell Ahlstedt <kjellahlstedt@gmail.com>2017-09-08 17:23:47 +0200
committerKjell Ahlstedt <kjellahlstedt@gmail.com>2017-09-08 17:23:47 +0200
commit746ae9535d85147bddc3e36468222dad10024089 (patch)
tree56b4eae76759cff9e85275706c7fda62434f5a5c
parent9b47fdf5b44d374ef24102d3a2e6232585c7e0ea (diff)
downloadglibmm-746ae9535d85147bddc3e36468222dad10024089.tar.gz
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
-rw-r--r--glib/glibmm/filelist.am2
-rw-r--r--glib/glibmm/variantdbusstring.cc17
-rw-r--r--glib/glibmm/variantdbusstring.h64
-rw-r--r--glib/src/variant.ccg138
-rw-r--r--glib/src/variant.hg171
-rw-r--r--glib/src/varianttype.ccg2
-rw-r--r--glib/src/varianttype.hg2
-rw-r--r--tests/glibmm_variant/main.cc55
8 files changed, 440 insertions, 11 deletions
diff --git a/glib/glibmm/filelist.am b/glib/glibmm/filelist.am
index dc6615f5..b5a61695 100644
--- a/glib/glibmm/filelist.am
+++ b/glib/glibmm/filelist.am
@@ -37,6 +37,7 @@ glibmm_files_extra_cc = \
utility.cc \
value.cc \
value_custom.cc \
+ variantdbusstring.cc \
vectorutils.cc \
wrap.cc
@@ -81,6 +82,7 @@ glibmm_files_extra_h = \
utility.h \
value.h \
value_custom.h \
+ variantdbusstring.h \
vectorutils.h \
weakref.h \
wrap.h \
diff --git a/glib/glibmm/variantdbusstring.cc b/glib/glibmm/variantdbusstring.cc
new file mode 100644
index 00000000..e8ad5ce7
--- /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 00000000..f6a6e75a
--- /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 97ca38fc..a645143f 100644
--- a/glib/src/variant.ccg
+++ b/glib/src/variant.ccg
@@ -354,6 +354,70 @@ VariantBase::cast_dynamic<Variant<Glib::ustring>>(const VariantBase& v) noexcept
}
}
+/*--------------------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()
@@ -496,6 +560,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 f0cf212c..5ec352b8 100644
--- a/glib/src/variant.hg
+++ b/glib/src/variant.hg
@@ -19,6 +19,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>
@@ -311,12 +312,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,
@@ -325,12 +326,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,
@@ -596,6 +597,98 @@ template<>
Variant<Glib::ustring> VariantBase::cast_dynamic< Variant<Glib::ustring> >(const VariantBase& v)
noexcept(false);
+/** 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.
@@ -827,6 +920,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 86d74cdb..ff1784fa 100644
--- a/glib/src/varianttype.ccg
+++ b/glib/src/varianttype.ccg
@@ -112,6 +112,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 5680abed..4a8a3550 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 3c08ab2e..7431a9a6 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: