11
11
#include < cstring>
12
12
#include < span>
13
13
#include < string>
14
+ #include < type_traits>
15
+ #include < variant>
14
16
#include < vector>
15
17
16
18
namespace msgpack23 {
@@ -97,6 +99,20 @@ namespace msgpack23 {
97
99
template <typename T>
98
100
concept EnumLike = std::is_enum_v<T>;
99
101
102
+ template <typename T>
103
+ struct is_variant : std::false_type {
104
+ };
105
+
106
+ template <typename ... Types>
107
+ struct is_variant <std::variant<Types...> > : std::true_type {
108
+ };
109
+
110
+ template <typename T>
111
+ inline constexpr bool is_variant_v = is_variant<T>::value;
112
+
113
+ template <typename T>
114
+ concept VariantLike = is_variant_v<T>;
115
+
100
116
template <typename T, std::enable_if_t <std::is_integral_v<T>, int > = 0 >
101
117
[[nodiscard]] constexpr T to_big_endian (T const value) noexcept {
102
118
if constexpr (std::endian::native == std::endian::little) {
@@ -183,7 +199,7 @@ namespace msgpack23 {
183
199
}
184
200
185
201
template <CollectionLike T>
186
- requires (!MapLike<T> && !EnumLike<T>)
202
+ requires (!MapLike<T>) && ( !EnumLike<T>)
187
203
void pack_type (T const &value) {
188
204
if (!pack_array_header (value.size ())) {
189
205
throw std::length_error (" Collection is too long to be serialized." );
@@ -199,7 +215,43 @@ namespace msgpack23 {
199
215
}
200
216
201
217
template <typename T>
202
- requires (!CollectionLike<T> && !MapLike<T> && !EnumLike<T>)
218
+ requires VariantLike<T>
219
+ void pack_type (T const &value) {
220
+ std::vector<std::byte> data{};
221
+ std::visit ([this , &data](auto const &arg) {
222
+ Packer packer{};
223
+ data = packer (arg);
224
+ }, value);
225
+ auto const index = static_cast <std::int8_t >(value.index ());
226
+ if (index > 127 ) {
227
+ throw std::overflow_error (" Variant index is to large to be serialized." );
228
+ }
229
+ if (data.size () == 1 ) {
230
+ emplace_constant (FormatConstants::fixext1);
231
+ } else if (data.size () == 2 ) {
232
+ emplace_constant (FormatConstants::fixext2);
233
+ } else if (data.size () == 4 ) {
234
+ emplace_constant (FormatConstants::fixext4);
235
+ } else if (data.size () == 8 ) {
236
+ emplace_constant (FormatConstants::fixext8);
237
+ } else if (data.size () < std::numeric_limits<std::uint8_t >::max ()) {
238
+ emplace_constant (FormatConstants::ext8);
239
+ emplace_integral (static_cast <std::uint8_t >(data.size ()));
240
+ } else if (data.size () < std::numeric_limits<std::uint16_t >::max ()) {
241
+ emplace_constant (FormatConstants::ext16);
242
+ emplace_integral (static_cast <std::uint16_t >(data.size ()));
243
+ } else if (data.size () < std::numeric_limits<std::uint32_t >::max ()) {
244
+ emplace_constant (FormatConstants::ext32);
245
+ emplace_integral (static_cast <std::uint32_t >(data.size ()));
246
+ } else {
247
+ throw std::length_error (" Variant is too long to be serialized." );
248
+ }
249
+ emplace_integral (index );
250
+ data_.insert (data_.end (), data.begin (), data.end ());
251
+ }
252
+
253
+ template <typename T>
254
+ requires (!CollectionLike<T>) && (!MapLike<T>) && (!EnumLike<T>) && (!VariantLike<T>)
203
255
void pack_type (T const &value) {
204
256
value.pack (*this );
205
257
}
@@ -476,6 +528,18 @@ namespace msgpack23 {
476
528
return false ;
477
529
}
478
530
531
+ template <typename Variant, std::size_t Index = 0 >
532
+ Variant create_variant_by_index (std::size_t const i) {
533
+ if constexpr (Index < std::variant_size_v<Variant>) {
534
+ if (i == Index) {
535
+ return Variant{std::in_place_index<Index>};
536
+ }
537
+ return create_variant_by_index<Variant, Index + 1 >(i);
538
+ } else {
539
+ throw std::logic_error (" Invalid variant index" );
540
+ }
541
+ }
542
+
479
543
[[nodiscard]] std::size_t unpack_map_header () {
480
544
std::size_t map_size = 0 ;
481
545
if (read_conditional<FormatConstants::map32, std::uint32_t >(map_size)) {
@@ -514,7 +578,7 @@ namespace msgpack23 {
514
578
}
515
579
516
580
template <CollectionLike T>
517
- requires (!MapLike<T> && EmplaceAvailable<T> && (!EnumLike<T>) )
581
+ requires (!MapLike<T>) && EmplaceAvailable<T> && (!EnumLike<T>)
518
582
void unpack_type (T &value) {
519
583
using ValueType = typename T::value_type;
520
584
auto const array_size = unpack_array_header ();
@@ -526,7 +590,7 @@ namespace msgpack23 {
526
590
}
527
591
528
592
template <CollectionLike T>
529
- requires (!MapLike<T> && (!EmplaceAvailable<T>) && (!EnumLike<T>) )
593
+ requires (!MapLike<T>) && (!EmplaceAvailable<T>) && (!EnumLike<T>)
530
594
void unpack_type (T &value) {
531
595
using ValueType = typename T::value_type;
532
596
std::vector<ValueType> vec;
@@ -540,7 +604,52 @@ namespace msgpack23 {
540
604
}
541
605
542
606
template <typename T>
543
- requires (!CollectionLike<T> && !MapLike<T> && !EnumLike<T>)
607
+ requires VariantLike<T>
608
+ void unpack_type (T &value) {
609
+ std::size_t size = 0 ;
610
+ if (check_constant (FormatConstants::fixext1)) {
611
+ increment ();
612
+ size = 1 ;
613
+ } else if (check_constant (FormatConstants::fixext2)) {
614
+ increment ();
615
+ size = 2 ;
616
+ } else if (check_constant (FormatConstants::fixext4)) {
617
+ increment ();
618
+ size = 4 ;
619
+ } else if (check_constant (FormatConstants::fixext8)) {
620
+ increment ();
621
+ size = 8 ;
622
+ } else if (check_constant (FormatConstants::ext8)) {
623
+ increment ();
624
+ size = read_integral<std::uint8_t >();
625
+ } else if (check_constant (FormatConstants::ext16)) {
626
+ increment ();
627
+ size = read_integral<std::uint16_t >();
628
+ } else if (check_constant (FormatConstants::ext32)) {
629
+ increment ();
630
+ size = read_integral<std::uint32_t >();
631
+ } else {
632
+ throw std::logic_error (" Unexpected format for std::variant" );
633
+ }
634
+ auto const index = static_cast <std::int8_t >(read_integral<std::uint8_t >());
635
+
636
+ if (index < 0 || index > static_cast <std::int8_t >(std::variant_size_v<T> - 1 )) {
637
+ throw std::out_of_range (" Invalid variant index" );
638
+ }
639
+
640
+ auto const data_start = data_.subspan (position_, size);
641
+ increment (size);
642
+
643
+ value = create_variant_by_index<T>(index );
644
+
645
+ std::visit ([this , &data_start](auto &arg) {
646
+ Unpacker unpacker (data_start);
647
+ unpacker (arg);
648
+ }, value);
649
+ }
650
+
651
+ template <typename T>
652
+ requires (!CollectionLike<T>) && (!MapLike<T>) && (!EnumLike<T>) && (!VariantLike<T>)
544
653
void unpack_type (T &value) {
545
654
value.unpack (*this );
546
655
}
0 commit comments