diff options
author | David Redondo <[email protected]> | 2024-12-11 12:23:45 +0100 |
---|---|---|
committer | David Redondo <[email protected]> | 2024-12-13 19:04:27 +0100 |
commit | 11518e92c2b4c0586d4ec29e50676049981c4239 (patch) | |
tree | 589677f21d8dc27ece44ecb7f8d28df9e467e8fb | |
parent | 95f02adf756d1ae485f39a060c6f23a5af3f64ee (diff) |
Provide D-Bus de-/marshalling operators for std::tuple
Currently Qt provides only generic operators for pairs which can be used
generically for structs with two elements. A tuple is the natural fit
for dealing generically with structs that have more elements.
This can be helpful when wanting to make a one-of calls to APIs that
take or return such types or deferring to tuple marshalling without
having to write custom operators.
[ChangeLog][QtDBus][QDBusArgument] Added generic support for
marshalling and demarshalling D-Bus STRUCTs from/to std::tuple.
Change-Id: Id5cf49063c9b43ed68ad7821111376f6fa887a73
Reviewed-by: Thiago Macieira <[email protected]>
-rw-r--r-- | src/dbus/doc/src/dbus-adaptors.qdoc | 5 | ||||
-rw-r--r-- | src/dbus/qdbusargument.h | 20 | ||||
-rw-r--r-- | tests/auto/dbus/qdbusmarshall/common.h | 23 | ||||
-rw-r--r-- | tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp | 21 |
4 files changed, 67 insertions, 2 deletions
diff --git a/src/dbus/doc/src/dbus-adaptors.qdoc b/src/dbus/doc/src/dbus-adaptors.qdoc index e57cc095b98..2eb977081ce 100644 --- a/src/dbus/doc/src/dbus-adaptors.qdoc +++ b/src/dbus/doc/src/dbus-adaptors.qdoc @@ -295,8 +295,9 @@ Qt D-Bus provides template specializations for arrays and maps for use with Qt's \l{Container classes}{container classes}, such as QMap and QList, so it is not necessary to write the streaming - operator functions for those. For other types, and specially for - types implementing structures, the operators have to be explicitly + operator functions for those. For structures Qt provides generic + specializations mapping to and from \c std::tuple. In order to use + a custom type instead or for other types the operators have to be explicitly implemented. See the documentation for QDBusArgument for examples for diff --git a/src/dbus/qdbusargument.h b/src/dbus/qdbusargument.h index 70f6703d2f2..8370de74bb6 100644 --- a/src/dbus/qdbusargument.h +++ b/src/dbus/qdbusargument.h @@ -321,6 +321,26 @@ inline const QDBusArgument &operator>>(const QDBusArgument &arg, std::pair<T1, T return arg; } +template <typename... T> +QDBusArgument &operator<<(QDBusArgument &argument, const std::tuple<T...> &tuple) +{ + static_assert(std::tuple_size_v<std::tuple<T...>> != 0, "D-Bus doesn't allow empty structs"); + argument.beginStructure(); + std::apply([&argument](const auto &...elements) { (argument << ... << elements); }, tuple); + argument.endStructure(); + return argument; +} + +template <typename... T> +const QDBusArgument &operator>>(const QDBusArgument &argument, std::tuple<T...> &tuple) +{ + static_assert(std::tuple_size_v<std::tuple<T...>> != 0, "D-Bus doesn't allow empty structs"); + argument.beginStructure(); + std::apply([&argument](auto &...elements) { (argument >> ... >> elements); }, tuple); + argument.endStructure(); + return argument; +} + QT_END_NAMESPACE #endif // QT_NO_DBUS diff --git a/tests/auto/dbus/qdbusmarshall/common.h b/tests/auto/dbus/qdbusmarshall/common.h index 9a7c1e1553a..8f1ecad29de 100644 --- a/tests/auto/dbus/qdbusmarshall/common.h +++ b/tests/auto/dbus/qdbusmarshall/common.h @@ -160,6 +160,14 @@ void commonInit() qDBusRegisterMetaType<QList<MyVariantMapStruct> >(); qDBusRegisterMetaType<MyFileDescriptorStruct>(); qDBusRegisterMetaType<QList<MyFileDescriptorStruct> >(); + + qDBusRegisterMetaType<std::tuple<int>>(); + qDBusRegisterMetaType<std::tuple<QString>>(); + qDBusRegisterMetaType<std::tuple<QVariantMap>>(); + qDBusRegisterMetaType<std::tuple<QPoint>>(); + qDBusRegisterMetaType<std::tuple<std::tuple<int>>>(); + qDBusRegisterMetaType<std::tuple<QList<int>>>(); + qDBusRegisterMetaType<std::tuple<int, QString, QVariantMap>>(); } #ifdef USE_PRIVATE_CODE #include "private/qdbusintrospection_p.h" @@ -510,6 +518,21 @@ bool compareToArgument(const QDBusArgument &arg, const QVariant &v2) return compare<MyFileDescriptorStruct>(arg, v2); else if (id == qMetaTypeId<QList<MyFileDescriptorStruct> >()) return compare<QList<MyFileDescriptorStruct> >(arg, v2); + + else if (id == qMetaTypeId<std::tuple<int>>()) + return compare<std::tuple<int>>(arg, v2); + else if (id == qMetaTypeId<std::tuple<QString>>()) + return compare<std::tuple<QString>>(arg, v2); + else if (id == qMetaTypeId<std::tuple<QVariantMap>>()) + return compare<std::tuple<QVariantMap>>(arg, v2); + else if (id == qMetaTypeId<std::tuple<QPoint>>()) + return compare<std::tuple<QPoint>>(arg, v2); + else if (id == qMetaTypeId<std::tuple<std::tuple<int>>>()) + return compare<std::tuple<std::tuple<int>>>(arg, v2); + else if (id == qMetaTypeId<std::tuple<QList<int>>>()) + return compare<std::tuple<QList<int>>>(arg, v2); + else if (id == qMetaTypeId<std::tuple<int, QString, QVariantMap>>()) + return compare<std::tuple<int, QString, QVariantMap>>(arg, v2); } qWarning() << "Unexpected QVariant type" << v2.userType() diff --git a/tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp b/tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp index ea515536e6e..79db456cfbd 100644 --- a/tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp +++ b/tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp @@ -549,6 +549,27 @@ void tst_QDBusMarshall::sendStructs_data() list << mvms; QTest::newRow("list-of-string-variantmap") << QVariant::fromValue(list) << "a(sa{sv})" << "[Argument: a(sa{sv}) {[Argument: (sa{sv}) \"Hello, World\", [Argument: a{sv} {\"bytearray\" = [Variant(QByteArray): {72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100}], \"int\" = [Variant(int): 42], \"short\" = [Variant(short): -47], \"uint\" = [Variant(uint): 42]}]]}]"; + QTest::newRow("std::tuple<int>") + << QVariant::fromValue(std::tuple<int>{ 1 }) << "(i)" << "[Argument: (i) 1]"; + QTest::newRow("std::tuple<QString>") << QVariant::fromValue(std::tuple<QString>{ "foo" }) + << "(s)" << "[Argument: (s) \"foo\"]"; + QTest::newRow("std::tuple<QVariantMap>") + << QVariant::fromValue(std::tuple<QVariantMap>{ { { "foo", 1 } } }) << "(a{sv})" + << "[Argument: (a{sv}) [Argument: a{sv} {\"foo\" = [Variant(int): 1]}]]"; + QTest::newRow("std::tuple<QPoint>") << QVariant::fromValue(std::tuple<QPoint>{ { 1, 2 } }) + << "((ii))" << "[Argument: ((ii)) [Argument: (ii) 1, 2]]"; + QTest::newRow("std::tuple<std::tuple<int>>") + << QVariant::fromValue(std::tuple<std::tuple<int>>{ 1 }) << "((i))" + << "[Argument: ((i)) [Argument: (i) 1]]"; + QTest::newRow("std::tuple<QList<int>>") + << QVariant::fromValue(std::tuple<QList<int>>{ { 1, 2, 3 } }) << "(ai)" + << "[Argument: (ai) [Argument: ai {1, 2, 3}]]"; + QTest::newRow("std::tuple<int, QString, QVariantMap>") + << QVariant::fromValue( + std::tuple<int, QString, QVariantMap>{ 1, "foo", { { "bar", 2 } } }) + << "(isa{sv})" + << "[Argument: (isa{sv}) 1, \"foo\", [Argument: a{sv} {\"bar\" = [Variant(int): 2]}]]"; + if (fileDescriptorPassing) { MyFileDescriptorStruct fds; fds.fd = QDBusUnixFileDescriptor(fileDescriptorForTest()); |