summaryrefslogtreecommitdiffstats
path: root/common/clientapi.h
diff options
context:
space:
mode:
Diffstat (limited to 'common/clientapi.h')
-rw-r--r--common/clientapi.h196
1 files changed, 1 insertions, 195 deletions
diff --git a/common/clientapi.h b/common/clientapi.h
index 48177df..56247a7 100644
--- a/common/clientapi.h
+++ b/common/clientapi.h
@@ -24,212 +24,18 @@
24#include <QSet> 24#include <QSet>
25#include <QSharedPointer> 25#include <QSharedPointer>
26#include <QStandardPaths> 26#include <QStandardPaths>
27#include <QTimer>
28#include <QDebug> 27#include <QDebug>
29#include <QEventLoop> 28#include <QEventLoop>
30#include <QtConcurrent/QtConcurrentRun>
31#include <functional> 29#include <functional>
32#include <memory> 30#include <memory>
33#include "threadboundary.h" 31#include "threadboundary.h"
34#include "async/src/async.h" 32#include "async/src/async.h"
33#include "resultprovider.h"
35 34
36namespace async { 35namespace async {
37 //This should abstract if we execute from eventloop or in thread. 36 //This should abstract if we execute from eventloop or in thread.
38 //It supposed to allow the caller to finish the current method before executing the runner. 37 //It supposed to allow the caller to finish the current method before executing the runner.
39 void run(const std::function<void()> &runner); 38 void run(const std::function<void()> &runner);
40
41 /**
42 * Query result set
43 */
44
45 template<class T>
46 class ResultEmitter;
47
48 /*
49 * The promise side for the result emitter
50 */
51 template<class T>
52 class ResultProvider {
53 private:
54 void callInMainThreadOnEmitter(void (ResultEmitter<T>::*f)())
55 {
56 //We use the eventloop to call the addHandler directly from the main eventloop.
57 //That way the result emitter implementation doesn't have to care about threadsafety at all.
58 //The alternative would be to make all handlers of the emitter threadsafe.
59 if (auto emitter = mResultEmitter.toStrongRef()) {
60 auto weakEmitter = mResultEmitter;
61 //We don't want to keep the emitter alive here, so we only capture a weak reference
62 emitter->mThreadBoundary.callInMainThread([weakEmitter, f]() {
63 if (auto strongRef = weakEmitter.toStrongRef()) {
64 (strongRef.data()->*f)();
65 }
66 });
67 }
68 }
69
70 void callInMainThreadOnEmitter(const std::function<void()> &f)
71 {
72 //We use the eventloop to call the addHandler directly from the main eventloop.
73 //That way the result emitter implementation doesn't have to care about threadsafety at all.
74 //The alternative would be to make all handlers of the emitter threadsafe.
75 if (auto emitter = mResultEmitter.toStrongRef()) {
76 emitter->mThreadBoundary.callInMainThread([f]() {
77 f();
78 });
79 }
80 }
81
82 public:
83 //Called from worker thread
84 void add(const T &value)
85 {
86 //Because I don't know how to use bind
87 auto weakEmitter = mResultEmitter;
88 callInMainThreadOnEmitter([weakEmitter, value](){
89 if (auto strongRef = weakEmitter.toStrongRef()) {
90 strongRef->addHandler(value);
91 }
92 });
93 }
94
95 void initialResultSetComplete()
96 {
97 callInMainThreadOnEmitter(&ResultEmitter<T>::initialResultSetComplete);
98 }
99
100 //Called from worker thread
101 void complete()
102 {
103 callInMainThreadOnEmitter(&ResultEmitter<T>::complete);
104 }
105
106 void clear()
107 {
108 callInMainThreadOnEmitter(&ResultEmitter<T>::clear);
109 }
110
111
112 QSharedPointer<ResultEmitter<T> > emitter()
113 {
114 if (!mResultEmitter) {
115 //We have to go over a separate var and return that, otherwise we'd delete the emitter immediately again
116 auto sharedPtr = QSharedPointer<ResultEmitter<T> >(new ResultEmitter<T>, [this](ResultEmitter<T> *emitter){ done(); delete emitter; });
117 mResultEmitter = sharedPtr;
118 return sharedPtr;
119 }
120
121 return mResultEmitter.toStrongRef();
122 }
123
124 /**
125 * For lifetimemanagement only.
126 * We keep the runner alive as long as the result provider exists.
127 */
128 void setQueryRunner(const QSharedPointer<QObject> &runner)
129 {
130 mQueryRunner = runner;
131 }
132
133 /**
134 * For lifetimemanagement only.
135 * We keep the runner alive as long as the result provider exists.
136 */
137 void setFacade(const std::shared_ptr<void> &facade)
138 {
139 mFacade = facade;
140 }
141
142 void onDone(const std::function<void()> &callback)
143 {
144 mOnDoneCallback = callback;
145 }
146
147 bool isDone() const
148 {
149 //The existance of the emitter currently defines wether we're done or not.
150 return mResultEmitter.toStrongRef().isNull();
151 }
152
153 private:
154 void done()
155 {
156 qWarning() << "done";
157 if (mOnDoneCallback) {
158 mOnDoneCallback();
159 mOnDoneCallback = std::function<void()>();
160 }
161 }
162
163 QWeakPointer<ResultEmitter<T> > mResultEmitter;
164 QSharedPointer<QObject> mQueryRunner;
165 std::shared_ptr<void> mFacade;
166 std::function<void()> mOnDoneCallback;
167 };
168
169 /*
170 * The future side for the client.
171 *
172 * It does not directly hold the state.
173 *
174 * The advantage of this is that we can specialize it to:
175 * * do inline transformations to the data
176 * * directly store the state in a suitable datastructure: QList, QSet, std::list, QVector, ...
177 * * build async interfaces with signals
178 * * build sync interfaces that block when accessing the value
179 *
180 */
181 template<class DomainType>
182 class ResultEmitter {
183 public:
184 void onAdded(const std::function<void(const DomainType&)> &handler)
185 {
186 addHandler = handler;
187 }
188 // void onRemoved(const std::function<void(const T&)> &handler);
189 void onInitialResultSetComplete(const std::function<void(void)> &handler)
190 {
191 initialResultSetCompleteHandler = handler;
192 }
193 void onComplete(const std::function<void(void)> &handler)
194 {
195 completeHandler = handler;
196 }
197 void onClear(const std::function<void(void)> &handler)
198 {
199 clearHandler = handler;
200 }
201
202 void add(const DomainType &value)
203 {
204 addHandler(value);
205 }
206
207 void initialResultSetComplete()
208 {
209 initialResultSetCompleteHandler();
210 }
211
212 void complete()
213 {
214 completeHandler();
215 }
216
217 void clear()
218 {
219 clearHandler();
220 }
221
222 private:
223 friend class ResultProvider<DomainType>;
224
225 std::function<void(const DomainType&)> addHandler;
226 // std::function<void(const T&)> removeHandler;
227 std::function<void(void)> initialResultSetCompleteHandler;
228 std::function<void(void)> completeHandler;
229 std::function<void(void)> clearHandler;
230 ThreadBoundary mThreadBoundary;
231 };
232
233} 39}
234 40
235namespace Akonadi2 { 41namespace Akonadi2 {