Loading [MathJax]/extensions/tex2jax.js
Loading...
Searching...
No Matches
result_traits.hpp
1/* Copyright (c) 2018-2024 Marcelo Zimbres Silva (mzimbres@gmail.com)
2 *
3 * Distributed under the Boost Software License, Version 1.0. (See
4 * accompanying file LICENSE.txt)
5 */
6
7#ifndef BOOST_REDIS_ADAPTER_RESPONSE_TRAITS_HPP
8#define BOOST_REDIS_ADAPTER_RESPONSE_TRAITS_HPP
9
10#include <boost/redis/error.hpp>
11#include <boost/redis/resp3/type.hpp>
12#include <boost/redis/ignore.hpp>
13#include <boost/redis/adapter/detail/adapters.hpp>
14#include <boost/redis/adapter/result.hpp>
15#include <boost/redis/adapter/ignore.hpp>
16#include <boost/mp11.hpp>
17
18#include <vector>
19#include <tuple>
20#include <string_view>
21#include <variant>
22
23namespace boost::redis::adapter::detail
24{
25
26/* Traits class for response objects.
27 *
28 * Provides traits for all supported response types i.e. all STL
29 * containers and C++ buil-in types.
30 */
31template <class Result>
32struct result_traits {
33 using adapter_type = wrapper<typename std::decay<Result>::type>;
34 static auto adapt(Result& r) noexcept { return adapter_type{&r}; }
35};
36
37template <>
38struct result_traits<result<ignore_t>> {
39 using response_type = result<ignore_t>;
40 using adapter_type = ignore;
41 static auto adapt(response_type) noexcept { return adapter_type{}; }
42};
43
44template <>
45struct result_traits<ignore_t> {
46 using response_type = ignore_t;
47 using adapter_type = ignore;
48 static auto adapt(response_type) noexcept { return adapter_type{}; }
49};
50
51template <class T>
52struct result_traits<result<resp3::basic_node<T>>> {
53 using response_type = result<resp3::basic_node<T>>;
54 using adapter_type = adapter::detail::general_simple<response_type>;
55 static auto adapt(response_type& v) noexcept { return adapter_type{&v}; }
56};
57
58template <class String, class Allocator>
59struct result_traits<result<std::vector<resp3::basic_node<String>, Allocator>>> {
60 using response_type = result<std::vector<resp3::basic_node<String>, Allocator>>;
61 using adapter_type = adapter::detail::general_aggregate<response_type>;
62 static auto adapt(response_type& v) noexcept { return adapter_type{&v}; }
63};
64
65template <class T>
66using adapter_t = typename result_traits<std::decay_t<T>>::adapter_type;
67
68template<class T>
69auto internal_adapt(T& t) noexcept
70 { return result_traits<std::decay_t<T>>::adapt(t); }
71
72template <std::size_t N>
73struct assigner {
74 template <class T1, class T2>
75 static void assign(T1& dest, T2& from)
76 {
77 dest[N].template emplace<N>(internal_adapt(std::get<N>(from)));
78 assigner<N - 1>::assign(dest, from);
79 }
80};
81
82template <>
83struct assigner<0> {
84 template <class T1, class T2>
85 static void assign(T1& dest, T2& from)
86 {
87 dest[0].template emplace<0>(internal_adapt(std::get<0>(from)));
88 }
89};
90
91template <class Tuple>
92class static_aggregate_adapter;
93
94template <class Tuple>
95class static_aggregate_adapter<result<Tuple>> {
96private:
97 using adapters_array_type =
98 std::array<
99 mp11::mp_rename<
100 mp11::mp_transform<
101 adapter_t, Tuple>,
102 std::variant>,
103 std::tuple_size<Tuple>::value>;
104
105 // Tuple element we are currently on.
106 std::size_t i_ = 0;
107
108 // Nested aggregate element counter.
109 std::size_t aggregate_size_ = 0;
110
111 adapters_array_type adapters_;
112 result<Tuple>* res_ = nullptr;
113
114public:
115 explicit static_aggregate_adapter(result<Tuple>* r = nullptr)
116 {
117 if (r) {
118 res_ = r;
119 detail::assigner<std::tuple_size<Tuple>::value - 1>::assign(adapters_, r->value());
120 }
121 }
122
123 template <class String>
124 void count(resp3::basic_node<String> const& elem)
125 {
126 if (elem.depth == 1 && is_aggregate(elem.data_type)) {
127 aggregate_size_ = element_multiplicity(elem.data_type) * elem.aggregate_size;
128 }
129
130 if (aggregate_size_ == 0) {
131 i_ += 1;
132 } else {
133 aggregate_size_ -= 1;
134 }
135 }
136
137 template <class String>
138 void operator()(resp3::basic_node<String> const& elem, system::error_code& ec)
139 {
140 using std::visit;
141
142 if (elem.depth == 0) {
143 auto const multiplicity = element_multiplicity(elem.data_type);
144 auto const real_aggr_size = elem.aggregate_size * multiplicity;
145 if (real_aggr_size != std::tuple_size<Tuple>::value)
147
148 return;
149 }
150
151 visit([&](auto& arg){arg(elem, ec);}, adapters_[i_]);
152 count(elem);
153 }
154};
155
156template <class... Ts>
157struct result_traits<result<std::tuple<Ts...>>>
158{
159 using response_type = result<std::tuple<Ts...>>;
160 using adapter_type = static_aggregate_adapter<response_type>;
161 static auto adapt(response_type& r) noexcept { return adapter_type{&r}; }
162};
163
164} // boost::redis::adapter::detail
165
166#endif // BOOST_REDIS_ADAPTER_RESPONSE_TRAITS_HPP
ignore_t ignore
Global ignore object.
system::result< Value, error > result
Stores response to individual Redis commands.
Definition result.hpp:56
std::decay_t< decltype(std::ignore)> ignore_t
Type used to ignore responses.
Definition ignore.hpp:31
@ incompatible_size
Aggregate container has incompatible size.