123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828 |
- // Copyright Takatoshi Kondo 2018
- //
- // Distributed under the Boost Software License, Version 1.0.
- // (See accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- #if !defined(MQTT_PROPERTY_HPP)
- #define MQTT_PROPERTY_HPP
- #include <string>
- #include <vector>
- #include <memory>
- #include <algorithm>
- #include <iosfwd>
- #include <iomanip>
- #include <boost/asio/buffer.hpp>
- #include <boost/numeric/conversion/cast.hpp>
- #include <boost/container/static_vector.hpp>
- #include <boost/operators.hpp>
- #include <mqtt/namespace.hpp>
- #include <mqtt/optional.hpp>
- #include <mqtt/two_byte_util.hpp>
- #include <mqtt/const_buffer_util.hpp>
- #include <mqtt/exception.hpp>
- #include <mqtt/string_check.hpp>
- #include <mqtt/property_id.hpp>
- #include <mqtt/four_byte_util.hpp>
- #include <mqtt/utf8encoded_strings.hpp>
- #include <mqtt/subscribe_options.hpp>
- #include <mqtt/variable_length.hpp>
- #include <mqtt/buffer.hpp>
- #include <mqtt/move.hpp>
- #include <mqtt/type.hpp>
- namespace MQTT_NS {
- namespace as = boost::asio;
- namespace v5 {
- namespace property {
- namespace detail {
- enum class ostream_format {
- direct,
- int_cast,
- key_val,
- binary_string,
- json_like
- };
- template <std::size_t N>
- struct n_bytes_property : private boost::totally_ordered<n_bytes_property<N>> {
- explicit n_bytes_property(property::id id)
- :id_(id) {}
- template <typename It>
- n_bytes_property(property::id id, It b, It e)
- :id_(id), buf_(force_move(b), force_move(e)) {}
- n_bytes_property(property::id id, boost::container::static_vector<char, N> buf)
- :id_(id), buf_(force_move(buf)) {}
- /**
- * @brief Add const buffer sequence into the given buffer.
- * @param v buffer to add
- */
- void add_const_buffer_sequence(std::vector<as::const_buffer>& v) const {
- v.emplace_back(as::buffer(&id_, 1));
- v.emplace_back(as::buffer(buf_.data(), buf_.size()));
- }
- /**
- * @brief Copy the internal information to the range between b and e
- * it is for boost asio APIs
- * @param b begin of the range to fill
- * @param e end of the range to fill
- */
- template <typename It>
- void fill(It b, It e) const {
- (void)e; // Avoid warning in release builds about unused variable
- BOOST_ASSERT(static_cast<std::size_t>(std::distance(b, e)) >= size());
- *b++ = static_cast<typename std::iterator_traits<It>::value_type>(id_);
- std::copy(buf_.begin(), buf_.end(), b);
- }
- /**
- * @brief Get property::id
- * @return id
- */
- property::id id() const {
- return id_;
- }
- /**
- * @brief Get whole size of sequence
- * @return whole size
- */
- std::size_t size() const {
- return 1 + buf_.size();
- }
- /**
- * @brief Get number of element of const_buffer_sequence
- * @return number of element of const_buffer_sequence
- */
- static constexpr std::size_t num_of_const_buffer_sequence() {
- return 2;
- }
- friend bool operator<(n_bytes_property<N> const& lhs, n_bytes_property<N> const& rhs) {
- return std::tie(lhs.id_, lhs.buf_) < std::tie(rhs.id_, rhs.buf_);
- }
- friend bool operator==(n_bytes_property<N> const& lhs, n_bytes_property<N> const& rhs) {
- return std::tie(lhs.id_, lhs.buf_) == std::tie(rhs.id_, rhs.buf_);
- }
- static constexpr ostream_format const of_ = ostream_format::direct;
- property::id id_;
- boost::container::static_vector<char, N> buf_;
- };
- struct binary_property : private boost::totally_ordered<binary_property> {
- binary_property(property::id id, buffer buf)
- :id_(id),
- buf_(force_move(buf)),
- length_{ num_to_2bytes(boost::numeric_cast<std::uint16_t>(buf_.size())) } {
- if (buf_.size() > 0xffff) throw property_length_error();
- }
- /**
- * @brief Add const buffer sequence into the given buffer.
- * @param v buffer to add
- */
- void add_const_buffer_sequence(std::vector<as::const_buffer>& v) const {
- v.emplace_back(as::buffer(&id_, 1));
- v.emplace_back(as::buffer(length_.data(), length_.size()));
- v.emplace_back(as::buffer(buf_.data(), buf_.size()));
- }
- /**
- * @brief Copy the internal information to the range between b and e
- * it is for boost asio APIs
- * @param b begin of the range to fill
- * @param e end of the range to fill
- */
- template <typename It>
- void fill(It b, It e) const {
- (void)e; // Avoid warning in release builds about unused variable
- using dt = typename It::difference_type;
- BOOST_ASSERT(static_cast<std::size_t>(std::distance(b, e)) >= size());
- *b++ = static_cast<typename std::iterator_traits<It>::value_type>(id_);
- std::copy(length_.begin(), length_.end(), b);
- std::advance(b, static_cast<dt>(length_.size()));
- std::copy(buf_.begin(), buf_.end(), b);
- }
- /**
- * @brief Get property::id
- * @return id
- */
- property::id id() const {
- return id_;
- }
- /**
- * @brief Get whole size of sequence
- * @return whole size
- */
- std::size_t size() const {
- return 1 + length_.size() + buf_.size();
- }
- /**
- * @brief Get number of element of const_buffer_sequence
- * @return number of element of const_buffer_sequence
- */
- static constexpr std::size_t num_of_const_buffer_sequence() {
- return 2;
- }
- constexpr buffer const& val() const {
- return buf_;
- }
- friend bool operator<(binary_property const& lhs, binary_property const& rhs) {
- return std::tie(lhs.id_, lhs.buf_) < std::tie(rhs.id_, rhs.buf_);
- }
- friend bool operator==(binary_property const& lhs, binary_property const& rhs) {
- return std::tie(lhs.id_, lhs.buf_) == std::tie(rhs.id_, rhs.buf_);
- }
- static constexpr ostream_format const of_ = ostream_format::json_like;
- property::id id_;
- buffer buf_;
- boost::container::static_vector<char, 2> length_;
- };
- struct string_property : binary_property {
- string_property(property::id id, buffer buf, bool already_checked)
- :binary_property(id, force_move(buf)) {
- if (!already_checked) {
- auto r = utf8string::validate_contents(this->val());
- if (r != utf8string::validation::well_formed) throw utf8string_contents_error(r);
- }
- }
- };
- struct variable_property : private boost::totally_ordered<variable_property> {
- variable_property(property::id id, std::size_t value)
- :id_(id) {
- variable_push(value_, value);
- }
- /**
- * @brief Add const buffer sequence into the given buffer.
- * @param v buffer to add
- */
- void add_const_buffer_sequence(std::vector<as::const_buffer>& v) const {
- v.emplace_back(as::buffer(&id_, 1));
- v.emplace_back(as::buffer(value_.data(), value_.size()));
- }
- /**
- * @brief Copy the internal information to the range between b and e
- * it is for boost asio APIs
- * @param b begin of the range to fill
- * @param e end of the range to fill
- */
- template <typename It>
- void fill(It b, It e) const {
- (void)e; // Avoid warning in release builds about unused variable
- BOOST_ASSERT(static_cast<std::size_t>(std::distance(b, e)) >= size());
- *b++ = static_cast<typename std::iterator_traits<It>::value_type>(id_);
- std::copy(value_.begin(), value_.end(), b);
- }
- /**
- * @brief Get property::id
- * @return id
- */
- property::id id() const {
- return id_;
- }
- /**
- * @brief Get whole size of sequence
- * @return whole size
- */
- std::size_t size() const {
- return 1 + value_.size();
- }
- /**
- * @brief Get number of element of const_buffer_sequence
- * @return number of element of const_buffer_sequence
- */
- static constexpr std::size_t num_of_const_buffer_sequence() {
- return 2;
- }
- constexpr std::size_t val() const {
- return std::get<0>(variable_length(value_));
- }
- friend bool operator<(variable_property const& lhs, variable_property const& rhs) {
- auto const& lval = lhs.val();
- auto const& rval = rhs.val();
- return std::tie(lhs.id_, lval) < std::tie(rhs.id_, rval);
- }
- friend bool operator==(variable_property const& lhs, variable_property const& rhs) {
- auto const& lval = lhs.val();
- auto const& rval = rhs.val();
- return std::tie(lhs.id_, lval) == std::tie(rhs.id_, rval);
- }
- static constexpr ostream_format const of_ = ostream_format::direct;
- property::id id_;
- boost::container::static_vector<char, 4> value_;
- };
- } // namespace detail
- class payload_format_indicator : public detail::n_bytes_property<1> {
- public:
- using recv = payload_format_indicator;
- using store = payload_format_indicator;
- enum payload_format {
- binary,
- string
- };
- payload_format_indicator(payload_format fmt = binary)
- : detail::n_bytes_property<1>(id::payload_format_indicator, { fmt == binary ? char(0) : char(1) } ) {}
- template <typename It>
- payload_format_indicator(It b, It e)
- : detail::n_bytes_property<1>(id::payload_format_indicator, b, e) {}
- payload_format val() const {
- return ( (buf_.front() == 0)
- ? binary
- : string);
- }
- static constexpr detail::ostream_format const of_ = detail::ostream_format::binary_string;
- };
- class message_expiry_interval : public detail::n_bytes_property<4> {
- public:
- using recv = message_expiry_interval;
- using store = message_expiry_interval;
- message_expiry_interval(std::uint32_t val)
- : detail::n_bytes_property<4>(id::message_expiry_interval, num_to_4bytes(val) ) {}
- template <typename It>
- message_expiry_interval(It b, It e)
- : detail::n_bytes_property<4>(id::message_expiry_interval, b, e) {}
- std::uint32_t val() const {
- return make_uint32_t(buf_.begin(), buf_.end());
- }
- };
- class content_type : public detail::string_property {
- public:
- explicit content_type(buffer val, bool already_checked = false)
- : detail::string_property(id::content_type, force_move(val), already_checked) {}
- };
- class response_topic : public detail::string_property {
- public:
- explicit response_topic(buffer val, bool already_checked = false)
- : detail::string_property(id::response_topic, force_move(val), already_checked) {}
- };
- class correlation_data : public detail::binary_property {
- public:
- explicit correlation_data(buffer val)
- : detail::binary_property(id::correlation_data, force_move(val)) {}
- };
- class subscription_identifier : public detail::variable_property {
- public:
- using recv = subscription_identifier;
- using store = subscription_identifier;
- subscription_identifier(std::size_t subscription_id)
- : detail::variable_property(id::subscription_identifier, subscription_id) {}
- };
- class session_expiry_interval : public detail::n_bytes_property<4> {
- public:
- using recv = session_expiry_interval;
- using store = session_expiry_interval;
- session_expiry_interval(session_expiry_interval_t val)
- : detail::n_bytes_property<4>(id::session_expiry_interval, { num_to_4bytes(val) } ) {
- static_assert(sizeof(session_expiry_interval_t) == 4, "sizeof(sesion_expiry_interval) should be 4");
- }
- template <typename It>
- session_expiry_interval(It b, It e)
- : detail::n_bytes_property<4>(id::session_expiry_interval, b, e) {}
- session_expiry_interval_t val() const {
- return make_uint32_t(buf_.begin(), buf_.end());
- }
- };
- class assigned_client_identifier : public detail::string_property {
- public:
- explicit assigned_client_identifier(buffer val, bool already_checked = false)
- : detail::string_property(id::assigned_client_identifier, force_move(val), already_checked) {}
- };
- class server_keep_alive : public detail::n_bytes_property<2> {
- public:
- using recv = server_keep_alive;
- using store = server_keep_alive;
- server_keep_alive(std::uint16_t val)
- : detail::n_bytes_property<2>(id::server_keep_alive, { num_to_2bytes(val) } ) {}
- template <typename It>
- server_keep_alive(It b, It e)
- : detail::n_bytes_property<2>(id::server_keep_alive, b, e) {}
- std::uint16_t val() const {
- return make_uint16_t(buf_.begin(), buf_.end());
- }
- };
- class authentication_method : public detail::string_property {
- public:
- explicit authentication_method(buffer val, bool already_checked = false)
- : detail::string_property(id::authentication_method, force_move(val), already_checked) {}
- };
- class authentication_data : public detail::binary_property {
- public:
- explicit authentication_data(buffer val)
- : detail::binary_property(id::authentication_data, force_move(val)) {}
- };
- class request_problem_information : public detail::n_bytes_property<1> {
- public:
- using recv = request_problem_information;
- using store = request_problem_information;
- request_problem_information(bool value)
- : detail::n_bytes_property<1>(id::request_problem_information, { value ? char(1) : char(0) } ) {}
- template <typename It>
- request_problem_information(It b, It e)
- : detail::n_bytes_property<1>(id::request_problem_information, b, e) {}
- bool val() const {
- return buf_.front() == 1;
- }
- };
- class will_delay_interval : public detail::n_bytes_property<4> {
- public:
- using recv = will_delay_interval;
- using store = will_delay_interval;
- will_delay_interval(std::uint32_t val)
- : detail::n_bytes_property<4>(id::will_delay_interval, { num_to_4bytes(val) } ) {}
- template <typename It>
- will_delay_interval(It b, It e)
- : detail::n_bytes_property<4>(id::will_delay_interval, b, e) {}
- std::uint32_t val() const {
- return make_uint32_t(buf_.begin(), buf_.end());
- }
- };
- class request_response_information : public detail::n_bytes_property<1> {
- public:
- using recv = request_response_information;
- using store = request_response_information;
- request_response_information(bool value)
- : detail::n_bytes_property<1>(id::request_response_information, { value ? char(1) : char(0) } ) {}
- template <typename It>
- request_response_information(It b, It e)
- : detail::n_bytes_property<1>(id::request_response_information, b, e) {}
- bool val() const {
- return buf_.front() == 1;
- }
- };
- class response_information : public detail::string_property {
- public:
- explicit response_information(buffer val, bool already_checked = false)
- : detail::string_property(id::response_information, force_move(val), already_checked) {}
- };
- class server_reference : public detail::string_property {
- public:
- explicit server_reference(buffer val, bool already_checked = false)
- : detail::string_property(id::server_reference, force_move(val), already_checked) {}
- };
- class reason_string : public detail::string_property {
- public:
- explicit reason_string(buffer val, bool already_checked = false)
- : detail::string_property(id::reason_string, force_move(val), already_checked) {}
- };
- class receive_maximum : public detail::n_bytes_property<2> {
- public:
- using recv = receive_maximum;
- using store = receive_maximum;
- receive_maximum(receive_maximum_t val)
- : detail::n_bytes_property<2>(id::receive_maximum, { num_to_2bytes(val) } ) {}
- template <typename It>
- receive_maximum(It b, It e)
- : detail::n_bytes_property<2>(id::receive_maximum, b, e) {}
- receive_maximum_t val() const {
- return make_uint16_t(buf_.begin(), buf_.end());
- }
- };
- class topic_alias_maximum : public detail::n_bytes_property<2> {
- public:
- using recv = topic_alias_maximum;
- using store = topic_alias_maximum;
- topic_alias_maximum(topic_alias_t val)
- : detail::n_bytes_property<2>(id::topic_alias_maximum, { num_to_2bytes(val) } ) {}
- template <typename It>
- topic_alias_maximum(It b, It e)
- : detail::n_bytes_property<2>(id::topic_alias_maximum, b, e) {}
- topic_alias_t val() const {
- return make_uint16_t(buf_.begin(), buf_.end());
- }
- };
- class topic_alias : public detail::n_bytes_property<2> {
- public:
- using recv = topic_alias;
- using store = topic_alias;
- topic_alias(topic_alias_t val)
- : detail::n_bytes_property<2>(id::topic_alias, { num_to_2bytes(val) } ) {}
- template <typename It>
- topic_alias(It b, It e)
- : detail::n_bytes_property<2>(id::topic_alias, b, e) {}
- topic_alias_t val() const {
- return make_uint16_t(buf_.begin(), buf_.end());
- }
- };
- class maximum_qos : public detail::n_bytes_property<1> {
- public:
- using recv = maximum_qos;
- using store = maximum_qos;
- maximum_qos(qos value)
- : detail::n_bytes_property<1>(id::maximum_qos, { static_cast<char>(value) } ) {
- if (value != qos::at_most_once &&
- value != qos::at_least_once &&
- value != qos::exactly_once) throw property_parse_error();
- }
- template <typename It>
- maximum_qos(It b, It e)
- : detail::n_bytes_property<1>(id::maximum_qos, b, e) {}
- std::uint8_t val() const {
- return static_cast<std::uint8_t>(buf_.front());
- }
- static constexpr const detail::ostream_format of_ = detail::ostream_format::int_cast;
- };
- class retain_available : public detail::n_bytes_property<1> {
- public:
- using recv = retain_available;
- using store = retain_available;
- retain_available(bool value)
- : detail::n_bytes_property<1>(id::retain_available, { value ? char(1) : char(0) } ) {}
- template <typename It>
- retain_available(It b, It e)
- : detail::n_bytes_property<1>(id::retain_available, b, e) {}
- bool val() const {
- return buf_.front() == 1;
- }
- };
- class user_property : private boost::totally_ordered<user_property> {
- public:
- user_property(buffer key, buffer val, bool key_already_checked = false, bool val_already_checked = false)
- : key_(force_move(key), key_already_checked), val_(force_move(val), val_already_checked) {}
- /**
- * @brief Add const buffer sequence into the given buffer.
- * @param v buffer to add
- */
- void add_const_buffer_sequence(std::vector<as::const_buffer>& v) const {
- v.emplace_back(as::buffer(&id_, 1));
- v.emplace_back(as::buffer(key_.len.data(), key_.len.size()));
- v.emplace_back(as::buffer(key_.buf));
- v.emplace_back(as::buffer(val_.len.data(), val_.len.size()));
- v.emplace_back(as::buffer(val_.buf));
- }
- template <typename It>
- void fill(It b, It e) const {
- (void)e; // Avoid warning in release builds about unused variable
- using dt = typename It::difference_type;
- BOOST_ASSERT(static_cast<std::size_t>(std::distance(b, e)) >= size());
- *b++ = static_cast<typename std::iterator_traits<It>::value_type>(id_);
- {
- std::copy(key_.len.begin(), key_.len.end(), b);
- std::advance(b, static_cast<dt>(key_.len.size()));
- auto ptr = key_.buf.data();
- auto size = key_.buf.size();
- std::copy(ptr, std::next(ptr, static_cast<dt>(size)), b);
- std::advance(b, static_cast<dt>(size));
- }
- {
- std::copy(val_.len.begin(), val_.len.end(), b);
- std::advance(b, static_cast<dt>(val_.len.size()));
- auto ptr = val_.buf.data();
- auto size = val_.buf.size();
- std::copy(ptr, std::next(ptr, static_cast<dt>(size)), b);
- std::advance(b, static_cast<dt>(size));
- }
- }
- /**
- * @brief Get property::id
- * @return id
- */
- property::id id() const {
- return id_;
- }
- /**
- * @brief Get whole size of sequence
- * @return whole size
- */
- std::size_t size() const {
- return
- 1 + // id_
- key_.size() +
- val_.size();
- }
- /**
- * @brief Get number of element of const_buffer_sequence
- * @return number of element of const_buffer_sequence
- */
- static constexpr std::size_t num_of_const_buffer_sequence() {
- return
- 1 + // header
- 2 + // key (len, buf)
- 2; // val (len, buf)
- }
- constexpr buffer const& key() const {
- return key_.buf;
- }
- constexpr buffer const& val() const {
- return val_.buf;
- }
- friend bool operator<(user_property const& lhs, user_property const& rhs) {
- return std::tie(lhs.id_, lhs.key_.buf, lhs.val_.buf) < std::tie(rhs.id_, rhs.key_.buf, rhs.val_.buf);
- }
- friend bool operator==(user_property const& lhs, user_property const& rhs) {
- return std::tie(lhs.id_, lhs.key_.buf, lhs.val_.buf) == std::tie(rhs.id_, rhs.key_.buf, rhs.val_.buf);
- }
- static constexpr detail::ostream_format const of_ = detail::ostream_format::key_val;
- private:
- struct len_str {
- explicit len_str(buffer b, bool already_checked = false)
- : buf(force_move(b)),
- len{ num_to_2bytes(boost::numeric_cast<std::uint16_t>(buf.size())) }
- {
- if (!already_checked) {
- auto r = utf8string::validate_contents(buf);
- if (r != utf8string::validation::well_formed) throw utf8string_contents_error(r);
- }
- }
- std::size_t size() const {
- return len.size() + buf.size();
- }
- buffer buf;
- boost::container::static_vector<char, 2> len;
- };
- private:
- property::id id_ = id::user_property;
- len_str key_;
- len_str val_;
- };
- class maximum_packet_size : public detail::n_bytes_property<4> {
- public:
- using recv = maximum_packet_size;
- using store = maximum_packet_size;
- maximum_packet_size(std::uint32_t val)
- : detail::n_bytes_property<4>(id::maximum_packet_size, { num_to_4bytes(val) } ) {}
- template <typename It>
- maximum_packet_size(It b, It e)
- : detail::n_bytes_property<4>(id::maximum_packet_size, b, e) {}
- std::uint32_t val() const {
- return make_uint32_t(buf_.begin(), buf_.end());
- }
- };
- class wildcard_subscription_available : public detail::n_bytes_property<1> {
- public:
- using recv = wildcard_subscription_available;
- using store = wildcard_subscription_available;
- wildcard_subscription_available(bool value)
- : detail::n_bytes_property<1>(id::wildcard_subscription_available, { value ? char(1) : char(0) } ) {}
- template <typename It>
- wildcard_subscription_available(It b, It e)
- : detail::n_bytes_property<1>(id::wildcard_subscription_available, b, e) {}
- bool val() const {
- return buf_.front() == 1;
- }
- };
- class subscription_identifier_available : public detail::n_bytes_property<1> {
- public:
- using recv = subscription_identifier_available;
- using store = subscription_identifier_available;
- subscription_identifier_available(bool value)
- : detail::n_bytes_property<1>(id::subscription_identifier_available, { value ? char(1) : char(0) } ) {}
- template <typename It>
- subscription_identifier_available(It b, It e)
- : detail::n_bytes_property<1>(id::subscription_identifier_available, b, e) {}
- bool val() const {
- return buf_.front() == 1;
- }
- };
- class shared_subscription_available : public detail::n_bytes_property<1> {
- public:
- using recv = shared_subscription_available;
- using store = shared_subscription_available;
- shared_subscription_available(bool value)
- : detail::n_bytes_property<1>(id::shared_subscription_available, { value ? char(1) : char(0) } ) {}
- template <typename It>
- shared_subscription_available(It b, It e)
- : detail::n_bytes_property<1>(id::shared_subscription_available, b, e) {}
- bool val() const {
- return buf_.front() == 1;
- }
- };
- template <typename Property>
- std::enable_if_t< Property::of_ == detail::ostream_format::direct, std::ostream& >
- operator<<(std::ostream& o, Property const& p) {
- o << p.val();
- return o;
- }
- template <typename Property>
- std::enable_if_t< Property::of_ == detail::ostream_format::int_cast, std::ostream& >
- operator<<(std::ostream& o, Property const& p) {
- o << static_cast<int>(p.val());
- return o;
- }
- template <typename Property>
- std::enable_if_t< Property::of_ == detail::ostream_format::key_val, std::ostream& >
- operator<<(std::ostream& o, Property const& p) {
- o << p.key() << ':' << p.val();
- return o;
- }
- template <typename Property>
- std::enable_if_t< Property::of_ == detail::ostream_format::binary_string, std::ostream& >
- operator<<(std::ostream& o, Property const& p) {
- // Note this only compiles because both strings below are the same length.
- o << ((p.val() == payload_format_indicator::binary) ? "binary" : "string");
- return o;
- }
- template <typename Property>
- std::enable_if_t< Property::of_ == detail::ostream_format::json_like, std::ostream& >
- operator<<(std::ostream& o, Property const& p) {
- auto const& v = p.val();
- for (auto const c : v) {
- switch (c) {
- case '\\':
- o << "\\\\";
- break;
- case '"':
- o << "\\\"";
- break;
- case '/':
- o << "\\/";
- break;
- case '\b':
- o << "\\b";
- break;
- case '\f':
- o << "\\f";
- break;
- case '\n':
- o << "\\n";
- break;
- case '\r':
- o << "\\r";
- break;
- case '\t':
- o << "\\t";
- break;
- default: {
- unsigned int code = static_cast<unsigned int>(c);
- if (code < 0x20 || code >= 0x7f) {
- std::ios::fmtflags flags(o.flags());
- o << "\\u" << std::hex << std::setw(4) << std::setfill('0') << (code & 0xff);
- o.flags(flags);
- }
- else {
- o << c;
- }
- } break;
- }
- }
- return o;
- }
- } // namespace property
- } // namespace v5
- } // namespace MQTT_NS
- #endif // MQTT_PROPERTY_HPP
|