QXmpp Version: 1.11.3
Loading...
Searching...
No Matches
QXmppXmlTags_p.h
1// SPDX-FileCopyrightText: 2025 Linus Jahn <lnj@kaidan.im>
2//
3// SPDX-License-Identifier: LGPL-2.1-or-later
4
5#ifndef QXMPPXMLTAGS_P_H
6#define QXMPPXMLTAGS_P_H
7
8#include <tuple>
9
10#include <QStringView>
11
12namespace QXmpp::Private {
13
14template<typename Name, std::convertible_to<QStringView> Xmlns>
15struct Tag {
16 Name name;
17 Xmlns xmlns;
18
19 using NameType = Name;
20 using XmlnsType = Xmlns;
21
22 Tag(Name name, Xmlns xmlns)
23 : name(std::forward<Name>(name)), xmlns(std::forward<Xmlns>(xmlns)) { }
24
25 template<typename N, typename X>
26 Tag(std::tuple<N, X> &&t) : name(std::get<0>(t)), xmlns(std::get<1>(t)) { }
27 template<typename N, typename X>
28 Tag(const std::tuple<N, X> &t) : name(std::get<0>(t)), xmlns(std::get<1>(t)) { }
29};
30
31template<size_t N, std::convertible_to<QStringView> Xmlns>
32Tag(const char16_t (&str)[N], Xmlns &&) -> Tag<QStringView, Xmlns>;
33
34template<typename Name, std::convertible_to<QStringView> Xmlns>
35Tag(Name &&, Xmlns &&) -> Tag<Name, Xmlns>;
36
37template<typename Name, typename Xmlns>
38Tag(std::tuple<Name, Xmlns> &&) -> Tag<Name, Xmlns>;
39
40template<typename T>
41concept IsXmlTag =
42 std::is_convertible_v<T, Tag<QStringView, QStringView>> || requires() {
43 typename T::NameType;
44 typename T::XmlnsType;
45 requires std::same_as<std::remove_cvref_t<T>, Tag<typename T::NameType, typename T::XmlnsType>>;
46 };
47
48template<typename T>
49concept HasXmlTag =
50 !std::is_void_v<T> &&
51 requires { { T::XmlTag }; } &&
52 IsXmlTag<decltype(T::XmlTag)>;
53
54template<typename T>
55concept HasPayloadXmlTagDirect =
56 requires { { T::PayloadXmlTag }; } &&
57 IsXmlTag<decltype(T::PayloadXmlTag)>;
58
59template<typename T>
60concept HasPayloadXmlTagIndirect =
61 requires { typename T::PayloadType; } &&
62 IsXmlTag<decltype(T::PayloadType::XmlTag)>;
63
64template<typename T>
65concept HasPayloadXmlTag = HasPayloadXmlTagDirect<T> || HasPayloadXmlTagIndirect<T>;
66
67template<HasPayloadXmlTag T>
68constexpr auto PayloadXmlTag = [] {
69 if constexpr (HasPayloadXmlTagIndirect<T>) {
70 return T::PayloadType::XmlTag;
71 } else if constexpr (HasPayloadXmlTagDirect<T>) {
72 return T::PayloadXmlTag;
73 }
74}();
75
76template<typename T>
77concept HasCustomCheckIqType =
78 requires(const QString &s1, const QString &s2) {
79 { T::checkIqType(s1, s2) } -> std::convertible_to<bool>;
80 };
81
82template<typename T, IsXmlTag Tag>
83bool isPayloadType(Tag xmlTag)
84{
85 static_assert(
86 Private::HasPayloadXmlTag<T> || HasCustomCheckIqType<T>,
87 "T must offer PayloadXmlTag, PayloadType::XmlTag or checkIqType()");
88
89 if constexpr (Private::HasPayloadXmlTag<T>) {
90 return xmlTag == Private::PayloadXmlTag<T>;
91 } else if constexpr (HasCustomCheckIqType<T>) {
92 static_assert(std::convertible_to<std::tuple_element_t<0, Tag>, QString>);
93 static_assert(std::convertible_to<std::tuple_element_t<1, Tag>, QString>);
94
95 auto &[name, xmlns] = xmlTag;
96 return T::checkIqType(name, xmlns);
97 }
98}
99
100} // namespace QXmpp::Private
101
102#endif // QXMPPXMLTAGS_P_H