File indexing completed on 2025-09-17 08:38:23
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_MQTT5_PROPERTY_TYPES_HPP
0009 #define BOOST_MQTT5_PROPERTY_TYPES_HPP
0010
0011 #include <boost/container/small_vector.hpp>
0012
0013 #include <cstdint>
0014 #include <functional>
0015 #include <optional>
0016 #include <string>
0017 #include <string_view>
0018 #include <tuple>
0019 #include <type_traits>
0020 #include <vector>
0021
0022 namespace boost::mqtt5::prop {
0023
0024
0025 enum property_type : uint8_t {
0026 payload_format_indicator_t = 0x01,
0027 message_expiry_interval_t = 0x02,
0028 content_type_t = 0x03,
0029 response_topic_t = 0x08,
0030 correlation_data_t = 0x09,
0031 subscription_identifier_t = 0x0b,
0032 session_expiry_interval_t = 0x11,
0033 assigned_client_identifier_t = 0x12,
0034 server_keep_alive_t = 0x13,
0035 authentication_method_t = 0x15,
0036 authentication_data_t = 0x16,
0037 request_problem_information_t = 0x17,
0038 will_delay_interval_t = 0x18,
0039 request_response_information_t = 0x19,
0040 response_information_t = 0x1a,
0041 server_reference_t = 0x1c,
0042 reason_string_t = 0x1f,
0043 receive_maximum_t = 0x21,
0044 topic_alias_maximum_t = 0x22,
0045 topic_alias_t = 0x23,
0046 maximum_qos_t = 0x24,
0047 retain_available_t = 0x25,
0048 user_property_t = 0x26,
0049 maximum_packet_size_t = 0x27,
0050 wildcard_subscription_available_t = 0x28,
0051 subscription_identifier_available_t = 0x29,
0052 shared_subscription_available_t = 0x2a
0053 };
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064 class alignas(8) subscription_identifiers :
0065 public boost::container::small_vector<int32_t, 1>
0066 {
0067 using base_type = boost::container::small_vector<int32_t, 1>;
0068
0069 public:
0070 using base_type::base_type;
0071
0072
0073 subscription_identifiers(int32_t val) : base_type { val } {}
0074
0075
0076 bool has_value() const noexcept {
0077 return !empty();
0078 }
0079
0080 explicit operator bool() const noexcept {
0081 return !empty();
0082 }
0083
0084
0085
0086 int32_t& operator*() noexcept {
0087 return front();
0088 }
0089
0090 int32_t operator*() const noexcept {
0091 return front();
0092 }
0093
0094
0095
0096 void emplace(int32_t val = 0) {
0097 *this = val;
0098 }
0099
0100
0101 int32_t value() const {
0102 return front();
0103 }
0104
0105
0106 int32_t value_or(int32_t default_val) const noexcept {
0107 return empty() ? default_val : front();
0108 }
0109
0110
0111 void reset() noexcept {
0112 clear();
0113 }
0114 };
0115
0116 template <property_type p>
0117 struct property_traits;
0118
0119 using user_property_value_t = std::vector<std::pair<std::string, std::string>>;
0120
0121 #define DEF_PROPERTY_TRAIT(Pname, Ptype) \
0122 template <> \
0123 struct property_traits<Pname##_t> { \
0124 static constexpr std::string_view name = #Pname; \
0125 using type = Ptype; \
0126 }; \
0127 constexpr std::integral_constant<property_type, Pname##_t> Pname {};
0128
0129 DEF_PROPERTY_TRAIT(payload_format_indicator, std::optional<uint8_t>);
0130 DEF_PROPERTY_TRAIT(message_expiry_interval, std::optional<uint32_t>);
0131 DEF_PROPERTY_TRAIT(content_type, std::optional<std::string>);
0132 DEF_PROPERTY_TRAIT(response_topic, std::optional<std::string>);
0133 DEF_PROPERTY_TRAIT(correlation_data, std::optional<std::string>);
0134 DEF_PROPERTY_TRAIT(subscription_identifier, subscription_identifiers);
0135 DEF_PROPERTY_TRAIT(session_expiry_interval, std::optional<uint32_t>);
0136 DEF_PROPERTY_TRAIT(assigned_client_identifier, std::optional<std::string>);
0137 DEF_PROPERTY_TRAIT(server_keep_alive, std::optional<uint16_t>);
0138 DEF_PROPERTY_TRAIT(authentication_method, std::optional<std::string>);
0139 DEF_PROPERTY_TRAIT(authentication_data, std::optional<std::string>);
0140 DEF_PROPERTY_TRAIT(request_problem_information, std::optional<uint8_t>);
0141 DEF_PROPERTY_TRAIT(will_delay_interval, std::optional<uint32_t>);
0142 DEF_PROPERTY_TRAIT(request_response_information, std::optional<uint8_t>);
0143 DEF_PROPERTY_TRAIT(response_information, std::optional<std::string>);
0144 DEF_PROPERTY_TRAIT(server_reference, std::optional<std::string>);
0145 DEF_PROPERTY_TRAIT(reason_string, std::optional<std::string>);
0146 DEF_PROPERTY_TRAIT(receive_maximum, std::optional<uint16_t>);
0147 DEF_PROPERTY_TRAIT(topic_alias_maximum, std::optional<uint16_t>);
0148 DEF_PROPERTY_TRAIT(topic_alias, std::optional<uint16_t>);
0149 DEF_PROPERTY_TRAIT(maximum_qos, std::optional<uint8_t>);
0150 DEF_PROPERTY_TRAIT(retain_available, std::optional<uint8_t>);
0151 DEF_PROPERTY_TRAIT(user_property, user_property_value_t);
0152 DEF_PROPERTY_TRAIT(maximum_packet_size, std::optional<uint32_t>);
0153 DEF_PROPERTY_TRAIT(wildcard_subscription_available, std::optional<uint8_t>);
0154 DEF_PROPERTY_TRAIT(subscription_identifier_available, std::optional<uint8_t>);
0155 DEF_PROPERTY_TRAIT(shared_subscription_available, std::optional<uint8_t>);
0156
0157 #undef DEF_PROPERTY_TRAIT
0158
0159 template <property_type p>
0160 using value_type_t = typename property_traits<p>::type;
0161
0162 template <property_type p>
0163 constexpr std::string_view name_v = property_traits<p>::name;
0164
0165
0166
0167
0168
0169 template <property_type ...Ps>
0170 class properties {
0171
0172 template <property_type p>
0173 struct property {
0174 using key = std::integral_constant<property_type, p>;
0175 constexpr static std::string_view name = name_v<p>;
0176 value_type_t<p> value;
0177 };
0178 std::tuple<property<Ps>...> _props;
0179
0180 public:
0181
0182
0183 template <property_type v>
0184 constexpr auto& operator[](std::integral_constant<property_type, v>)
0185 noexcept {
0186 return std::get<property<v>>(_props).value;
0187 }
0188
0189
0190 template <property_type v>
0191 constexpr const auto& operator[](std::integral_constant<property_type, v>)
0192 const noexcept {
0193 return std::get<property<v>>(_props).value;
0194 }
0195
0196
0197 template <typename Func>
0198 using is_apply_on = std::conjunction<
0199 std::is_invocable<Func, value_type_t<Ps>&>...
0200 >;
0201
0202 template <typename Func>
0203 using is_nothrow_apply_on = std::conjunction<
0204 std::is_nothrow_invocable<Func, value_type_t<Ps>&>...
0205 >;
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218 template <
0219 typename Func,
0220 std::enable_if_t<is_apply_on<Func>::value, bool> = true
0221 >
0222 constexpr bool apply_on(uint8_t property_id, Func&& func)
0223 noexcept (is_nothrow_apply_on<Func>::value) {
0224 return std::apply(
0225 [&func, property_id](auto&... ptype) {
0226 auto pc = [&func, property_id](auto& px) {
0227 using ptype = std::remove_reference_t<decltype(px)>;
0228 constexpr typename ptype::key prop;
0229 if (prop.value == property_id)
0230 std::invoke(func, px.value);
0231 return prop.value == property_id;
0232 };
0233 return (pc(ptype) || ...);
0234 },
0235 _props
0236 );
0237 }
0238
0239
0240 template <typename Func>
0241 using is_visitor = std::conjunction<
0242 std::is_invocable_r<bool, Func, decltype(Ps), value_type_t<Ps>&>...
0243 >;
0244
0245 template <typename Func>
0246 using is_nothrow_visitor = std::conjunction<
0247 std::is_nothrow_invocable<Func, decltype(Ps), value_type_t<Ps>&>...
0248 >;
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263 template <
0264 typename Func,
0265 std::enable_if_t<is_visitor<Func>::value, bool> = true
0266 >
0267 constexpr bool visit(Func&& func)
0268 const noexcept (is_nothrow_visitor<Func>::value) {
0269 return std::apply(
0270 [&func](const auto&... props) {
0271 auto pc = [&func](const auto& px) {
0272 using ptype = std::remove_reference_t<decltype(px)>;
0273 constexpr typename ptype::key prop;
0274 return std::invoke(func, prop, px.value);
0275 };
0276 return (pc(props) && ...);
0277 },
0278 _props
0279 );
0280 }
0281
0282
0283 template <
0284 typename Func,
0285 std::enable_if_t<is_visitor<Func>::value, bool> = true
0286 >
0287 constexpr bool visit(Func&& func)
0288 noexcept (is_nothrow_visitor<Func>::value) {
0289 return std::apply(
0290 [&func](auto&... props) {
0291 auto pc = [&func](auto& px) {
0292 using ptype = std::remove_reference_t<decltype(px)>;
0293 constexpr typename ptype::key prop;
0294 return std::invoke(func, prop, px.value);
0295 };
0296 return (pc(props) && ...);
0297 },
0298 _props
0299 );
0300 }
0301 };
0302
0303
0304 }
0305
0306 #endif