diff options
author | Kjell Ahlstedt <kjellahlstedt@gmail.com> | 2017-09-08 17:23:47 +0200 |
---|---|---|
committer | Kjell Ahlstedt <kjellahlstedt@gmail.com> | 2017-09-08 17:23:47 +0200 |
commit | 746ae9535d85147bddc3e36468222dad10024089 (patch) | |
tree | 56b4eae76759cff9e85275706c7fda62434f5a5c | |
parent | 9b47fdf5b44d374ef24102d3a2e6232585c7e0ea (diff) | |
download | glibmm-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.am | 2 | ||||
-rw-r--r-- | glib/glibmm/variantdbusstring.cc | 17 | ||||
-rw-r--r-- | glib/glibmm/variantdbusstring.h | 64 | ||||
-rw-r--r-- | glib/src/variant.ccg | 138 | ||||
-rw-r--r-- | glib/src/variant.hg | 171 | ||||
-rw-r--r-- | glib/src/varianttype.ccg | 2 | ||||
-rw-r--r-- | glib/src/varianttype.hg | 2 | ||||
-rw-r--r-- | 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 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: |