1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qdbuspendingreply.h"
6#include "qdbuspendingcall_p.h"
7#include "qdbusmetatype.h"
8
9#include <QtCore/private/qlocking_p.h>
10
11#ifndef QT_NO_DBUS
12
13/*!
14 \class QDBusPendingReply
15 \inmodule QtDBus
16 \since 4.5
17
18 \brief The QDBusPendingReply class contains the reply to an asynchronous method call.
19
20 The QDBusPendingReply is a variadic template class. The template parameters
21 are the types that will be used to extract the contents of the reply's data.
22
23 This class is similar in functionality to QDBusReply, but with two
24 important differences:
25
26 \list
27 \li QDBusReply accepts exactly one return type, whereas
28 QDBusPendingReply can have any number of types
29 \li QDBusReply only works on already completed replies, whereas
30 QDBusPendingReply allows one to wait for replies from pending
31 calls
32 \endlist
33
34 Where with QDBusReply you would write:
35
36 \snippet code/src_qdbus_qdbusreply.cpp 0
37
38 with QDBusPendingReply, the equivalent code (including the blocking
39 wait for the reply) would be:
40
41 \snippet code/src_qdbus_qdbuspendingreply.cpp 0
42
43 For method calls that have more than one output argument, with
44 QDBusReply, you would write:
45
46 \snippet code/src_qdbus_qdbusreply.cpp 1
47
48 whereas with QDBusPendingReply, all of the output arguments should
49 be template parameters:
50
51 \snippet code/src_qdbus_qdbuspendingreply.cpp 2
52
53 QDBusPendingReply objects can be associated with
54 QDBusPendingCallWatcher objects, which emit signals when the reply
55 arrives.
56
57 \sa QDBusPendingCallWatcher, QDBusReply
58*/
59
60/*!
61 \fn template<typename... Types> QDBusPendingReply<Types...>::QDBusPendingReply()
62
63 Creates an empty QDBusPendingReply object. Without assigning a
64 QDBusPendingCall object to this reply, QDBusPendingReply cannot do
65 anything. All functions return their failure values.
66*/
67
68/*!
69 \fn template<typename... Types> QDBusPendingReply<Types...>::QDBusPendingReply(const QDBusPendingReply &other)
70
71 Creates a copy of the \a other QDBusPendingReply object. Just like
72 QDBusPendingCall and QDBusPendingCallWatcher, this QDBusPendingReply
73 object will share the same pending call reference. All copies
74 share the same return values.
75*/
76
77/*!
78 \fn template<typename... Types> QDBusPendingReply<Types...>::QDBusPendingReply(const QDBusPendingCall &call)
79
80 Creates a QDBusPendingReply object that will take its contents from
81 the \a call pending asynchronous call. This QDBusPendingReply object
82 will share the same pending call reference as \a call.
83*/
84
85/*!
86 \fn template<typename... Types> QDBusPendingReply<Types...>::QDBusPendingReply(const QDBusMessage &message)
87
88 Creates a QDBusPendingReply object that will take its contents from
89 the message \a message. In this case, this object will be already
90 in its finished state and the reply's contents will be accessible.
91
92 \sa isFinished()
93*/
94
95/*!
96 \fn template<typename... Types> QDBusPendingReply &QDBusPendingReply<Types...>::operator=(const QDBusPendingReply &other)
97
98 Makes a copy of \a other and drops the reference to the current
99 pending call. If the current reference is to an unfinished pending
100 call and this is the last reference, the pending call will be
101 canceled and there will be no way of retrieving the reply's
102 contents, when they arrive.
103*/
104
105/*!
106 \fn template<typename... Types> QDBusPendingReply &QDBusPendingReply<Types...>::operator=(const QDBusPendingCall &call)
107
108 Makes this object take its contents from the \a call pending call
109 and drops the reference to the current pending call. If the
110 current reference is to an unfinished pending call and this is the
111 last reference, the pending call will be canceled and there will
112 be no way of retrieving the reply's contents, when they arrive.
113*/
114
115/*!
116 \fn template<typename... Types> QDBusPendingReply &QDBusPendingReply<Types...>::operator=(const QDBusMessage &message)
117
118 Makes this object take its contents from the \a message message
119 and drops the reference to the current pending call. If the
120 current reference is to an unfinished pending call and this is the
121 last reference, the pending call will be canceled and there will
122 be no way of retrieving the reply's contents, when they arrive.
123
124 After this function is finished, the QDBusPendingReply object will
125 be in its "finished" state and the \a message contents will be
126 accessible.
127
128 \sa isFinished()
129*/
130
131/*!
132 \enum QDBusPendingReply::anonymous
133
134 \value Count The number of arguments the reply is expected to have
135 */
136
137/*!
138 \fn template<typename... Types> int QDBusPendingReply<Types...>::count() const
139
140 Return the number of arguments the reply is supposed to have. This
141 number matches the number of non-void template parameters in this
142 class.
143
144 If the reply arrives with a different number of arguments (or with
145 different types), it will be transformed into an error reply
146 indicating a bad signature.
147*/
148
149/*!
150 \fn template<typename... Types> QVariant QDBusPendingReply<Types...>::argumentAt(int index) const
151
152 Returns the argument at position \a index in the reply's
153 contents. If the reply doesn't have that many elements, this
154 function's return value is undefined (will probably cause an
155 assertion failure), so it is important to verify that the
156 processing is finished and the reply is valid.
157
158 If the reply does not contain an argument at position \a index or if the
159 reply was an error, this function returns an invalid QVariant. Since D-Bus
160 messages can never contain invalid QVariants, this return can be used to
161 detect an error condition.
162*/
163
164/*!
165 \fn template<typename... Types> typename Select<0>::Type QDBusPendingReply<Types...>::value() const
166
167 Returns the first argument in this reply, cast to type \c Types[0] (the
168 first template parameter of this class). This is equivalent to
169 calling argumentAt<0>().
170
171 This function is provided as a convenience, matching the
172 QDBusReply::value() function.
173
174 Note that, if the reply hasn't arrived, this function causes the
175 calling thread to block until the reply is processed.
176
177 If the reply is an error reply, this function returns a default-constructed
178 \c Types[0] object, which may be indistinguishable from a valid value. To
179 reliably determine whether the message was an error, use isError().
180*/
181
182/*!
183 \fn template<typename... Types> QDBusPendingReply<Types...>::operator typename Select<0>::Type() const
184
185 Returns the first argument in this reply, cast to type \c Types[0] (the
186 first template parameter of this class). This is equivalent to
187 calling argumentAt<0>().
188
189 This function is provided as a convenience, matching the
190 QDBusReply::value() function.
191
192 Note that, if the reply hasn't arrived, this function causes the
193 calling thread to block until the reply is processed.
194
195 If the reply is an error reply, this function returns a default-constructed
196 \c Types[0] object, which may be indistinguishable from a valid value. To
197 reliably determine whether the message was an error, use isError().
198*/
199
200/*!
201 \fn template<typename... Types> void QDBusPendingReply<Types...>::waitForFinished()
202
203 Suspends the execution of the calling thread until the reply is
204 received and processed. After this function returns, isFinished()
205 should return true, indicating the reply's contents are ready to
206 be processed.
207
208 \sa QDBusPendingCallWatcher::waitForFinished()
209*/
210
211QDBusPendingReplyBase::QDBusPendingReplyBase()
212 : QDBusPendingCall(nullptr) // initialize base class empty
213{
214}
215
216QDBusPendingReplyBase::~QDBusPendingReplyBase()
217{
218}
219
220void QDBusPendingReplyBase::assign(const QDBusPendingCall &other)
221{
222 QDBusPendingCall::operator=(other);
223}
224
225void QDBusPendingReplyBase::assign(const QDBusMessage &message)
226{
227 d = new QDBusPendingCallPrivate(QDBusMessage(), nullptr); // drops the reference to the old one
228 d->replyMessage = message;
229}
230
231QVariant QDBusPendingReplyBase::argumentAt(int index) const
232{
233 if (!d)
234 return QVariant();
235
236 d->waitForFinished(); // bypasses "const"
237
238 return d->replyMessage.arguments().value(i: index);
239}
240
241void QDBusPendingReplyBase::setMetaTypes(int count, const QMetaType *types)
242{
243 Q_ASSERT(d);
244 const auto locker = qt_scoped_lock(mutex&: d->mutex);
245 d->setMetaTypes(count, types);
246 d->checkReceivedSignature();
247}
248
249#endif // QT_NO_DBUS
250

source code of qtbase/src/dbus/qdbuspendingreply.cpp