QXmpp Version: 1.11.3
Loading...
Searching...
No Matches
QXmppAsync_p.h
1// SPDX-FileCopyrightText: 2021 Linus Jahn <lnj@kaidan.im>
2//
3// SPDX-License-Identifier: LGPL-2.1-or-later
4
5#ifndef QXMPPASYNC_P_H
6#define QXMPPASYNC_P_H
7
8#include "QXmppPromise.h"
9#include "QXmppVisitHelper_p.h"
10
11class QDomElement;
12class QXmppError;
13
14namespace QXmpp::Private {
15
16// first argument of function
17template<typename F, typename Ret, typename A, typename... Rest>
18A lambda_helper(Ret (F::*)(A, Rest...));
19
20template<typename F, typename Ret, typename A, typename... Rest>
21A lambda_helper(Ret (F::*)(A, Rest...) const);
22
23template<typename F>
24struct first_argument {
25 using type = decltype(lambda_helper(&F::operator()));
26};
27
28template<typename F>
29using first_argument_t = typename first_argument<F>::type;
30
31// creates a task in finished state with value
32template<typename T>
33QXmppTask<T> makeReadyTask(T &&value)
34{
35 QXmppPromise<T> promise;
36 promise.finish(std::move(value));
37 return promise.task();
38}
39
40inline QXmppTask<void> makeReadyTask()
41{
42 QXmppPromise<void> promise;
43 promise.finish();
44 return promise.task();
45}
46
47// creates new task which converts the result of the first
48template<typename Result, typename Input, typename Converter>
49auto chain(QXmppTask<Input> &&source, QObject *context, Converter convert) -> QXmppTask<Result>
50{
52 auto task = promise.task();
53 if constexpr (std::is_void_v<Input>) {
54 source.then(context, [p = std::move(promise), convert = std::move(convert)]() mutable {
55 if constexpr (std::is_void_v<Result>) {
56 convert();
57 p.finish();
58 } else {
59 p.finish(convert());
60 }
61 });
62 } else {
63 source.then(context, [p = std::move(promise), convert = std::move(convert)](Input &&input) mutable {
64 if constexpr (std::is_void_v<Result>) {
65 convert(std::move(input));
66 p.finish();
67 } else {
68 p.finish(convert(std::move(input)));
69 }
70 });
71 }
72 return task;
73}
74
75// parse Iq type from QDomElement or pass error
76template<typename IqType, typename Input, typename Converter>
77auto parseIq(Input &&sendResult, Converter convert) -> decltype(convert({}))
78{
79 using Result = decltype(convert({}));
80 return std::visit(overloaded {
81 [convert = std::move(convert)](const QDomElement &element) -> Result {
82 IqType iq;
83 iq.parse(element);
84 return convert(std::move(iq));
85 },
86 [](QXmppError &&error) -> Result {
87 return error;
88 },
89 },
90 std::move(sendResult));
91}
92
93template<typename IqType, typename Result, typename Input>
94auto parseIq(Input &&sendResult) -> Result
95{
96 return parseIq<IqType>(std::move(sendResult), [](IqType &&iq) -> Result {
97 // no conversion
98 return iq;
99 });
100}
101
102// chain sendIq() task and parse DOM element to IQ type of first parameter of convert function
103template<typename Input, typename Converter>
104auto chainIq(QXmppTask<Input> &&input, QObject *context, Converter convert) -> QXmppTask<decltype(convert({}))>
105{
106 using Result = decltype(convert({}));
107 using IqType = std::decay_t<first_argument_t<Converter>>;
108 return chain<Result>(std::move(input), context, [convert = std::move(convert)](Input &&input) -> Result {
109 return parseIq<IqType>(std::move(input), convert);
110 });
111}
112
113// chain sendIq() task and parse DOM element to first type of Result variant
114template<typename Result, typename Input>
115auto chainIq(QXmppTask<Input> &&input, QObject *context) -> QXmppTask<Result>
116{
117 // IQ type is first std::variant parameter
118 using IqType = std::decay_t<decltype(std::get<0>(Result {}))>;
119 return chain<Result>(std::move(input), context, [](Input &&sendResult) mutable {
120 return parseIq<IqType, Result>(sendResult);
121 });
122}
123
124} // namespace QXmpp::Private
125
126#endif // QXMPPASYNC_P_H
Create and update QXmppTask objects to communicate results of asynchronous operations.
Definition QXmppPromise.h:23
QXmppTask< T > task()
Definition QXmppPromise.h:86
Definition QXmppTask.h:46
Definition QXmppError.h:17