aboutsummaryrefslogtreecommitdiff
path: root/src/base/QXmppFutureUtils_p.h
blob: d109f74b6606bb075efd6e37ace8b3baebf28e6b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
 * Copyright (C) 2008-2021 The QXmpp developers
 *
 * Author:
 *  Linus Jahn
 *
 * Source:
 *  https://github.com/qxmpp-project/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 */

#ifndef QXMPPFUTUREUTILS_P_H
#define QXMPPFUTUREUTILS_P_H

//
//  W A R N I N G
//  -------------
//
// This file is not part of the QXmpp API.  This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//

#include <QXmppIq.h>

#include <memory>
#include <variant>

#include <QFutureWatcher>
#include <QObject>

namespace QXmpp::Private {

// helper for std::visit
template<class... Ts>
struct overloaded : Ts... {
    using Ts::operator()...;
};
// explicit deduction guide (not needed as of C++20)
template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;

template<typename T>
QFuture<T> makeReadyFuture(T &&value)
{
    QFutureInterface<T> interface(QFutureInterfaceBase::Started);
    interface.reportResult(value);
    interface.reportFinished();
    return interface.future();
}

template<typename Result, typename Input, typename Converter>
QFuture<Result> chain(QFuture<Input> &&source, QObject *context, Converter task)
{
    auto resultInterface = std::make_shared<QFutureInterface<Result>>(QFutureInterfaceBase::Started);

    auto *watcher = new QFutureWatcher<Input>(context);
    QObject::connect(watcher, &QFutureWatcherBase::finished, context, [=]() {
        resultInterface->reportResult(task(watcher->result()));
        resultInterface->reportFinished();
        watcher->deleteLater();
    });
    watcher->setFuture(source);
    return resultInterface->future();
}

template<typename Result, typename IqType, typename Input, typename Converter>
Result parseIq(Input &&sendResult, Converter convert)
{
    return std::visit(overloaded {
                          [convert { std::move(convert) }](const QDomElement &element) -> Result {
                              IqType iq;
                              iq.parse(element);
                              if (iq.type() == QXmppIq::Error) {
                                  return iq.error();
                              }
                              return convert(std::move(iq));
                          },
                          [](QXmpp::PacketState) -> Result {
                              using Error = QXmppStanza::Error;
                              return Error(Error::Wait, Error::UndefinedCondition,
                                           QStringLiteral("Couldn't send request: lost connection."));
                          },
                      },
                      sendResult);
}

template<typename Result, typename IqType, typename Input>
Result parseIq(Input &&sendResult)
{
    return parseIq<Result, IqType>(std::move(sendResult), [](IqType &&iq) {
        // no conversion
        return iq;
    });
}

template<typename Result, typename IqType, typename Input, typename Converter>
QFuture<Result> chainIq(QFuture<Input> &&input, QObject *context, Converter convert)
{
    return chain<Result>(std::move(input), context, [convert { std::move(convert) }](Input &&input) -> Result {
        return parseIq<Result, IqType>(std::move(input), convert);
    });
}

template<typename Result, typename IqType, typename Input>
QFuture<Result> chainIq(QFuture<Input> &&input, QObject *context)
{
    return chain<Result>(std::move(input), context, [](Input &&sendResult) {
        return parseIq<Result, IqType>(sendResult);
    });
}

}

#endif  // QXMPPFUTUREUTILS_P_H