File indexing completed on 2025-09-18 09:04:21
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_REDIS_ADAPTER_RESPONSE_TRAITS_HPP
0008 #define BOOST_REDIS_ADAPTER_RESPONSE_TRAITS_HPP
0009
0010 #include <boost/redis/error.hpp>
0011 #include <boost/redis/resp3/type.hpp>
0012 #include <boost/redis/ignore.hpp>
0013 #include <boost/redis/adapter/detail/adapters.hpp>
0014 #include <boost/redis/adapter/result.hpp>
0015 #include <boost/redis/adapter/ignore.hpp>
0016 #include <boost/mp11.hpp>
0017
0018 #include <vector>
0019 #include <tuple>
0020 #include <string_view>
0021 #include <variant>
0022
0023 namespace boost::redis::adapter::detail
0024 {
0025
0026
0027
0028
0029
0030
0031 template <class Result>
0032 struct result_traits {
0033 using adapter_type = wrapper<typename std::decay<Result>::type>;
0034 static auto adapt(Result& r) noexcept { return adapter_type{&r}; }
0035 };
0036
0037 template <>
0038 struct result_traits<result<ignore_t>> {
0039 using response_type = result<ignore_t>;
0040 using adapter_type = ignore;
0041 static auto adapt(response_type) noexcept { return adapter_type{}; }
0042 };
0043
0044 template <>
0045 struct result_traits<ignore_t> {
0046 using response_type = ignore_t;
0047 using adapter_type = ignore;
0048 static auto adapt(response_type) noexcept { return adapter_type{}; }
0049 };
0050
0051 template <class T>
0052 struct result_traits<result<resp3::basic_node<T>>> {
0053 using response_type = result<resp3::basic_node<T>>;
0054 using adapter_type = adapter::detail::general_simple<response_type>;
0055 static auto adapt(response_type& v) noexcept { return adapter_type{&v}; }
0056 };
0057
0058 template <class String, class Allocator>
0059 struct result_traits<result<std::vector<resp3::basic_node<String>, Allocator>>> {
0060 using response_type = result<std::vector<resp3::basic_node<String>, Allocator>>;
0061 using adapter_type = adapter::detail::general_aggregate<response_type>;
0062 static auto adapt(response_type& v) noexcept { return adapter_type{&v}; }
0063 };
0064
0065 template <class T>
0066 using adapter_t = typename result_traits<std::decay_t<T>>::adapter_type;
0067
0068 template<class T>
0069 auto internal_adapt(T& t) noexcept
0070 { return result_traits<std::decay_t<T>>::adapt(t); }
0071
0072 template <std::size_t N>
0073 struct assigner {
0074 template <class T1, class T2>
0075 static void assign(T1& dest, T2& from)
0076 {
0077 dest[N].template emplace<N>(internal_adapt(std::get<N>(from)));
0078 assigner<N - 1>::assign(dest, from);
0079 }
0080 };
0081
0082 template <>
0083 struct assigner<0> {
0084 template <class T1, class T2>
0085 static void assign(T1& dest, T2& from)
0086 {
0087 dest[0].template emplace<0>(internal_adapt(std::get<0>(from)));
0088 }
0089 };
0090
0091 template <class Tuple>
0092 class static_aggregate_adapter;
0093
0094 template <class Tuple>
0095 class static_aggregate_adapter<result<Tuple>> {
0096 private:
0097 using adapters_array_type =
0098 std::array<
0099 mp11::mp_rename<
0100 mp11::mp_transform<
0101 adapter_t, Tuple>,
0102 std::variant>,
0103 std::tuple_size<Tuple>::value>;
0104
0105
0106 std::size_t i_ = 0;
0107
0108
0109 std::size_t aggregate_size_ = 0;
0110
0111 adapters_array_type adapters_;
0112 result<Tuple>* res_ = nullptr;
0113
0114 public:
0115 explicit static_aggregate_adapter(result<Tuple>* r = nullptr)
0116 {
0117 if (r) {
0118 res_ = r;
0119 detail::assigner<std::tuple_size<Tuple>::value - 1>::assign(adapters_, r->value());
0120 }
0121 }
0122
0123 template <class String>
0124 void count(resp3::basic_node<String> const& elem)
0125 {
0126 if (elem.depth == 1 && is_aggregate(elem.data_type)) {
0127 aggregate_size_ = element_multiplicity(elem.data_type) * elem.aggregate_size;
0128 }
0129
0130 if (aggregate_size_ == 0) {
0131 i_ += 1;
0132 } else {
0133 aggregate_size_ -= 1;
0134 }
0135 }
0136
0137 template <class String>
0138 void operator()(resp3::basic_node<String> const& elem, system::error_code& ec)
0139 {
0140 using std::visit;
0141
0142 if (elem.depth == 0) {
0143 auto const multiplicity = element_multiplicity(elem.data_type);
0144 auto const real_aggr_size = elem.aggregate_size * multiplicity;
0145 if (real_aggr_size != std::tuple_size<Tuple>::value)
0146 ec = redis::error::incompatible_size;
0147
0148 return;
0149 }
0150
0151 visit([&](auto& arg){arg(elem, ec);}, adapters_[i_]);
0152 count(elem);
0153 }
0154 };
0155
0156 template <class... Ts>
0157 struct result_traits<result<std::tuple<Ts...>>>
0158 {
0159 using response_type = result<std::tuple<Ts...>>;
0160 using adapter_type = static_aggregate_adapter<response_type>;
0161 static auto adapt(response_type& r) noexcept { return adapter_type{&r}; }
0162 };
0163
0164 }
0165
0166 #endif