#pragma once #include "for_each_field.hpp" #include "stream.hpp" #include #include #include #include #include namespace eosio { struct no_conversion { using reverse = no_conversion; }; struct widening_conversion; // Fields must match exactly struct strict_conversion { using reverse = strict_conversion; }; // Can discard some fields struct narrowing_conversion { using reverse = widening_conversion; }; // Can default construct some fields struct widening_conversion { using reverse = narrowing_conversion; }; no_conversion conversion_kind(...); void serialize_as(...); template using serialization_type = decltype(serialize_as(std::declval())); template using conversion_kind_t = std::conditional_t(), std::declval())), no_conversion>, typename decltype(conversion_kind(std::declval(), std::declval()))::reverse, decltype(conversion_kind(std::declval(), std::declval()))>; template auto convert_impl(Field field, const T& src, U& dst, F&& f, int) -> std::void_t { convert(field(&src), field(&dst), f); } template auto convert_impl(Field field, const T& src, U& dst, F&& f, long) { static_assert(!std::is_same_v, strict_conversion>, "Member not found"); static_assert(!std::is_same_v, widening_conversion>, "Member not found"); } inline constexpr auto choose_first = [](auto src, auto dest) { return src; }; inline constexpr auto choose_second = [](auto src, auto dest) { return dest; }; // TODO: add some validation template void convert(const T& src, U& dst, F&& chooser) { if constexpr (std::is_same_v) { dst = src; } else { static_assert(!std::is_same_v, no_conversion>, "Conversion not defined"); for_each_field>( [&](const char*, auto field) { convert_impl(field, src, dst, chooser, 0); }); } } template void convert(const std::variant& src, U& dst, F&& chooser) { std::visit([&](auto& src) { return convert(src, dst, chooser); }, src); } template void convert(const std::vector& src, std::vector& dst, F&& chooser) { dst.resize(src.size()); for (std::size_t i = 0; i < src.size(); ++i) { convert(src[i], dst[i], chooser); } } template void convert(const std::optional& src, std::optional& dst, F&& chooser) { if (src) { dst.emplace(); convert(*src, *dst, chooser); } else { dst = std::nullopt; } } struct stream; template void convert(const input_stream& src, std::vector& dst, F&& chooser) { dst.assign(src.pos, src.end); } } // namespace eosio