1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtDBus module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QDBUSPENDINGREPLY_H
41 #define QDBUSPENDINGREPLY_H
42 
43 #include <QtDBus/qtdbusglobal.h>
44 #include <QtDBus/qdbusargument.h>
45 #include <QtDBus/qdbuspendingcall.h>
46 
47 #ifndef QT_NO_DBUS
48 
49 QT_BEGIN_NAMESPACE
50 
51 
52 class Q_DBUS_EXPORT QDBusPendingReplyData: public QDBusPendingCall
53 {
54 protected:
55     QDBusPendingReplyData();
56     ~QDBusPendingReplyData();
57     void assign(const QDBusPendingCall &call);
58     void assign(const QDBusMessage &message);
59 
60     QVariant argumentAt(int index) const;
61     void setMetaTypes(int count, const int *metaTypes);
62 };
63 
64 namespace QDBusPendingReplyTypes {
65     template<int Index,
66              typename T1, typename T2, typename T3, typename T4,
67              typename T5, typename T6, typename T7, typename T8>
68     struct Select
69     {
70         typedef Select<Index - 1, T2, T3, T4, T5, T6, T7, T8, void> Next;
71         typedef typename Next::Type Type;
72     };
73     template<typename T1, typename T2, typename T3, typename T4,
74              typename T5, typename T6, typename T7, typename T8>
75     struct Select<0, T1, T2, T3, T4, T5, T6, T7, T8>
76     {
77         typedef T1 Type;
78     };
79 
80     template<typename T1> inline int metaTypeFor(T1 * = nullptr)
81     { return qMetaTypeId<T1>(); }
82     // specialize for QVariant, allowing it to be used in place of QDBusVariant
83     template<> inline int metaTypeFor<QVariant>(QVariant *)
84     { return qMetaTypeId<QDBusVariant>(); }
85 
86     template<typename T1, typename T2, typename T3, typename T4,
87              typename T5, typename T6, typename T7, typename T8>
88     struct ForEach
89     {
90         typedef ForEach<T2, T3, T4, T5, T6, T7, T8, void> Next;
91         enum { Total = Next::Total + 1 };
92         static inline void fillMetaTypes(int *p)
93         {
94             *p = metaTypeFor<T1>(nullptr);
95             Next::fillMetaTypes(++p);
96         }
97     };
98     template<>
99     struct ForEach<void, void, void, void,   void, void, void, void>
100     {
101         enum { Total = 0 };
102         static inline void fillMetaTypes(int *)
103         { }
104     };
105 
106     struct TypeIsVoid {};
107     template <typename T> struct NotVoid       { typedef T Type; };
108     template <>           struct NotVoid<void> { typedef TypeIsVoid Type; };
109 } // namespace QDBusPendingReplyTypes
110 
111 template<typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void,
112          typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void>
113 class QDBusPendingReply:
114 #ifdef Q_CLANG_QDOC
115     public QDBusPendingCall
116 #else
117     public QDBusPendingReplyData
118 #endif
119 {
120     typedef QDBusPendingReplyTypes::ForEach<T1, T2, T3, T4, T5, T6, T7, T8> ForEach;
121     template<int Index> struct Select :
122     QDBusPendingReplyTypes::Select<Index, T1, T2, T3, T4, T5, T6, T7, T8>
123     {
124     };
125 
126 public:
127     enum { Count = ForEach::Total };
128 
129     inline QDBusPendingReply()
130     { }
131     inline QDBusPendingReply(const QDBusPendingReply &other)
132         : QDBusPendingReplyData(other)
133     { }
134     inline /*implicit*/ QDBusPendingReply(const QDBusPendingCall &call) // required by qdbusxml2cpp-generated code
135     { *this = call; }
136     inline /*implicit*/ QDBusPendingReply(const QDBusMessage &message)
137     { *this = message; }
138     inline QDBusPendingReply &operator=(const QDBusPendingReply &other)
139     { assign(other); return *this; }
140     inline QDBusPendingReply &operator=(const QDBusPendingCall &call)
141     { assign(call); return *this; }
142     inline QDBusPendingReply &operator=(const QDBusMessage &message)
143     { assign(message); return *this; }
144 
145     inline int count() const { return Count; }
146 
147 #if defined(Q_CLANG_QDOC)
148     QVariant argumentAt(int index) const;
149 #else
150     using QDBusPendingReplyData::argumentAt;
151 #endif
152 
153 #ifndef Q_CLANG_QDOC
154     template<int Index> inline
155     const typename Select<Index>::Type argumentAt() const
156     {
157         Q_STATIC_ASSERT_X(Index >= 0 && Index < Count, "Index out of bounds");
158         typedef typename Select<Index>::Type ResultType;
159         return qdbus_cast<ResultType>(argumentAt(Index), nullptr);
160     }
161 #endif
162 
163 #if defined(Q_CLANG_QDOC)
164     bool isFinished() const;
165     void waitForFinished();
166 
167     bool isValid() const;
168     bool isError() const;
169     QDBusError error() const;
170     QDBusMessage reply() const;
171 
172     inline T1 value() const;
173     inline operator T1() const;
174 #else
175     inline typename Select<0>::Type value() const
176     {
177         return argumentAt<0>();
178     }
179 
180     inline operator typename QDBusPendingReplyTypes::NotVoid<T1>::Type() const
181     {
182         return argumentAt<0>();
183     }
184 #endif
185 
186 private:
187     inline void calculateMetaTypes()
188     {
189         if (!d) return;
190         int typeIds[Count > 0 ? Count : 1]; // use at least one since zero-sized arrays aren't valid
191         ForEach::fillMetaTypes(typeIds);
192         setMetaTypes(Count, typeIds);
193     }
194 
195     inline void assign(const QDBusPendingCall &call)
196     {
197         QDBusPendingReplyData::assign(call);
198         calculateMetaTypes();
199     }
200 
201     inline void assign(const QDBusMessage &message)
202     {
203         QDBusPendingReplyData::assign(message);
204         calculateMetaTypes();
205     }
206 };
207 
208 QT_END_NAMESPACE
209 
210 #endif // QT_NO_DBUS
211 #endif
212