1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #ifndef QDBUSPENDINGREPLY_H |
5 | #define QDBUSPENDINGREPLY_H |
6 | |
7 | #include <QtDBus/qtdbusglobal.h> |
8 | #include <QtDBus/qdbusargument.h> |
9 | #include <QtDBus/qdbuspendingcall.h> |
10 | |
11 | #ifndef QT_NO_DBUS |
12 | |
13 | QT_BEGIN_NAMESPACE |
14 | |
15 | |
16 | class Q_DBUS_EXPORT QDBusPendingReplyBase : public QDBusPendingCall |
17 | { |
18 | protected: |
19 | QDBusPendingReplyBase(); |
20 | ~QDBusPendingReplyBase(); |
21 | void assign(const QDBusPendingCall &call); |
22 | void assign(const QDBusMessage &message); |
23 | |
24 | QVariant argumentAt(int index) const; |
25 | void setMetaTypes(int count, const QMetaType *metaTypes); |
26 | }; |
27 | |
28 | namespace QDBusPendingReplyTypes { |
29 | template<int Index, typename T, typename... Types> |
30 | struct Select |
31 | { |
32 | typedef Select<Index - 1, Types...> Next; |
33 | typedef typename Next::Type Type; |
34 | }; |
35 | template<typename T, typename... Types> |
36 | struct Select<0, T, Types...> |
37 | { |
38 | typedef T Type; |
39 | }; |
40 | |
41 | template<typename T> inline QMetaType metaTypeFor() |
42 | { return QMetaType::fromType<T>(); } |
43 | // specialize for QVariant, allowing it to be used in place of QDBusVariant |
44 | template<> inline QMetaType metaTypeFor<QVariant>() |
45 | { return QMetaType::fromType<QDBusVariant>(); } |
46 | } |
47 | |
48 | |
49 | template<typename... Types> |
50 | class QDBusPendingReply : public QDBusPendingReplyBase |
51 | { |
52 | template<int Index> using Select = QDBusPendingReplyTypes::Select<Index, Types...>; |
53 | public: |
54 | enum { Count = std::is_same_v<typename Select<0>::Type, void> ? 0 : sizeof...(Types) }; |
55 | |
56 | inline constexpr int count() const { return Count; } |
57 | |
58 | |
59 | inline QDBusPendingReply() = default; |
60 | inline QDBusPendingReply(const QDBusPendingReply &other) |
61 | : QDBusPendingReplyBase(other) |
62 | { } |
63 | inline Q_IMPLICIT QDBusPendingReply(const QDBusPendingCall &call) // required by qdbusxml2cpp-generated code |
64 | { *this = call; } |
65 | inline Q_IMPLICIT QDBusPendingReply(const QDBusMessage &message) |
66 | { *this = message; } |
67 | |
68 | inline QDBusPendingReply &operator=(const QDBusPendingReply &other) |
69 | { assign(other); return *this; } |
70 | inline QDBusPendingReply &operator=(const QDBusPendingCall &call) |
71 | { assign(call); return *this; } |
72 | inline QDBusPendingReply &operator=(const QDBusMessage &message) |
73 | { assign(message); return *this; } |
74 | |
75 | using QDBusPendingReplyBase::argumentAt; |
76 | template<int Index> inline |
77 | typename Select<Index>::Type argumentAt() const |
78 | { |
79 | static_assert(Index >= 0 && Index < Count, "Index out of bounds" ); |
80 | typedef typename Select<Index>::Type ResultType; |
81 | return qdbus_cast<ResultType>(argumentAt(Index)); |
82 | } |
83 | |
84 | #if defined(Q_QDOC) |
85 | bool isFinished() const; |
86 | void waitForFinished(); |
87 | QVariant argumentAt(int index) const; |
88 | |
89 | bool isValid() const; |
90 | bool isError() const; |
91 | QDBusError error() const; |
92 | QDBusMessage reply() const; |
93 | #endif |
94 | |
95 | inline typename Select<0>::Type value() const |
96 | { |
97 | return argumentAt<0>(); |
98 | } |
99 | |
100 | inline operator typename Select<0>::Type() const |
101 | { |
102 | return argumentAt<0>(); |
103 | } |
104 | |
105 | private: |
106 | inline void calculateMetaTypes() |
107 | { |
108 | if (!d) return; |
109 | if constexpr (Count == 0) { |
110 | setMetaTypes(count: 0, metaTypes: nullptr); |
111 | } else { |
112 | std::array<QMetaType, Count> typeIds = { QDBusPendingReplyTypes::metaTypeFor<Types>()... }; |
113 | setMetaTypes(count: Count, metaTypes: typeIds.data()); |
114 | } |
115 | } |
116 | |
117 | inline void assign(const QDBusPendingCall &call) |
118 | { |
119 | QDBusPendingReplyBase::assign(call); |
120 | calculateMetaTypes(); |
121 | } |
122 | |
123 | inline void assign(const QDBusMessage &message) |
124 | { |
125 | QDBusPendingReplyBase::assign(message); |
126 | calculateMetaTypes(); |
127 | } |
128 | }; |
129 | |
130 | template<> |
131 | class QDBusPendingReply<> : public QDBusPendingReplyBase |
132 | { |
133 | public: |
134 | enum { Count = 0 }; |
135 | inline int count() const { return Count; } |
136 | |
137 | inline QDBusPendingReply() = default; |
138 | inline QDBusPendingReply(const QDBusPendingReply &other) |
139 | : QDBusPendingReplyBase(other) |
140 | { } |
141 | inline Q_IMPLICIT QDBusPendingReply(const QDBusPendingCall &call) // required by qdbusxml2cpp-generated code |
142 | { *this = call; } |
143 | inline Q_IMPLICIT QDBusPendingReply(const QDBusMessage &message) |
144 | { *this = message; } |
145 | |
146 | inline QDBusPendingReply &operator=(const QDBusPendingReply &other) |
147 | { assign(call: other); return *this; } |
148 | inline QDBusPendingReply &operator=(const QDBusPendingCall &call) |
149 | { assign(call); return *this; } |
150 | inline QDBusPendingReply &operator=(const QDBusMessage &message) |
151 | { assign(message); return *this; } |
152 | |
153 | private: |
154 | inline void assign(const QDBusPendingCall &call) |
155 | { |
156 | QDBusPendingReplyBase::assign(call); |
157 | if (d) |
158 | setMetaTypes(count: 0, metaTypes: nullptr); |
159 | } |
160 | |
161 | inline void assign(const QDBusMessage &message) |
162 | { |
163 | QDBusPendingReplyBase::assign(message); |
164 | if (d) |
165 | setMetaTypes(count: 0, metaTypes: nullptr); |
166 | } |
167 | |
168 | }; |
169 | |
170 | QT_END_NAMESPACE |
171 | |
172 | #endif // QT_NO_DBUS |
173 | #endif |
174 | |