any_adapter.hpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /* Copyright (c) 2018-2025 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_ANY_ADAPTER_HPP
  7. #define BOOST_REDIS_ANY_ADAPTER_HPP
  8. #include <boost/redis/adapter/adapt.hpp>
  9. #include <boost/redis/resp3/node.hpp>
  10. #include <boost/system/error_code.hpp>
  11. #include <cstddef>
  12. #include <functional>
  13. #include <string_view>
  14. #include <type_traits>
  15. namespace boost::redis {
  16. /** @brief A type-erased reference to a response.
  17. *
  18. * A type-erased response adapter. It can be executed using @ref connection::async_exec.
  19. * Using this type instead of raw response references enables separate compilation.
  20. *
  21. * Given a response object `resp` that can be passed to `async_exec`, the following two
  22. * statements have the same effect:
  23. *
  24. * @code
  25. * co_await conn.async_exec(req, resp);
  26. * co_await conn.async_exec(req, any_response(resp));
  27. * @endcode
  28. */
  29. class any_adapter {
  30. public:
  31. /** @brief Parse events that an adapter must support.
  32. */
  33. enum class parse_event
  34. {
  35. /// Called before the parser starts processing data
  36. init,
  37. /// Called for each and every node of RESP3 data
  38. node,
  39. /// Called when done processing a complete RESP3 message
  40. done
  41. };
  42. /// The type erased implementation type.
  43. using impl_t = std::function<void(parse_event, resp3::node_view const&, system::error_code&)>;
  44. template <class T>
  45. static auto create_impl(T& resp) -> impl_t
  46. {
  47. using namespace boost::redis::adapter;
  48. return [adapter2 = boost_redis_adapt(resp)](
  49. any_adapter::parse_event ev,
  50. resp3::node_view const& nd,
  51. system::error_code& ec) mutable {
  52. switch (ev) {
  53. case parse_event::init: adapter2.on_init(); break;
  54. case parse_event::node: adapter2.on_node(nd, ec); break;
  55. case parse_event::done: adapter2.on_done(); break;
  56. }
  57. };
  58. }
  59. /// Contructs from a type erased adaper
  60. any_adapter(impl_t fn = [](parse_event, resp3::node_view const&, system::error_code&) { })
  61. : impl_{std::move(fn)}
  62. { }
  63. /**
  64. * @brief Constructor.
  65. *
  66. * Creates a type-erased response adapter from `resp` by calling
  67. * `boost_redis_adapt`. `T` must be a valid Redis response type.
  68. * Any type passed to @ref connection::async_exec qualifies.
  69. *
  70. * This object stores a reference to `resp`, which must be kept alive
  71. * while `*this` is being used.
  72. */
  73. template <class T, class = std::enable_if_t<!std::is_same_v<T, any_adapter>>>
  74. explicit any_adapter(T& resp)
  75. : impl_(create_impl(resp))
  76. { }
  77. /// Calls the implementation with the arguments `impl_(parse_event::init, ...);`
  78. void on_init()
  79. {
  80. system::error_code ec;
  81. impl_(parse_event::init, {}, ec);
  82. };
  83. /// Calls the implementation with the arguments `impl_(parse_event::done, ...);`
  84. void on_done()
  85. {
  86. system::error_code ec;
  87. impl_(parse_event::done, {}, ec);
  88. };
  89. /// Calls the implementation with the arguments `impl_(parse_event::node, ...);`
  90. void on_node(resp3::node_view const& nd, system::error_code& ec)
  91. {
  92. impl_(parse_event::node, nd, ec);
  93. };
  94. private:
  95. impl_t impl_;
  96. };
  97. } // namespace boost::redis
  98. #endif