QXmpp Version: 1.14.1
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// Attaches to existing promise
48template<typename Result, typename Input, typename Converter>
49auto chain(QXmppTask<Input> &&source, QObject *context, QXmppPromise<Result> &&p, Converter convert)
50{
51 if constexpr (std::is_void_v<Input>) {
52 source.then(context, [p = std::move(p), convert = std::move(convert)]() mutable {
53 if constexpr (std::is_void_v<Result>) {
54 convert();
55 p.finish();
56 } else {
57 p.finish(convert());
58 }
59 });
60 } else {
61 source.then(context, [p = std::move(p), convert = std::move(convert)](Input &&input) mutable {
62 if constexpr (std::is_void_v<Result>) {
63 convert(std::move(input));
64 p.finish();
65 } else {
66 p.finish(convert(std::move(input)));
67 }
68 });
69 }
70}
71
72// creates new task which converts the result of the first
73template<typename Result, typename Input, typename Converter>
74auto chain(QXmppTask<Input> &&source, QObject *context, Converter convert) -> QXmppTask<Result>
75{
76 QXmppPromise<Result> p;
77 auto task = p.task();
78 if constexpr (std::is_void_v<Input>) {
79 source.then(context, [p = std::move(p), convert = std::move(convert)]() mutable {
80 if constexpr (std::is_void_v<Result>) {
81 convert();
82 p.finish();
83 } else {
84 p.finish(convert());
85 }
86 });
87 } else {
88 source.then(context, [p = std::move(p), convert = std::move(convert)](Input &&input) mutable {
89 if constexpr (std::is_void_v<Result>) {
90 convert(std::move(input));
91 p.finish();
92 } else {
93 p.finish(convert(std::move(input)));
94 }
95 });
96 }
97 return task;
98}
99
100// parse Iq type from QDomElement or pass error
101template<typename IqType, typename Input, typename Converter>
102auto parseIq(Input &&sendResult, Converter convert) -> decltype(convert({}))
103{
104 using Result = decltype(convert({}));
105 return std::visit(overloaded {
106 [convert = std::move(convert)](const QDomElement &element) -> Result {
107 IqType iq;
108 iq.parse(element);
109 return convert(std::move(iq));
110 },
111 [](QXmppError &&error) -> Result {
112 return error;
113 },
114 },
115 std::move(sendResult));
116}
117
118template<typename IqType, typename Result, typename Input>
119auto parseIq(Input &&sendResult) -> Result
120{
121 return parseIq<IqType>(std::move(sendResult), [](IqType &&iq) -> Result {
122 // no conversion
123 return iq;
124 });
125}
126
127// chain sendIq() task and parse DOM element to IQ type of first parameter of convert function
128template<typename Input, typename Converter>
129auto chainIq(QXmppTask<Input> &&input, QObject *context, Converter convert) -> QXmppTask<decltype(convert({}))>
130{
131 using Result = decltype(convert({}));
132 using IqType = std::decay_t<first_argument_t<Converter>>;
133 return chain<Result>(std::move(input), context, [convert = std::move(convert)](Input &&input) -> Result {
134 return parseIq<IqType>(std::move(input), convert);
135 });
136}
137
138// chain sendIq() task and parse DOM element to first type of Result variant
139template<typename Result, typename Input>
140auto chainIq(QXmppTask<Input> &&input, QObject *context) -> QXmppTask<Result>
141{
142 // IQ type is first std::variant parameter
143 using IqType = std::decay_t<decltype(getValue(Result {}))>;
144 return chain<Result>(std::move(input), context, [](Input &&sendResult) mutable {
145 return parseIq<IqType, Result>(sendResult);
146 });
147}
148
149} // namespace QXmpp::Private
150
151#endif // QXMPPASYNC_P_H
QXmppTask< T > task()
Definition QXmppPromise.h:86
const T & getValue(const Result< T > &r)
Definition QXmppGlobal.h:232
Definition QXmppError.h:17