/* Copyright (c) 2018-2023 Marcelo Zimbres Silva (mzimbres@gmail.com) * * Distributed under the Boost Software License, Version 1.0. (See * accompanying file LICENSE.txt) */ #ifndef BOOST_REDIS_ADAPTER_RESPONSE_TRAITS_HPP #define BOOST_REDIS_ADAPTER_RESPONSE_TRAITS_HPP #include #include #include #include #include #include #include #include #include #include #include namespace boost::redis::adapter::detail { /* Traits class for response objects. * * Provides traits for all supported response types i.e. all STL * containers and C++ buil-in types. */ template struct result_traits { using adapter_type = adapter::detail::wrapper::type>; static auto adapt(Result& r) noexcept { return adapter_type{&r}; } }; template <> struct result_traits> { using response_type = result; using adapter_type = ignore; static auto adapt(response_type) noexcept { return adapter_type{}; } }; template <> struct result_traits { using response_type = ignore_t; using adapter_type = ignore; static auto adapt(response_type) noexcept { return adapter_type{}; } }; template struct result_traits>> { using response_type = result>; using adapter_type = adapter::detail::general_simple; static auto adapt(response_type& v) noexcept { return adapter_type{&v}; } }; template struct result_traits, Allocator>>> { using response_type = result, Allocator>>; using adapter_type = adapter::detail::general_aggregate; static auto adapt(response_type& v) noexcept { return adapter_type{&v}; } }; template using adapter_t = typename result_traits>::adapter_type; template auto internal_adapt(T& t) noexcept { return result_traits>::adapt(t); } template struct assigner { template static void assign(T1& dest, T2& from) { dest[N].template emplace(internal_adapt(std::get(from))); assigner::assign(dest, from); } }; template <> struct assigner<0> { template static void assign(T1& dest, T2& from) { dest[0].template emplace<0>(internal_adapt(std::get<0>(from))); } }; template class static_aggregate_adapter; template class static_aggregate_adapter> { private: using adapters_array_type = std::array< mp11::mp_rename< mp11::mp_transform< adapter_t, Tuple>, std::variant>, std::tuple_size::value>; std::size_t i_ = 0; std::size_t aggregate_size_ = 0; adapters_array_type adapters_; result* res_ = nullptr; public: explicit static_aggregate_adapter(result* r = nullptr) { if (r) { res_ = r; detail::assigner::value - 1>::assign(adapters_, r->value()); } } template void count(resp3::basic_node const& nd) { if (nd.depth == 1) { if (is_aggregate(nd.data_type)) aggregate_size_ = element_multiplicity(nd.data_type) * nd.aggregate_size; else ++i_; return; } if (--aggregate_size_ == 0) ++i_; } template void operator()(resp3::basic_node const& nd, system::error_code& ec) { using std::visit; if (nd.depth == 0) { auto const real_aggr_size = nd.aggregate_size * element_multiplicity(nd.data_type); if (real_aggr_size != std::tuple_size::value) ec = redis::error::incompatible_size; return; } visit([&](auto& arg){arg(nd, ec);}, adapters_[i_]); count(nd); } }; template struct result_traits>> { using response_type = result>; using adapter_type = static_aggregate_adapter; static auto adapt(response_type& r) noexcept { return adapter_type{&r}; } }; } // boost::redis::adapter::detail #endif // BOOST_REDIS_ADAPTER_RESPONSE_TRAITS_HPP