serialization.hpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /* Copyright (c) 2018-2023 Marcelo Zimbres Silva ([email protected])
  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/type.hpp>
  9. #include <boost/system/system_error.hpp>
  10. #include <boost/throw_exception.hpp>
  11. #include <boost/redis/resp3/parser.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. * See more in @ref serialization.
  35. */
  36. void boost_redis_to_bulk(std::string& payload, std::string_view data);
  37. template <class T, typename = typename std::enable_if<std::is_integral<T>::value>::type>
  38. void boost_redis_to_bulk(std::string& payload, T n)
  39. {
  40. auto const s = std::to_string(n);
  41. boost::redis::resp3::boost_redis_to_bulk(payload, std::string_view{s});
  42. }
  43. template <class T>
  44. struct add_bulk_impl {
  45. static void add(std::string& payload, T const& from)
  46. {
  47. using namespace boost::redis::resp3;
  48. boost_redis_to_bulk(payload, from);
  49. }
  50. };
  51. template <class ...Ts>
  52. struct add_bulk_impl<std::tuple<Ts...>> {
  53. static void add(std::string& payload, std::tuple<Ts...> const& t)
  54. {
  55. auto f = [&](auto const&... vs)
  56. {
  57. using namespace boost::redis::resp3;
  58. (boost_redis_to_bulk(payload, vs), ...);
  59. };
  60. std::apply(f, t);
  61. }
  62. };
  63. template <class U, class V>
  64. struct add_bulk_impl<std::pair<U, V>> {
  65. static void add(std::string& payload, std::pair<U, V> const& from)
  66. {
  67. using namespace boost::redis::resp3;
  68. boost_redis_to_bulk(payload, from.first);
  69. boost_redis_to_bulk(payload, from.second);
  70. }
  71. };
  72. void add_header(std::string& payload, type t, std::size_t size);
  73. template <class T>
  74. void add_bulk(std::string& payload, T const& data)
  75. {
  76. add_bulk_impl<T>::add(payload, data);
  77. }
  78. template <class>
  79. struct bulk_counter;
  80. template <class>
  81. struct bulk_counter {
  82. static constexpr auto size = 1U;
  83. };
  84. template <class T, class U>
  85. struct bulk_counter<std::pair<T, U>> {
  86. static constexpr auto size = 2U;
  87. };
  88. void add_blob(std::string& payload, std::string_view blob);
  89. void add_separator(std::string& payload);
  90. namespace detail
  91. {
  92. template <class Adapter>
  93. void deserialize(std::string_view const& data, Adapter adapter, system::error_code& ec)
  94. {
  95. parser parser;
  96. while (!parser.done()) {
  97. auto const res = parser.consume(data, ec);
  98. if (ec)
  99. return;
  100. BOOST_ASSERT(res.has_value());
  101. adapter(res.value(), ec);
  102. if (ec)
  103. return;
  104. }
  105. BOOST_ASSERT(parser.get_consumed() == std::size(data));
  106. }
  107. template <class Adapter>
  108. void deserialize(std::string_view const& data, Adapter adapter)
  109. {
  110. system::error_code ec;
  111. deserialize(data, adapter, ec);
  112. if (ec)
  113. BOOST_THROW_EXCEPTION(system::system_error{ec});
  114. }
  115. }
  116. } // boost::redis::resp3
  117. #endif // BOOST_REDIS_RESP3_SERIALIZATION_HPP