7#ifndef BOOST_REDIS_ADAPTER_ADAPTERS_HPP
8#define BOOST_REDIS_ADAPTER_ADAPTERS_HPP
10#include <boost/redis/error.hpp>
11#include <boost/redis/resp3/type.hpp>
12#include <boost/redis/resp3/serialization.hpp>
13#include <boost/redis/resp3/node.hpp>
14#include <boost/redis/adapter/result.hpp>
15#include <boost/assert.hpp>
19#include <unordered_set>
20#include <forward_list>
21#include <system_error>
23#include <unordered_map>
38namespace boost::redis::adapter::detail
44auto boost_redis_from_bulk(T& i, std::string_view sv, system::error_code& ec) ->
typename std::enable_if<std::is_integral<T>::value,
void>
::type
46 auto const res = std::from_chars(sv.data(), sv.data() + std::size(sv), i);
47 if (res.ec != std::errc())
52void boost_redis_from_bulk(
bool& t, std::string_view sv, system::error_code&)
54 t = *sv.data() ==
't';
58void boost_redis_from_bulk(
double& d, std::string_view sv, system::error_code& ec)
64 std::string
const tmp{sv.data(), sv.data() + std::size(sv)};
66 d = std::strtod(tmp.data(), &end);
67 if (d == HUGE_VAL || d == 0)
70 auto const res = std::from_chars(sv.data(), sv.data() + std::size(sv), d);
71 if (res.ec != std::errc())
76template <
class CharT,
class Traits,
class Allocator>
79 std::basic_string<CharT, Traits, Allocator>& s,
83 s.append(sv.data(), sv.size());
88template <
class Result>
89class general_aggregate {
94 explicit general_aggregate(Result* c =
nullptr): result_(c) {}
95 void operator()(resp3::basic_node<std::string_view>
const& nd, system::error_code&)
97 BOOST_ASSERT_MSG(!!result_,
"Unexpected null pointer");
98 switch (nd.data_type) {
101 *result_ =
error{nd.data_type, std::string{std::cbegin(nd.value), std::cend(nd.value)}};
104 result_->value().push_back({nd.data_type, nd.aggregate_size, nd.depth, std::string{std::cbegin(nd.value), std::cend(nd.value)}});
110class general_simple {
115 explicit general_simple(Node* t =
nullptr) : result_(t) {}
117 void operator()(resp3::basic_node<std::string_view>
const& nd, system::error_code&)
119 BOOST_ASSERT_MSG(!!result_,
"Unexpected null pointer");
120 switch (nd.data_type) {
123 *result_ =
error{nd.data_type, std::string{std::cbegin(nd.value), std::cend(nd.value)}};
126 result_->value().data_type = nd.data_type;
127 result_->value().aggregate_size = nd.aggregate_size;
128 result_->value().depth = nd.depth;
129 result_->value().value.assign(nd.value.data(), nd.value.size());
134template <
class Result>
137 void on_value_available(Result&) {}
142 resp3::basic_node<std::string_view>
const& n,
143 system::error_code& ec)
145 if (is_aggregate(n.data_type)) {
150 boost_redis_from_bulk(
result, n.value, ec);
154template <
class Result>
157 typename Result::iterator hint_;
160 void on_value_available(Result&
result)
161 { hint_ = std::end(
result); }
166 resp3::basic_node<std::string_view>
const& nd,
167 system::error_code& ec)
169 if (is_aggregate(nd.data_type)) {
175 BOOST_ASSERT(nd.aggregate_size == 1);
182 typename Result::key_type obj;
183 boost_redis_from_bulk(obj, nd.value, ec);
184 hint_ =
result.insert(hint_, std::move(obj));
188template <
class Result>
191 typename Result::iterator current_;
195 void on_value_available(Result&
result)
196 { current_ = std::end(
result); }
201 resp3::basic_node<std::string_view>
const& nd,
202 system::error_code& ec)
204 if (is_aggregate(nd.data_type)) {
205 if (element_multiplicity(nd.data_type) != 2)
210 BOOST_ASSERT(nd.aggregate_size == 1);
218 typename Result::key_type obj;
219 boost_redis_from_bulk(obj, nd.value, ec);
220 current_ =
result.insert(current_, {std::move(obj), {}});
222 typename Result::mapped_type obj;
223 boost_redis_from_bulk(obj, nd.value, ec);
224 current_->second = std::move(obj);
231template <
class Result>
234 void on_value_available(Result& ) { }
239 resp3::basic_node<std::string_view>
const& nd,
240 system::error_code& ec)
242 if (is_aggregate(nd.data_type)) {
243 auto const m = element_multiplicity(nd.data_type);
247 boost_redis_from_bulk(
result.back(), nd.value, ec);
252template <
class Result>
258 void on_value_available(Result& ) { }
263 resp3::basic_node<std::string_view>
const& nd,
264 system::error_code& ec)
266 if (is_aggregate(nd.data_type)) {
272 if (
result.size() != nd.aggregate_size * element_multiplicity(nd.data_type)) {
282 BOOST_ASSERT(nd.aggregate_size == 1);
283 boost_redis_from_bulk(
result.at(i_), nd.value, ec);
290template <
class Result>
293 void on_value_available(Result& ) { }
298 resp3::basic_node<std::string_view>
const& nd,
299 system::error_code& ec)
301 if (!is_aggregate(nd.data_type)) {
302 BOOST_ASSERT(nd.aggregate_size == 1);
309 boost_redis_from_bulk(
result.back(), nd.value, ec);
317struct impl_map {
using type = simple_impl<T>; };
319template <
class Key,
class Compare,
class Allocator>
320struct impl_map<std::
set<Key, Compare, Allocator>> {
using type = set_impl<std::set<Key, Compare, Allocator>>; };
322template <
class Key,
class Compare,
class Allocator>
323struct impl_map<std::multiset<Key, Compare, Allocator>> {
using type = set_impl<std::multiset<Key, Compare, Allocator>>; };
325template <
class Key,
class Hash,
class KeyEqual,
class Allocator>
326struct impl_map<std::unordered_set<Key, Hash, KeyEqual, Allocator>> {
using type = set_impl<std::unordered_set<Key, Hash, KeyEqual, Allocator>>; };
328template <
class Key,
class Hash,
class KeyEqual,
class Allocator>
329struct impl_map<std::unordered_multiset<Key, Hash, KeyEqual, Allocator>> {
using type = set_impl<std::unordered_multiset<Key, Hash, KeyEqual, Allocator>>; };
331template <
class Key,
class T,
class Compare,
class Allocator>
332struct impl_map<std::
map<Key, T, Compare, Allocator>> {
using type = map_impl<std::map<Key, T, Compare, Allocator>>; };
334template <
class Key,
class T,
class Compare,
class Allocator>
335struct impl_map<std::multimap<Key, T, Compare, Allocator>> {
using type = map_impl<std::multimap<Key, T, Compare, Allocator>>; };
337template <
class Key,
class Hash,
class KeyEqual,
class Allocator>
338struct impl_map<std::unordered_map<Key, Hash, KeyEqual, Allocator>> {
using type = map_impl<std::unordered_map<Key, Hash, KeyEqual, Allocator>>; };
340template <
class Key,
class Hash,
class KeyEqual,
class Allocator>
341struct impl_map<std::unordered_multimap<Key, Hash, KeyEqual, Allocator>> {
using type = map_impl<std::unordered_multimap<Key, Hash, KeyEqual, Allocator>>; };
343template <
class T,
class Allocator>
344struct impl_map<std::vector<T, Allocator>> {
using type = vector_impl<std::vector<T, Allocator>>; };
346template <
class T, std::
size_t N>
347struct impl_map<std::
array<T, N>> {
using type = array_impl<std::array<T, N>>; };
349template <
class T,
class Allocator>
350struct impl_map<std::list<T, Allocator>> {
using type = list_impl<std::list<T, Allocator>>; };
352template <
class T,
class Allocator>
353struct impl_map<std::deque<T, Allocator>> {
using type = list_impl<std::deque<T, Allocator>>; };
360template <
class Result>
361class wrapper<
result<Result>> {
363 using response_type = result<Result>;
365 response_type* result_;
368 bool set_if_resp3_error(resp3::basic_node<std::string_view>
const& nd)
noexcept
370 switch (nd.data_type) {
374 *result_ =
error{nd.data_type, {std::cbegin(nd.value), std::cend(nd.value)}};
382 explicit wrapper(response_type* t =
nullptr) : result_(t)
385 result_->value() = Result{};
386 impl_.on_value_available(result_->value());
392 resp3::basic_node<std::string_view>
const& nd,
393 system::error_code& ec)
395 BOOST_ASSERT_MSG(!!result_,
"Unexpected null pointer");
397 if (result_->has_error())
400 if (set_if_resp3_error(nd))
403 BOOST_ASSERT(result_);
404 impl_(result_->value(), nd, ec);
409class wrapper<
result<std::optional<T>>> {
411 using response_type = result<std::optional<T>>;
414 response_type* result_;
417 bool set_if_resp3_error(resp3::basic_node<std::string_view>
const& nd)
noexcept
419 switch (nd.data_type) {
422 *result_ =
error{nd.data_type, {std::cbegin(nd.value), std::cend(nd.value)}};
430 explicit wrapper(response_type* o =
nullptr) : result_(o) {}
434 resp3::basic_node<std::string_view>
const& nd,
435 system::error_code& ec)
437 BOOST_ASSERT_MSG(!!result_,
"Unexpected null pointer");
439 if (result_->has_error())
442 if (set_if_resp3_error(nd))
448 if (!result_->value().has_value()) {
449 result_->value() = T{};
450 impl_.on_value_available(result_->value().value());
453 impl_(result_->value().value(), nd, ec);
system::result< Value, error > result
Stores response to individual Redis commands.
@ expects_resp3_set
Expects a set aggregate but got something else.
@ incompatible_size
Aggregate container has incompatible size.
@ not_a_number
Can't parse the string as a number.
@ nested_aggregate_not_supported
Nested response not supported.
@ expects_resp3_map
Expects a map but got other aggregate.
@ not_a_double
Not a double.
@ expects_resp3_aggregate
Expects aggregate.
@ expects_resp3_simple_type
Expects a simple RESP3 type but got an aggregate.