1 | // Copyright (C) 2017 Lorenz Haas |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include "qmqtttopicname.h" |
5 | |
6 | #include <QtCore/QDebug> |
7 | |
8 | QT_BEGIN_NAMESPACE |
9 | |
10 | /*! |
11 | \class QMqttTopicName |
12 | \inmodule QtMqtt |
13 | \reentrant |
14 | \ingroup shared |
15 | |
16 | \brief The QMqttTopicName class represents a MQTT topic name. |
17 | |
18 | QMqttTopicName is a thin wrapper around a QString providing an expressive |
19 | data type for MQTT topic names. Beside the benefits of having a strong type |
20 | preventing unintended misuse, QMqttTopicName provides convenient functions |
21 | related to topic names like isValid() or levels(). |
22 | |
23 | \sa QMqttTopicFilter |
24 | */ |
25 | |
26 | /*! |
27 | \fn void QMqttTopicName::swap(QMqttTopicName &other) |
28 | Swaps the MQTT topic name \a other with this MQTT topic name. This |
29 | operation is very fast and never fails. |
30 | */ |
31 | |
32 | class QMqttTopicNamePrivate : public QSharedData |
33 | { |
34 | public: |
35 | QString name; |
36 | }; |
37 | |
38 | /*! |
39 | Creates a new MQTT topic name with the specified \a name. |
40 | */ |
41 | QMqttTopicName::QMqttTopicName(const QString &name) : d(new QMqttTopicNamePrivate) |
42 | { |
43 | d->name = name; |
44 | } |
45 | |
46 | /*! |
47 | Creates a new MQTT topic name with the specified \a name. |
48 | */ |
49 | QMqttTopicName::QMqttTopicName(const QLatin1String &name) : d(new QMqttTopicNamePrivate) |
50 | { |
51 | d->name = name; |
52 | } |
53 | |
54 | /*! |
55 | Creates a new MQTT topic name as a copy of \a name. |
56 | */ |
57 | QMqttTopicName::QMqttTopicName(const QMqttTopicName &name) : d(name.d) |
58 | { |
59 | } |
60 | |
61 | /*! |
62 | Destroys the QMqttTopicName object. |
63 | */ |
64 | QMqttTopicName::~QMqttTopicName() |
65 | { |
66 | } |
67 | |
68 | /*! |
69 | Assigns the MQTT topic name \a name to this object, and returns a reference |
70 | to the copy. |
71 | */ |
72 | QMqttTopicName &QMqttTopicName::operator=(const QMqttTopicName &name) |
73 | { |
74 | d = name.d; |
75 | return *this; |
76 | } |
77 | |
78 | /*! |
79 | Returns the topic name. |
80 | */ |
81 | QString QMqttTopicName::name() const |
82 | { |
83 | return d->name; |
84 | } |
85 | |
86 | /*! |
87 | Sets the topic name to \a name. |
88 | */ |
89 | void QMqttTopicName::setName(const QString &name) |
90 | { |
91 | d.detach(); |
92 | d->name = name; |
93 | } |
94 | |
95 | /*! |
96 | Returns \c true if the topic name is valid according to the MQTT standard |
97 | section 4.7, or \c false otherwise. |
98 | */ |
99 | bool QMqttTopicName::isValid() const |
100 | { |
101 | const int bytes = d->name.size(); |
102 | return bytes > 0 // [MQTT-4.7.3-1] |
103 | && bytes < 65536 // [MQTT-4.7.3-3] |
104 | && !d->name.contains(c: QLatin1Char('#')) // [MQTT-4.7.1-1] |
105 | && !d->name.contains(c: QLatin1Char('+')) // [MQTT-4.7.1-1] |
106 | && !d->name.contains(c: QChar(QChar::Null)); // [MQTT-4.7.3-2] |
107 | } |
108 | |
109 | /*! |
110 | Returns the total number of topic levels. |
111 | */ |
112 | int QMqttTopicName::levelCount() const |
113 | { |
114 | return d->name.isEmpty() ? 0 : d->name.count(c: QLatin1Char('/')) + 1; |
115 | } |
116 | |
117 | /*! |
118 | Returns the topic levels. |
119 | */ |
120 | QStringList QMqttTopicName::levels() const |
121 | { |
122 | return d->name.split(sep: QLatin1Char('/'), behavior: Qt::KeepEmptyParts); |
123 | } |
124 | |
125 | /*! |
126 | //! friend |
127 | \fn bool QMqttTopicName::operator==(const QMqttTopicName &lhs, const QMqttTopicName &rhs) |
128 | |
129 | Returns \c true if the topic names \a lhs and \a rhs are equal, |
130 | otherwise returns \c false. |
131 | */ |
132 | bool operator==(const QMqttTopicName &lhs, const QMqttTopicName &rhs) Q_DECL_NOTHROW |
133 | { |
134 | return (lhs.d == rhs.d) || (lhs.d->name == rhs.d->name); |
135 | } |
136 | |
137 | /*! |
138 | //! friend |
139 | \fn bool QMqttTopicName::operator!=(const QMqttTopicName &lhs, const QMqttTopicName &rhs) |
140 | |
141 | Returns \c true if the topic names \a lhs and \a rhs are different, |
142 | otherwise returns \c false. |
143 | */ |
144 | |
145 | /*! |
146 | //! friend |
147 | \fn bool QMqttTopicName::operator<(const QMqttTopicName &lhs, const QMqttTopicName &rhs) |
148 | |
149 | Returns \c true if the topic name \a lhs is lexically less than the topic |
150 | name \a rhs; otherwise returns \c false. |
151 | */ |
152 | bool operator<(const QMqttTopicName &lhs, const QMqttTopicName &rhs) Q_DECL_NOTHROW |
153 | { |
154 | return lhs.d->name < rhs.d->name; |
155 | } |
156 | |
157 | /*! |
158 | \relates QHash |
159 | |
160 | Returns the hash value for \a name. If specified, \a seed is used to |
161 | initialize the hash. |
162 | */ |
163 | size_t qHash(const QMqttTopicName &name, size_t seed) Q_DECL_NOTHROW |
164 | { |
165 | return qHash(key: name.d->name, seed); |
166 | } |
167 | |
168 | #ifndef QT_NO_DATASTREAM |
169 | /*! \relates QMqttTopicName |
170 | |
171 | Writes the topic name \a name to the stream \a out and returns a reference |
172 | to the stream. |
173 | |
174 | \sa{Serializing Qt Data Types}{Format of the QDataStream operators} |
175 | */ |
176 | QDataStream &operator<<(QDataStream &out, const QMqttTopicName &name) |
177 | { |
178 | out << name.name(); |
179 | return out; |
180 | } |
181 | |
182 | /*! \relates QMqttTopicName |
183 | |
184 | Reads a topic name into \a name from the stream \a in and returns a |
185 | reference to the stream. |
186 | |
187 | \sa{Serializing Qt Data Types}{Format of the QDataStream operators} |
188 | */ |
189 | QDataStream &operator>>(QDataStream &in, QMqttTopicName &name) |
190 | { |
191 | QString n; |
192 | in >> n; |
193 | name.setName(n); |
194 | return in; |
195 | } |
196 | #endif // QT_NO_DATASTREAM |
197 | |
198 | #ifndef QT_NO_DEBUG_STREAM |
199 | QDebug operator<<(QDebug d, const QMqttTopicName &name) |
200 | { |
201 | QDebugStateSaver saver(d); |
202 | d.nospace() << "QMqttTopicName(" << name.name() << ')'; |
203 | return d; |
204 | } |
205 | #endif |
206 | |
207 | QT_END_NAMESPACE |
208 | |