serialization.hpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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. #ifndef BOOST_REDIS_RESP3_SERIALIZATION_HPP
  7. #define BOOST_REDIS_RESP3_SERIALIZATION_HPP
  8. #include <boost/redis/resp3/parser.hpp>
  9. #include <boost/redis/resp3/type.hpp>
  10. #include <boost/system/system_error.hpp>
  11. #include <boost/throw_exception.hpp>
  12. #include <string>
  13. #include <tuple>
  14. // NOTE: Consider detecting tuples in the type in the parameter pack
  15. // to calculate the header size correctly.
  16. namespace boost::redis::resp3 {
  17. /** @brief Adds a bulk to the request.
  18. * @relates boost::redis::request
  19. *
  20. * This function is useful in serialization of your own data
  21. * structures in a request. For example
  22. *
  23. * @code
  24. * void boost_redis_to_bulk(std::string& payload, mystruct const& obj)
  25. * {
  26. * auto const str = // Convert obj to a string.
  27. * boost_redis_to_bulk(payload, str);
  28. * }
  29. * @endcode
  30. *
  31. * @param payload Storage on which data will be copied into.
  32. * @param data Data that will be serialized and stored in `payload`.
  33. */
  34. void boost_redis_to_bulk(std::string& payload, std::string_view data);
  35. template <class T, typename = typename std::enable_if<std::is_integral<T>::value>::type>
  36. void boost_redis_to_bulk(std::string& payload, T n)
  37. {
  38. auto const s = std::to_string(n);
  39. boost::redis::resp3::boost_redis_to_bulk(payload, std::string_view{s});
  40. }
  41. template <class T>
  42. struct add_bulk_impl {
  43. static void add(std::string& payload, T const& from)
  44. {
  45. using namespace boost::redis::resp3;
  46. boost_redis_to_bulk(payload, from);
  47. }
  48. };
  49. template <class... Ts>
  50. struct add_bulk_impl<std::tuple<Ts...>> {
  51. static void add(std::string& payload, std::tuple<Ts...> const& t)
  52. {
  53. auto f = [&](auto const&... vs) {
  54. using namespace boost::redis::resp3;
  55. (boost_redis_to_bulk(payload, vs), ...);
  56. };
  57. std::apply(f, t);
  58. }
  59. };
  60. template <class U, class V>
  61. struct add_bulk_impl<std::pair<U, V>> {
  62. static void add(std::string& payload, std::pair<U, V> const& from)
  63. {
  64. using namespace boost::redis::resp3;
  65. boost_redis_to_bulk(payload, from.first);
  66. boost_redis_to_bulk(payload, from.second);
  67. }
  68. };
  69. void add_header(std::string& payload, type t, std::size_t size);
  70. template <class T>
  71. void add_bulk(std::string& payload, T const& data)
  72. {
  73. add_bulk_impl<T>::add(payload, data);
  74. }
  75. template <class>
  76. struct bulk_counter;
  77. template <class>
  78. struct bulk_counter {
  79. static constexpr auto size = 1U;
  80. };
  81. template <class T, class U>
  82. struct bulk_counter<std::pair<T, U>> {
  83. static constexpr auto size = 2U;
  84. };
  85. void add_blob(std::string& payload, std::string_view blob);
  86. void add_separator(std::string& payload);
  87. namespace detail {
  88. template <class Adapter>
  89. void deserialize(std::string_view const& data, Adapter adapter, system::error_code& ec)
  90. {
  91. adapter.on_init();
  92. parser parser;
  93. while (!parser.done()) {
  94. auto const res = parser.consume(data, ec);
  95. if (ec)
  96. return;
  97. BOOST_ASSERT(res.has_value());
  98. adapter.on_node(res.value(), ec);
  99. if (ec)
  100. return;
  101. }
  102. BOOST_ASSERT(parser.get_consumed() == std::size(data));
  103. adapter.on_done();
  104. }
  105. template <class Adapter>
  106. void deserialize(std::string_view const& data, Adapter adapter)
  107. {
  108. system::error_code ec;
  109. deserialize(data, adapter, ec);
  110. if (ec)
  111. BOOST_THROW_EXCEPTION(system::system_error{ec});
  112. }
  113. } // namespace detail
  114. } // namespace boost::redis::resp3
  115. #endif // BOOST_REDIS_RESP3_SERIALIZATION_HPP