7#if !defined(ASYNC_MQTT_PACKET_PROPERTY_VARIANT_HPP)
8#define ASYNC_MQTT_PACKET_PROPERTY_VARIANT_HPP
10#include <async_mqtt/util/variant.hpp>
12#include <async_mqtt/packet/validate_property.hpp>
13#include <async_mqtt/exception.hpp>
41 template <
typename Func>
45 std::forward<Func>(
func),
54 template <
typename Func>
58 std::forward<Func>(
func),
67 template <
typename Func>
71 std::forward<Func>(
func),
80 property::id
id()
const {
88 return property::id(0);
102 return p.num_of_const_buffer_sequence();
106 return std::size_t(0);
121 return p.const_buffer_sequence();
125 return std::vector<as::const_buffer>{};
143 return std::size_t(0);
153 template <
typename T>
155 return std::get<T>(var_);
162 template <
typename T>
163 decltype(
auto)
get()
const {
164 return std::get<T>(var_);
171 template <
typename T>
173 return std::get_if<T>(&var_);
180 template <
typename T>
182 return std::get_if<T>(&var_);
186 return var_.index() != 0;
190 return lhs.var_ == rhs.var_;
193 return lhs.var_ < rhs.var_;
195 friend std::ostream& operator<<(std::ostream& o,
property_variant const& v) {
197 [&] (
auto const& p) { o << p; }
203 using variant_t = variant<
205 property::payload_format_indicator,
206 property::message_expiry_interval,
207 property::content_type,
208 property::response_topic,
209 property::correlation_data,
210 property::subscription_identifier,
211 property::session_expiry_interval,
212 property::assigned_client_identifier,
213 property::server_keep_alive,
214 property::authentication_method,
215 property::authentication_data,
216 property::request_problem_information,
217 property::will_delay_interval,
218 property::request_response_information,
219 property::response_information,
220 property::server_reference,
221 property::reason_string,
222 property::receive_maximum,
223 property::topic_alias_maximum,
224 property::topic_alias,
225 property::maximum_qos,
226 property::retain_available,
227 property::user_property,
228 property::maximum_packet_size,
229 property::wildcard_subscription_available,
230 property::subscription_identifier_available,
231 property::shared_subscription_available
237using properties = std::vector<property_variant>;
239inline std::ostream& operator<<(std::ostream& o, properties
const& props) {
241 auto it = props.cbegin();
242 auto end = props.cend();
247 for (; it != end; ++it) {
255property_variant make_property_variant(buffer& buf, property_location loc) {
259 "property doesn't exist"
264 using namespace std::literals;
265 auto id =
static_cast<property::id
>(buf.front());
266 if (!validate_property(loc,
id)) {
269 "property "s + property::id_to_str(
id) +
" is not allowed in " + property_location_to_str(loc)
272 buf.remove_prefix(1);
274 case property::id::payload_format_indicator: {
275 if (buf.size() < 1) {
278 "property::payload_format_indicator is invalid"
281 auto p = property::payload_format_indicator(buf.begin(), std::next(buf.begin(), 1));
282 buf.remove_prefix(1);
283 return property_variant(p);
285 case property::id::message_expiry_interval: {
286 if (buf.size() < 4) {
289 "property::message_expiry_interval is invalid"
292 auto p = property::message_expiry_interval(buf.begin(), std::next(buf.begin(), 4));
293 buf.remove_prefix(4);
294 return property_variant(p);
296 case property::id::content_type: {
297 if (buf.size() < 2) {
300 "property::content_type length is invalid"
303 auto len = endian_load<std::uint16_t>(buf.data());
304 if (buf.size() < 2U + len) {
307 "property::content_type is invalid"
310 auto p = property::content_type(buf.substr(2, len));
311 buf.remove_prefix(2 + len);
312 return property_variant(p);
314 case property::id::response_topic: {
315 if (buf.size() < 2) {
318 "property::response_topic length is invalid"
321 auto len = endian_load<std::uint16_t>(buf.data());
322 if (buf.size() < 2U + len) {
325 "property::response_topic is invalid"
328 auto p = property::response_topic(buf.substr(2, len));
329 buf.remove_prefix(2 + len);
330 return property_variant(p);
332 case property::id::correlation_data: {
333 if (buf.size() < 2) {
336 "property::correlation_data length is invalid"
339 auto len = endian_load<std::uint16_t>(buf.data());
340 if (buf.size() < 2U + len) {
343 "property::correlation_data is invalid"
346 auto p = property::correlation_data(buf.substr(2, len));
347 buf.remove_prefix(2 + len);
348 return property_variant(p);
350 case property::id::subscription_identifier: {
351 auto it = buf.begin();
352 if (
auto val_opt = variable_bytes_to_val(it, buf.end())) {
353 auto p = property::subscription_identifier(*val_opt);
354 buf.remove_prefix(std::size_t(std::distance(buf.begin(), it)));
355 return property_variant(p);
359 "property::subscription_identifier is invalid"
362 case property::id::session_expiry_interval: {
363 if (buf.size() < 4) {
366 "property::session_expiry_interval is invalid"
369 auto p = property::session_expiry_interval(buf.begin(), std::next(buf.begin(), 4));
370 buf.remove_prefix(4);
371 return property_variant(p);
373 case property::id::assigned_client_identifier: {
374 if (buf.size() < 2) {
377 "property::assigned_client_identifier length is invalid"
380 auto len = endian_load<std::uint16_t>(buf.data());
381 if (buf.size() < 2U + len) {
384 "property::assigned_client_identifier is invalid"
387 auto p = property::assigned_client_identifier(buf.substr(2, len));
388 buf.remove_prefix(2 + len);
389 return property_variant(p);
391 case property::id::server_keep_alive: {
392 if (buf.size() < 2) {
395 "property::server_keep_alive is invalid"
398 auto p = property::server_keep_alive(buf.begin(), std::next(buf.begin(), 2));
399 buf.remove_prefix(2);
400 return property_variant(p);
402 case property::id::authentication_method: {
403 if (buf.size() < 2) {
406 "property::authentication_method length is invalid"
409 auto len = endian_load<std::uint16_t>(buf.data());
410 if (buf.size() < 2U + len) {
413 "property::authentication_method is invalid"
416 auto p = property::authentication_method(buf.substr(2, len));
417 buf.remove_prefix(2 + len);
418 return property_variant(p);
420 case property::id::authentication_data: {
421 if (buf.size() < 2) {
424 "property::authentication_data length is invalid"
427 auto len = endian_load<std::uint16_t>(buf.data());
428 if (buf.size() < 2U + len) {
431 "property::authentication_data is invalid"
434 auto p = property::authentication_data(buf.substr(2, len));
435 buf.remove_prefix(2 + len);
436 return property_variant(p);
438 case property::id::request_problem_information: {
439 if (buf.size() < 1) {
442 "property::request_problem_information is invalid"
445 auto p = property::request_problem_information(buf.begin(), std::next(buf.begin(), 1));
446 buf.remove_prefix(1);
447 return property_variant(p);
449 case property::id::will_delay_interval: {
450 if (buf.size() < 4) {
453 "property::will_delay_interval is invalid"
456 auto p = property::will_delay_interval(buf.begin(), std::next(buf.begin(), 4));
457 buf.remove_prefix(4);
458 return property_variant(p);
460 case property::id::request_response_information: {
461 if (buf.size() < 1) {
464 "property::request_response_information is invalid"
467 auto p = property::request_response_information(buf.begin(), std::next(buf.begin(), 1));
468 buf.remove_prefix(1);
469 return property_variant(p);
471 case property::id::response_information: {
472 if (buf.size() < 2) {
475 "property::response_information length is invalid"
478 auto len = endian_load<std::uint16_t>(buf.data());
479 if (buf.size() < 2U + len) {
482 "property::response_information is invalid"
485 auto p = property::response_information(buf.substr(2, len));
486 buf.remove_prefix(2 + len);
487 return property_variant(p);
489 case property::id::server_reference: {
490 if (buf.size() < 2) {
493 "property::server_reference length is invalid"
496 auto len = endian_load<std::uint16_t>(buf.data());
497 if (buf.size() < 2U + len) {
500 "property::server_reference is invalid"
503 auto p = property::server_reference(buf.substr(2, len));
504 buf.remove_prefix(2 + len);
505 return property_variant(p);
507 case property::id::reason_string: {
508 if (buf.size() < 2) {
511 "property::reason_string length is invalid"
514 auto len = endian_load<std::uint16_t>(buf.data());
515 if (buf.size() < 2U + len) {
518 "property::reason_string is invalid"
521 auto p = property::reason_string(buf.substr(2, len));
522 buf.remove_prefix(2 + len);
523 return property_variant(p);
525 case property::id::receive_maximum: {
526 if (buf.size() < 2) {
529 "property::receive_maximum is invalid"
532 auto p = property::receive_maximum(buf.begin(), std::next(buf.begin(), 2));
533 buf.remove_prefix(2);
534 return property_variant(p);
536 case property::id::topic_alias_maximum: {
537 if (buf.size() < 2) {
540 "property::topic_alias_maximum is invalid"
543 auto p = property::topic_alias_maximum(buf.begin(), std::next(buf.begin(), 2));
544 buf.remove_prefix(2);
545 return property_variant(p);
547 case property::id::topic_alias: {
548 if (buf.size() < 2) {
551 "property::topic_alias is invalid"
554 auto p = property::topic_alias(buf.begin(), std::next(buf.begin(), 2));
555 buf.remove_prefix(2);
556 return property_variant(p);
558 case property::id::maximum_qos: {
559 if (buf.size() < 1) {
562 "property::maximum_qos is invalid"
565 auto p = property::maximum_qos(buf.begin(), std::next(buf.begin(), 1));
566 buf.remove_prefix(1);
567 return property_variant(p);
569 case property::id::retain_available: {
570 if (buf.size() < 1) {
573 "property::reason_string length is invalid"
576 auto p = property::retain_available(buf.begin(), std::next(buf.begin(), 1));
577 buf.remove_prefix(1);
578 return property_variant(p);
580 case property::id::user_property: {
581 if (buf.size() < 2) {
584 "property::user_property key length is invalid"
587 auto keylen = endian_load<std::uint16_t>(buf.data());
588 if (buf.size() < 2U + keylen) {
591 "property::user_property key is invalid"
594 auto key = buf.substr(2, keylen);
595 buf.remove_prefix(2 + keylen);
597 if (buf.size() < 2) {
600 "property::user_property val length is invalid"
603 auto vallen = endian_load<std::uint16_t>(buf.data());
604 if (buf.size() < 2U + vallen) {
607 "property::user_property val is invalid"
610 auto val = buf.substr(2, vallen);
611 auto p = property::user_property(force_move(key), force_move(val));
612 buf.remove_prefix(2 + vallen);
614 return property_variant(p);
616 case property::id::maximum_packet_size: {
617 if (buf.size() < 4) {
620 "property::maximum_packet_size is invalid"
623 auto p = property::maximum_packet_size(buf.begin(), std::next(buf.begin(), 4));
624 buf.remove_prefix(4);
625 return property_variant(p);
627 case property::id::wildcard_subscription_available: {
628 if (buf.size() < 1) {
631 "property::wildcard_subscription_available is invalid"
634 auto p = property::wildcard_subscription_available(buf.begin(), std::next(buf.begin(), 1));
635 buf.remove_prefix(1);
636 return property_variant(p);
638 case property::id::subscription_identifier_available: {
639 if (buf.size() < 1) {
642 "property::subscription_identifier_available is invalid"
645 auto p = property::subscription_identifier_available(buf.begin(), std::next(buf.begin(), 1));
646 buf.remove_prefix(1);
647 return property_variant(p);
649 case property::id::shared_subscription_available: {
650 if (buf.size() < 1) {
653 "property::shared_subscription_available is invalid"
656 auto p = property::shared_subscription_available(buf.begin(), std::next(buf.begin(), 1));
657 buf.remove_prefix(1);
658 return property_variant(p);
662 catch (system_error
const& e) {
672properties make_properties(buffer buf, property_location loc) {
674 while (!buf.empty()) {
675 if (
auto pv = make_property_variant(buf, loc)) {
676 props.push_back(force_move(pv));
687std::vector<as::const_buffer> const_buffer_sequence(properties
const& props) {
688 std::vector<as::const_buffer> v;
689 for (
auto const& p : props) {
690 auto cbs = p.const_buffer_sequence();
691 std::move(cbs.begin(), cbs.end(), std::back_inserter(v));
697std::size_t size(properties
const& props) {
703 [](std::size_t total, property_variant
const& pv) {
704 return total + pv.size();
710std::size_t num_of_const_buffer_sequence(properties
const& props) {
716 [](std::size_t total, property_variant
const& pv) {
717 return total + pv.num_of_const_buffer_sequence();
Definition packet_variant.hpp:49
property variant
Definition property_variant.hpp:20
decltype(auto) get()
Get by type. If not match, then throw std::bad_variant_access exception.
Definition property_variant.hpp:154
std::size_t size() const
Get packet size.
Definition property_variant.hpp:135
property::id id() const
Get property_id.
Definition property_variant.hpp:80
std::vector< as::const_buffer > const_buffer_sequence() const
Create const buffer sequence. it is for boost asio APIs.
Definition property_variant.hpp:117
decltype(auto) get_if() const
Get by type pointer.
Definition property_variant.hpp:181
property_variant(Property &&property)
constructor
Definition property_variant.hpp:34
decltype(auto) get_if()
Get by type pointer.
Definition property_variant.hpp:172
auto visit(Func &&func) &
visit to variant
Definition property_variant.hpp:55
decltype(auto) get() const
Get by type. If not match, then throw std::bad_variant_access exception.
Definition property_variant.hpp:163
std::size_t num_of_const_buffer_sequence() const
Get number of element of const_buffer_sequence.
Definition property_variant.hpp:98
auto visit(Func &&func) const &
visit to variant
Definition property_variant.hpp:42
auto visit(Func &&func) &&
visit to variant
Definition property_variant.hpp:68
async_mqtt error class. It is used as CompletionToken parameter and exception.
Definition exception.hpp:29