145 lines
3.5 KiB
C++
145 lines
3.5 KiB
C++
|
/* Copyright (c) 2018-2023 Marcelo Zimbres Silva (mzimbres@gmail.com)
|
||
|
*
|
||
|
* Distributed under the Boost Software License, Version 1.0. (See
|
||
|
* accompanying file LICENSE.txt)
|
||
|
*/
|
||
|
|
||
|
#ifndef BOOST_REDIS_RESP3_SERIALIZATION_HPP
|
||
|
#define BOOST_REDIS_RESP3_SERIALIZATION_HPP
|
||
|
|
||
|
#include <boost/redis/resp3/type.hpp>
|
||
|
#include <boost/system/system_error.hpp>
|
||
|
#include <boost/throw_exception.hpp>
|
||
|
#include <boost/redis/resp3/parser.hpp>
|
||
|
|
||
|
#include <string>
|
||
|
#include <tuple>
|
||
|
|
||
|
// NOTE: Consider detecting tuples in the type in the parameter pack
|
||
|
// to calculate the header size correctly.
|
||
|
|
||
|
namespace boost::redis::resp3 {
|
||
|
|
||
|
/** @brief Adds a bulk to the request.
|
||
|
* @relates boost::redis::request
|
||
|
*
|
||
|
* This function is useful in serialization of your own data
|
||
|
* structures in a request. For example
|
||
|
*
|
||
|
* @code
|
||
|
* void boost_redis_to_bulk(std::string& payload, mystruct const& obj)
|
||
|
* {
|
||
|
* auto const str = // Convert obj to a string.
|
||
|
* boost_redis_to_bulk(payload, str);
|
||
|
* }
|
||
|
* @endcode
|
||
|
*
|
||
|
* @param payload Storage on which data will be copied into.
|
||
|
* @param data Data that will be serialized and stored in `payload`.
|
||
|
*
|
||
|
* See more in @ref serialization.
|
||
|
*/
|
||
|
void boost_redis_to_bulk(std::string& payload, std::string_view data);
|
||
|
|
||
|
template <class T, typename = typename std::enable_if<std::is_integral<T>::value>::type>
|
||
|
void boost_redis_to_bulk(std::string& payload, T n)
|
||
|
{
|
||
|
auto const s = std::to_string(n);
|
||
|
boost::redis::resp3::boost_redis_to_bulk(payload, std::string_view{s});
|
||
|
}
|
||
|
|
||
|
template <class T>
|
||
|
struct add_bulk_impl {
|
||
|
static void add(std::string& payload, T const& from)
|
||
|
{
|
||
|
using namespace boost::redis::resp3;
|
||
|
boost_redis_to_bulk(payload, from);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template <class ...Ts>
|
||
|
struct add_bulk_impl<std::tuple<Ts...>> {
|
||
|
static void add(std::string& payload, std::tuple<Ts...> const& t)
|
||
|
{
|
||
|
auto f = [&](auto const&... vs)
|
||
|
{
|
||
|
using namespace boost::redis::resp3;
|
||
|
(boost_redis_to_bulk(payload, vs), ...);
|
||
|
};
|
||
|
|
||
|
std::apply(f, t);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template <class U, class V>
|
||
|
struct add_bulk_impl<std::pair<U, V>> {
|
||
|
static void add(std::string& payload, std::pair<U, V> const& from)
|
||
|
{
|
||
|
using namespace boost::redis::resp3;
|
||
|
boost_redis_to_bulk(payload, from.first);
|
||
|
boost_redis_to_bulk(payload, from.second);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
void add_header(std::string& payload, type t, std::size_t size);
|
||
|
|
||
|
template <class T>
|
||
|
void add_bulk(std::string& payload, T const& data)
|
||
|
{
|
||
|
add_bulk_impl<T>::add(payload, data);
|
||
|
}
|
||
|
|
||
|
template <class>
|
||
|
struct bulk_counter;
|
||
|
|
||
|
template <class>
|
||
|
struct bulk_counter {
|
||
|
static constexpr auto size = 1U;
|
||
|
};
|
||
|
|
||
|
template <class T, class U>
|
||
|
struct bulk_counter<std::pair<T, U>> {
|
||
|
static constexpr auto size = 2U;
|
||
|
};
|
||
|
|
||
|
void add_blob(std::string& payload, std::string_view blob);
|
||
|
void add_separator(std::string& payload);
|
||
|
|
||
|
namespace detail
|
||
|
{
|
||
|
|
||
|
template <class Adapter>
|
||
|
void deserialize(std::string_view const& data, Adapter adapter, system::error_code& ec)
|
||
|
{
|
||
|
parser parser;
|
||
|
while (!parser.done()) {
|
||
|
auto const res = parser.consume(data, ec);
|
||
|
if (ec)
|
||
|
return;
|
||
|
|
||
|
BOOST_ASSERT(res.has_value());
|
||
|
|
||
|
adapter(res.value(), ec);
|
||
|
if (ec)
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
BOOST_ASSERT(parser.get_consumed() == std::size(data));
|
||
|
}
|
||
|
|
||
|
template <class Adapter>
|
||
|
void deserialize(std::string_view const& data, Adapter adapter)
|
||
|
{
|
||
|
system::error_code ec;
|
||
|
deserialize(data, adapter, ec);
|
||
|
|
||
|
if (ec)
|
||
|
BOOST_THROW_EXCEPTION(system::system_error{ec});
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
} // boost::redis::resp3
|
||
|
|
||
|
#endif // BOOST_REDIS_RESP3_SERIALIZATION_HPP
|