response_traits.hpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /* Copyright (c) 2018-2023 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. #ifndef BOOST_REDIS_ADAPTER_DETAIL_RESPONSE_TRAITS_HPP
  7. #define BOOST_REDIS_ADAPTER_DETAIL_RESPONSE_TRAITS_HPP
  8. #include <boost/redis/resp3/node.hpp>
  9. #include <boost/redis/response.hpp>
  10. #include <boost/redis/adapter/detail/result_traits.hpp>
  11. #include <boost/mp11.hpp>
  12. #include <boost/system.hpp>
  13. #include <tuple>
  14. #include <limits>
  15. #include <string_view>
  16. #include <variant>
  17. namespace boost::redis::adapter::detail
  18. {
  19. class ignore_adapter {
  20. public:
  21. template <class String>
  22. void operator()(std::size_t, resp3::basic_node<String> const& nd, system::error_code& ec)
  23. {
  24. switch (nd.data_type) {
  25. case resp3::type::simple_error: ec = redis::error::resp3_simple_error; break;
  26. case resp3::type::blob_error: ec = redis::error::resp3_blob_error; break;
  27. case resp3::type::null: ec = redis::error::resp3_null; break;
  28. default:;
  29. }
  30. }
  31. [[nodiscard]]
  32. auto get_supported_response_size() const noexcept
  33. { return static_cast<std::size_t>(-1);}
  34. };
  35. template <class Response>
  36. class static_adapter {
  37. private:
  38. static constexpr auto size = std::tuple_size<Response>::value;
  39. using adapter_tuple = mp11::mp_transform<adapter_t, Response>;
  40. using variant_type = mp11::mp_rename<adapter_tuple, std::variant>;
  41. using adapters_array_type = std::array<variant_type, size>;
  42. adapters_array_type adapters_;
  43. public:
  44. explicit static_adapter(Response& r)
  45. {
  46. assigner<size - 1>::assign(adapters_, r);
  47. }
  48. [[nodiscard]]
  49. auto get_supported_response_size() const noexcept
  50. { return size;}
  51. template <class String>
  52. void operator()(std::size_t i, resp3::basic_node<String> const& nd, system::error_code& ec)
  53. {
  54. using std::visit;
  55. // I am usure whether this should be an error or an assertion.
  56. BOOST_ASSERT(i < adapters_.size());
  57. visit([&](auto& arg){arg(nd, ec);}, adapters_.at(i));
  58. }
  59. };
  60. template <class Vector>
  61. class vector_adapter {
  62. private:
  63. using adapter_type = typename result_traits<Vector>::adapter_type;
  64. adapter_type adapter_;
  65. public:
  66. explicit vector_adapter(Vector& v)
  67. : adapter_{internal_adapt(v)}
  68. { }
  69. [[nodiscard]]
  70. auto
  71. get_supported_response_size() const noexcept
  72. { return static_cast<std::size_t>(-1);}
  73. template <class String>
  74. void operator()(std::size_t, resp3::basic_node<String> const& nd, system::error_code& ec)
  75. {
  76. adapter_(nd, ec);
  77. }
  78. };
  79. template <class>
  80. struct response_traits;
  81. template <>
  82. struct response_traits<ignore_t> {
  83. using response_type = ignore_t;
  84. using adapter_type = detail::ignore_adapter;
  85. static auto adapt(response_type&) noexcept
  86. { return detail::ignore_adapter{}; }
  87. };
  88. template <>
  89. struct response_traits<result<ignore_t>> {
  90. using response_type = result<ignore_t>;
  91. using adapter_type = detail::ignore_adapter;
  92. static auto adapt(response_type&) noexcept
  93. { return detail::ignore_adapter{}; }
  94. };
  95. template <class String, class Allocator>
  96. struct response_traits<result<std::vector<resp3::basic_node<String>, Allocator>>> {
  97. using response_type = result<std::vector<resp3::basic_node<String>, Allocator>>;
  98. using adapter_type = vector_adapter<response_type>;
  99. static auto adapt(response_type& v) noexcept
  100. { return adapter_type{v}; }
  101. };
  102. template <class ...Ts>
  103. struct response_traits<response<Ts...>> {
  104. using response_type = response<Ts...>;
  105. using adapter_type = static_adapter<response_type>;
  106. static auto adapt(response_type& r) noexcept
  107. { return adapter_type{r}; }
  108. };
  109. template <class Adapter>
  110. class wrapper {
  111. public:
  112. explicit wrapper(Adapter adapter) : adapter_{adapter} {}
  113. template <class String>
  114. void operator()(resp3::basic_node<String> const& nd, system::error_code& ec)
  115. { return adapter_(0, nd, ec); }
  116. [[nodiscard]]
  117. auto get_supported_response_size() const noexcept
  118. { return adapter_.get_supported_response_size();}
  119. private:
  120. Adapter adapter_;
  121. };
  122. template <class Adapter>
  123. auto make_adapter_wrapper(Adapter adapter)
  124. {
  125. return wrapper{adapter};
  126. }
  127. } // boost::redis::adapter::detail
  128. #endif // BOOST_REDIS_ADAPTER_DETAIL_RESPONSE_TRAITS_HPP