9#ifndef KASYNC_JOB_IMPL_H
10#define KASYNC_JOB_IMPL_H
22template<
typename Out,
typename ...
In>
23template<
typename ... InOther>
24Job<
Out,
In ...>::operator std::conditional_t<std::is_void<OutType>::value, IncompleteType, Job<void>> ()
26 return thenImpl<void, InOther ...>({JobContinuation<void, InOther ...>([](InOther ...){
return KAsync::null<void>(); })}, {});
29template<
typename Out,
typename ...
In>
30template<
typename OutOther,
typename ... InOther>
31Job<OutOther,
In ...> Job<Out, In ...>::thenImpl(Private::ContinuationHolder<OutOther, InOther ...> workHelper,
32 Private::ExecutionFlag execFlag)
const
34 thenInvariants<InOther ...>();
35 return Job<OutOther,
In ...>(
QSharedPointer<Private::Executor<OutOther, InOther ...>>::create(
36 std::forward<Private::ContinuationHolder<OutOther, InOther ...>>(workHelper), mExecutor, execFlag));
39template<
typename Out,
typename ...
In>
40template<
typename OutOther,
typename ... InOther>
41Job<OutOther,
In ...> Job<Out, In ...>::then(
const Job<OutOther, InOther ...> &job)
const
43 thenInvariants<InOther ...>();
44 auto executor = job.mExecutor;
45 executor->prepend(mExecutor);
46 return Job<OutOther,
In ...>(executor);
49template<
typename Out,
typename ...
In>
50Job<
Out,
In ...> Job<Out, In ...>::onError(SyncErrorContinuation<void> &&errorFunc)
const
55 Private::ContinuationHolder<Out, Out>([errorFunc = std::move(errorFunc)](
const Error &error,
const Out &val) {
58 }), mExecutor, Private::ExecutionFlag::ErrorCase));
62inline Job<void> Job<void>::onError(SyncErrorContinuation<void> &&errorFunc)
const
65 Private::ContinuationHolder<void>(std::forward<SyncErrorContinuation<void>>(errorFunc)),
66 mExecutor, Private::ExecutionFlag::ErrorCase));
69template<
typename Out,
typename ...
In>
70template<
typename FirstIn>
71KAsync::Future<Out> Job<Out, In ...>::exec(FirstIn in)
74 Private::ExecutorBasePtr first = mExecutor;
75 while (first->mPrev) {
80 Private::ContinuationHolder<FirstIn>([val = std::move(in)](Future<FirstIn> &future) {
81 future.setResult(val);
90template<
typename Out,
typename ...
In>
91KAsync::Future<Out> Job<Out, In ...>::exec()
93 Private::ExecutionPtr execution = mExecutor->exec(mExecutor, Private::ExecutionContext::Ptr::create());
94 KAsync::Future<Out> result = *execution->result<
Out>();
99template<
typename Out,
typename ...
In>
100Job<Out, In ...>::Job(Private::ExecutorBasePtr executor)
104template<
typename Out,
typename ...
In>
105Job<Out, In ...>::Job(JobContinuation<Out, In ...> &&func)
106 : JobBase(new Private::Executor<
Out,
In ...>(std::
forward<JobContinuation<
Out,
In ...>>(func), {}))
108 qWarning() <<
"Creating job job";
109 static_assert(
sizeof...(In) <= 1,
"Only one or zero input parameters are allowed.");
112template<
typename Out,
typename ...
In>
113template<
typename OutOther>
114void Job<Out, In ...>::eachInvariants()
const
116 static_assert(traits::isContainer<Out>::value,
117 "The 'Each' task can only be connected to a job that returns a list or an array.");
118 static_assert(std::is_void<OutOther>::value || traits::isContainer<OutOther>::value,
119 "The result type of 'Each' task must be void, a list or an array.");
122template<
typename Out,
typename ...
In>
123template<
typename InOtherFirst,
typename ... InOtherTail>
124void Job<Out, In ...>::thenInvariants()
const
126 static_assert(!std::is_void<Out>::value && (std::is_convertible<Out, InOtherFirst>::value || std::is_base_of<Out, InOtherFirst>::value),
127 "The return type of previous task must be compatible with input type of this task");
130template<
typename Out,
typename ...
In>
131template<
typename ... InOther>
132auto Job<Out, In ...>::thenInvariants() const -> std::enable_if_t<(sizeof...(InOther) == 0)>
136template<
template<
typename>
class Container>
137KAsync::Job<void> waitForCompletion(Container<KAsync::Future<void>> &futures)
140 void removeWatcher(KAsync::FutureWatcher<void> *w)
142 pending.erase(std::remove_if(pending.begin(), pending.end(), [w](
const auto &watcher) {
143 return w == watcher.get();
147 std::vector<std::unique_ptr<KAsync::FutureWatcher<void>>> pending;
151 return new Context();
153 .
template then<Context*, Context*>([futures](Context *context, KAsync::Future<Context *> &future) {
154 for (KAsync::Future<void> subFuture : futures) {
155 if (subFuture.isFinished()) {
159 auto watcher = std::make_unique<KAsync::FutureWatcher<void>>();
161 [&future, watcher = watcher.get(), context]() {
162 context->removeWatcher(watcher);
163 if (context->pending.empty()) {
164 future.setResult(context);
167 watcher->setFuture(subFuture);
168 context->pending.push_back(std::move(watcher));
170 if (context->pending.empty()) {
171 future.setResult(context);
174 .
template then<void, Context*>([](Context *context) {
180template<
typename List,
typename ValueType>
181Job<void, List>
forEach(KAsync::Job<void, ValueType> job)
183 auto cont = [job] (
const List &values)
mutable {
186 for (
const auto &v : values) {
188 .template then<void>([error] (
const KAsync::Error &e) {
197 return waitForCompletion(list)
198 .then<
void>([
error](KAsync::Future<void> &future) {
200 future.setError(*error);
202 future.setFinished();
206 return Job<void, List>(
QSharedPointer<Private::Executor<void, List>>::create(
207 Private::ContinuationHolder<void, List>(JobContinuation<void, List>(std::move(cont))),
nullptr, Private::ExecutionFlag::GoodCase));
211template<
typename List,
typename ValueType>
212Job<void, List> serialForEach(KAsync::Job<void, ValueType> job)
214 auto cont = [job] (
const List &values)
mutable {
216 auto serialJob = KAsync::null<void>();
217 for (
const auto &value : values) {
218 serialJob = serialJob.then<
void>([value, job,
error](KAsync::Future<void> &future) {
219 job.template then<void>([&future, error] (
const KAsync::Error &e) {
224 future.setFinished();
230 .then<
void>([
error](KAsync::Future<void> &future) {
232 future.setError(*error);
234 future.setFinished();
238 return Job<void, List>(
QSharedPointer<Private::Executor<void, List>>::create(
239 Private::ContinuationHolder<void, List>(JobContinuation<void, List>(std::move(cont))),
nullptr, Private::ExecutionFlag::GoodCase));
242template<
typename List,
typename ValueType>
243Job<void, List>
forEach(JobContinuation<void, ValueType> &&func)
245 return forEach<List, ValueType>(KAsync::start<void, ValueType>(std::forward<JobContinuation<void, ValueType>>(func)));
248template<
typename List,
typename ValueType>
249Job<void, List> serialForEach(JobContinuation<void, ValueType> &&func)
251 return serialForEach<List, ValueType>(KAsync::start<void, ValueType>(std::forward<JobContinuation<void, ValueType>>(func)));
254template<
typename Out>
257 return KAsync::start<Out>(
258 [](KAsync::Future<Out> &future) {
259 future.setFinished();
263template<
typename Out>
266 return KAsync::start<Out>(
267 [val = std::move(v)](KAsync::Future<Out> &future) {
268 future.setResult(val);
272template<
typename Out>
273Job<Out>
error(
int errorCode,
const QString &errorMessage)
278template<
typename Out>
279Job<Out>
error(
const char *message)
281 return error<Out>(
Error(message));
284template<
typename Out>
285Job<Out>
error(
const Error &error)
287 return KAsync::start<Out>(
288 [error](KAsync::Future<Out> &future) {
289 future.setError(error);
293inline Job<void> doWhile(
const Job<ControlFlowFlag> &body)
295 return KAsync::start<void>([body] (KAsync::Future<void> &future) {
296 auto job = body.then<void, ControlFlowFlag>([&future, body](
const KAsync::Error &
error, ControlFlowFlag flag) {
298 future.setError(error);
299 future.setFinished();
300 }
else if (flag == ControlFlowFlag::Continue) {
301 doWhile(body).then<
void>([&future](
const KAsync::Error &
error) {
303 future.setError(error);
305 future.setFinished();
308 future.setFinished();
314inline Job<void> doWhile(
const JobContinuation<ControlFlowFlag> &body)
316 return doWhile(KAsync::start<ControlFlowFlag>([body] {
321inline Job<void> wait(
int delay)
323 return KAsync::start<void>([delay](KAsync::Future<void> &future) {
325 future.setFinished();
Q_SCRIPTABLE Q_NOREPLY void start()
KCALUTILS_EXPORT QString errorMessage(const KCalendarCore::Exception &exception)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
const QList< QKeySequence > & forward()
void forEach(const typename Trait::template Vector< ItemType > &types, std::shared_ptr< Document< Trait > > doc, ItemFunctor< Trait > func, unsigned int maxNestingLevel=0)
void push_back(parameter_type value)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QSharedPointer< T > create(Args &&... args)