diff --git a/include/msgpack/adaptor/cpp17/variant.hpp b/include/msgpack/adaptor/cpp17/variant.hpp new file mode 100644 index 00000000..bd73ff9a --- /dev/null +++ b/include/msgpack/adaptor/cpp17/variant.hpp @@ -0,0 +1,16 @@ +// +// MessagePack for C++ static resolution routine +// +// Copyright (C) 2023 Uy Ha +// +// 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) +// + +#ifndef MSGPACK_TYPE_CPP17_VARIANT_HPP +#define MSGPACK_TYPE_CPP17_VARIANT_HPP + +#include "msgpack/v1/adaptor/cpp17/variant.hpp" + +#endif // MSGPACK_TYPE_CPP17_VARIANT_HPP diff --git a/include/msgpack/type.hpp b/include/msgpack/type.hpp index e48bdade..f90dfb16 100644 --- a/include/msgpack/type.hpp +++ b/include/msgpack/type.hpp @@ -63,6 +63,10 @@ #include "adaptor/cpp17/carray_byte.hpp" #include "adaptor/cpp17/vector_byte.hpp" +#if MSGPACK_HAS_INCLUDE() +#include "adaptor/cpp17/variant.hpp" +#endif // MSGPACK_HAS_INCLUDE() + #if MSGPACK_HAS_INCLUDE() #include "adaptor/cpp20/span.hpp" #endif // MSGPACK_HAS_INCLUDE() diff --git a/include/msgpack/v1/adaptor/cpp17/variant.hpp b/include/msgpack/v1/adaptor/cpp17/variant.hpp new file mode 100644 index 00000000..1e6bad59 --- /dev/null +++ b/include/msgpack/v1/adaptor/cpp17/variant.hpp @@ -0,0 +1,133 @@ +// +// MessagePack for C++ static resolution routine +// +// Copyright (C) 2023 Uy Ha +// +// 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) +// + +#ifndef MSGPACK_V1_TYPE_VARIANT_HPP +#define MSGPACK_V1_TYPE_VARIANT_HPP + +#define MSGPACK_USE_STD_VARIANT_ADAPTOR + +#if defined(MSGPACK_USE_STD_VARIANT_ADAPTOR) + +#include "msgpack/cpp_version.hpp" + +#if MSGPACK_CPP_VERSION >= 201703 + +#include "msgpack/adaptor/adaptor_base.hpp" +#include "msgpack/object.hpp" +#include "msgpack/versioning.hpp" + +#include + +namespace msgpack { +MSGPACK_API_VERSION_NAMESPACE(v1) { + namespace adaptor { + namespace detail { + template + Variant construct_variant(std::size_t index, + msgpack::object &object, + std::index_sequence) { + if constexpr(sizeof...(Ts) == 0) { + return object.as(); + } else { + if (index == current_index) { + return object.as(); + } + return construct_variant(index, object, std::index_sequence()); + } + } + + } // namespace detail + + template + struct as, std::enable_if_t<(msgpack::has_as::value && ...)>> { + std::variant operator()(msgpack::object const &o) const { + if (o.type != msgpack::type::ARRAY) { + throw msgpack::type_error{}; + } + if (o.via.array.size != 2) { + throw msgpack::type_error{}; + } + if (o.via.array.ptr[0].type != msgpack::type::POSITIVE_INTEGER) { + throw msgpack::type_error{}; + } + return detail::construct_variant, Ts...>( + o.via.array.ptr[0].as(), + o.via.array.ptr[1], + std::make_index_sequence() + ); + } + }; + + template + struct convert> { + msgpack::object const &operator()(msgpack::object const &o, std::variant &v) const { + if (o.type != msgpack::type::ARRAY) { + throw msgpack::type_error{}; + } + if (o.via.array.size != 2) { + throw msgpack::type_error{}; + } + if (o.via.array.ptr[0].type != msgpack::type::POSITIVE_INTEGER) { + throw msgpack::type_error{}; + } + v = detail::construct_variant, Ts...>( + o.via.array.ptr[0].as(), + o.via.array.ptr[1], + std::make_index_sequence() + ); + return o; + } + }; + + template + struct pack>{ + template + msgpack::packer& operator()(msgpack::packer &o, std::variant const &v) const { + o.pack_array(2); + o.pack_uint64(v.index()); + std::visit([&o](auto const &real_value){o.pack(real_value);}, v); + return o; + } + }; + + // template + // struct object> { + // void operator()(msgpack::object &o, std::variant const &v) const { + // o.type = msgpack::type::ARRAY; + // o.via.array.size = 2; + // msgpack::adaptor::object(o.via.array.ptr[0], v.index()); + // std::visit([&o](auto const &value) { + // msgpack::adaptor::object(o.via.array.ptr[1], value); + // }, v); + // } + // }; + // + // template + // struct object_with_zone> { + // void operator()(msgpack::object::with_zone &o, std::variant const &v) const { + // o.type = msgpack::type::ARRAY; + // + // msgpack::object *p = static_cast(o.zone.allocate_align(sizeof(msgpack::object) * 2, MSGPACK_ZONE_ALIGNOF(msgpack::object))); + // + // o.via.array.size = 2; + // o.via.array.ptr = p; + // msgpack::adaptor::object_with_zone()(o.via.array.ptr[0], v.index(), o.zone); + // std::visit([&o](auto const &real_value){ + // o.via.array.ptr[1] = msgpack::adaptor::object()(real_value, o.zone); + // }, v); + // } + // }; + } // namespace adaptor +} +} // namespace msgpack + +#endif // MSGPACK_CPP_VERSION >= 201703 +#endif // defined(MSGPACK_USE_STD_VARIANT_ADAPTOR) +#endif // MSGPACK_V1_TYPE_VARIANT_HPP diff --git a/test/msgpack_cpp17.cpp b/test/msgpack_cpp17.cpp index c90a55ad..742a58b6 100644 --- a/test/msgpack_cpp17.cpp +++ b/test/msgpack_cpp17.cpp @@ -461,4 +461,15 @@ BOOST_AUTO_TEST_CASE(carray_byte_object_with_zone) } } +BOOST_AUTO_TEST_CASE(variant_as) { + std::stringstream ss; + std::variant val1{1.0}; + msgpack::pack(ss, val1); + std::string const& str = ss.str(); + msgpack::object_handle oh = + msgpack::unpack(str.data(), str.size()); + std::variant val2 = oh.get().as >(); + BOOST_CHECK(val1 == val2); +} + #endif // MSGPACK_CPP_VERSION >= 201703