libcarla/include/carla/MsgPackAdaptors.h
2024-10-18 13:19:59 +08:00

172 lines
5.5 KiB
C++

// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "carla/Exception.h"
#include "carla/MsgPack.h"
#include <boost/optional.hpp>
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4583)
#pragma warning(disable:4582)
#include <boost/variant2/variant.hpp>
#pragma warning(pop)
#else
#include <boost/variant2/variant.hpp>
#endif
#include <tuple>
namespace clmdep_msgpack {
MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS) {
namespace adaptor {
// ===========================================================================
// -- Adaptors for boost::optional -------------------------------------------
// ===========================================================================
template<typename T>
struct convert<boost::optional<T>> {
const clmdep_msgpack::object &operator()(
const clmdep_msgpack::object &o,
boost::optional<T> &v) const {
if (o.type != clmdep_msgpack::type::ARRAY) {
::carla::throw_exception(clmdep_msgpack::type_error());
}
if (o.via.array.size == 1) {
v.reset();
} else if (o.via.array.size == 2) {
v.reset(o.via.array.ptr[1].as<T>());
} else {
::carla::throw_exception(clmdep_msgpack::type_error());
}
return o;
}
};
template<typename T>
struct pack<boost::optional<T>> {
template <typename Stream>
packer<Stream> &operator()(
clmdep_msgpack::packer<Stream> &o,
const boost::optional<T> &v) const {
if (v.has_value()) {
o.pack_array(2);
o.pack(true);
o.pack(*v);
} else {
o.pack_array(1);
o.pack(false);
}
return o;
}
};
template<typename T>
struct object_with_zone<boost::optional<T>> {
void operator()(
clmdep_msgpack::object::with_zone &o,
const boost::optional<T> &v) const {
o.type = type::ARRAY;
if (v.has_value()) {
o.via.array.size = 2;
o.via.array.ptr = static_cast<clmdep_msgpack::object*>(o.zone.allocate_align(
sizeof(clmdep_msgpack::object) * o.via.array.size,
MSGPACK_ZONE_ALIGNOF(clmdep_msgpack::object)));
o.via.array.ptr[0] = clmdep_msgpack::object(true, o.zone);
o.via.array.ptr[1] = clmdep_msgpack::object(*v, o.zone);
} else {
o.via.array.size = 1;
o.via.array.ptr = static_cast<clmdep_msgpack::object*>(o.zone.allocate_align(
sizeof(clmdep_msgpack::object) * o.via.array.size,
MSGPACK_ZONE_ALIGNOF(clmdep_msgpack::object)));
o.via.array.ptr[0] = clmdep_msgpack::object(false, o.zone);
}
}
};
// ===========================================================================
// -- Adaptors for boost::variant2::variant ----------------------------------
// ===========================================================================
template<typename... Ts>
struct convert<boost::variant2::variant<Ts...>> {
const clmdep_msgpack::object &operator()(
const clmdep_msgpack::object &o,
boost::variant2::variant<Ts...> &v) const {
if (o.type != clmdep_msgpack::type::ARRAY) {
::carla::throw_exception(clmdep_msgpack::type_error());
}
if (o.via.array.size != 2) {
::carla::throw_exception(clmdep_msgpack::type_error());
}
const auto index = o.via.array.ptr[0].as<uint64_t>();
copy_to_variant(index, o, v, std::make_index_sequence<sizeof...(Ts)>());
return o;
}
private:
template <uint64_t I>
static void copy_to_variant_impl(
const clmdep_msgpack::object &o,
boost::variant2::variant<Ts...> &v) {
/// @todo Workaround for finding the type.
auto dummy = std::get<I>(std::tuple<Ts...>{});
using T = decltype(dummy);
v = o.via.array.ptr[1].as<T>();
}
template <uint64_t... Is>
static void copy_to_variant(
const uint64_t index,
const clmdep_msgpack::object &o,
boost::variant2::variant<Ts...> &v,
std::index_sequence<Is...>) {
std::initializer_list<int> ({
(index == Is ? copy_to_variant_impl<Is>(o, v), 0 : 0)...
});
}
};
template<typename... Ts>
struct pack<boost::variant2::variant<Ts...>> {
template <typename Stream>
packer<Stream> &operator()(
clmdep_msgpack::packer<Stream> &o,
const boost::variant2::variant<Ts...> &v) const {
o.pack_array(2);
o.pack(static_cast<uint64_t>(v.index()));
boost::variant2::visit([&](const auto &value) { o.pack(value); }, v);
return o;
}
};
template<typename... Ts>
struct object_with_zone<boost::variant2::variant<Ts...>> {
void operator()(
clmdep_msgpack::object::with_zone &o,
const boost::variant2::variant<Ts...> &v) const {
o.type = type::ARRAY;
o.via.array.size = 2;
o.via.array.ptr = static_cast<clmdep_msgpack::object*>(o.zone.allocate_align(
sizeof(clmdep_msgpack::object) * o.via.array.size,
MSGPACK_ZONE_ALIGNOF(clmdep_msgpack::object)));
o.via.array.ptr[0] = clmdep_msgpack::object(static_cast<uint64_t>(v.index()), o.zone);
boost::variant2::visit([&](const auto &value) {
o.via.array.ptr[1] = clmdep_msgpack::object(value, o.zone);
}, v);
}
};
} // namespace adaptor
} // MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS)
} // namespace msgpack