Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:38:23

0001 //
0002 // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic
0003 //
0004 // Distributed under the Boost Software License, Version 1.0.
0005 // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
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 /// \cond internal
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 /// \endcond
0055 
0056 /**
0057  * \brief A class holding any number of Subscription Identifiers.
0058  * 
0059  * \details Subscription Identifier is an integer that can be set in \__SUBSCRIBE_PROPS\__ when subscribing to a Topic.
0060  *    Broker will store the mapping between that Subscription and the Subscription Identifier.
0061  *    When an incoming \__PUBLISH\__ message matches one or more Subscriptions, respective Subscription
0062  *    Identifiers will be forwarded in the \__PUBLISH_PROPS\__ of the received message.
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     /// Constructs Subscription Identifiers with given parameters.
0073     subscription_identifiers(int32_t val) : base_type { val } {}
0074 
0075     /// \{ Checks whether there are any Subscription Identifiers.
0076     bool has_value() const noexcept {
0077         return !empty();
0078     }
0079 
0080     explicit operator bool() const noexcept {
0081         return !empty();
0082     }
0083     /// \}
0084 
0085     /// \{ Accesses the (first) Subscription Identifier.
0086     int32_t& operator*() noexcept {
0087         return front();
0088     }
0089 
0090     int32_t operator*() const noexcept {
0091         return front();
0092     }
0093     /// \}
0094 
0095     /// Sets or replaces the (first) Subscription Identifier.
0096     void emplace(int32_t val = 0) {
0097         *this = val;
0098     }
0099 
0100     /// Returns the first Subscription Identifier.
0101     int32_t value() const {
0102         return front();
0103     }
0104 
0105     /// Returns the first Subscription Identifier if it exists, otherwise returns \p default_val
0106     int32_t value_or(int32_t default_val) const noexcept {
0107         return empty() ? default_val : front();
0108     }
0109 
0110     /// Clears the Subscription Identifiers.
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  * \brief Base class for different Property classes that contains common access
0167         and modification functions.
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     /// \brief Accesses the value of a Property by its compile-time constant ID.
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     /// \copydoc operator[]
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 /// \cond internal
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 /// \endcond
0207 
0208     /**
0209     * \brief Applies a function to a Property identified by its ID.
0210     *
0211     * This function iterates over all Properties and invokes the provided function
0212     * on the value of the Property that matches the given property ID.
0213     *
0214     * \param property_id The ID of the Property to apply the function on.
0215     * \param func The function to invoke on the Property value.
0216     * \return `true` if the function was applied to a Property and `false` otherwise.
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 /// \cond internal
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 /// \endcond
0250 
0251     /**
0252     * \brief Invokes a visitor function on each Property.
0253     *
0254     * This function iterates over Properties and invokes the provided function 
0255     * on each Property, passing both the compile-time constant Property ID and its value.
0256     * The visitor function should return a boolean value that determines whether iteration continues.
0257     *
0258     * @param func The visitor function to invoke. It must accept two arguments: 
0259     *        a Property ID and the corresponding Property value.
0260     * @return `true` if the visitor function returns `true` for all Properties, 
0261     *         `false` otherwise.
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     /// \copydoc visit
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 } // end namespace boost::mqtt5::prop
0305 
0306 #endif // !BOOST_MQTT5_PROPERTY_TYPES_HPP