mirror of
https://github.com/boostorg/redis.git
synced 2026-01-19 04:42:09 +00:00
Moves read functions from resp3:: to redis::.
This commit is contained in:
@@ -9,10 +9,11 @@
|
||||
|
||||
#include <boost/asio/connect.hpp>
|
||||
#include <boost/redis.hpp>
|
||||
#include <boost/redis/write.hpp>
|
||||
#include <boost/redis/src.hpp>
|
||||
|
||||
namespace net = boost::asio;
|
||||
namespace resp3 = boost::redis::resp3;
|
||||
namespace redis = boost::redis;
|
||||
using boost::redis::adapter::adapt2;
|
||||
using boost::redis::request;
|
||||
using boost::redis::adapter::result;
|
||||
@@ -39,16 +40,16 @@ auto main(int argc, char * argv[]) -> int
|
||||
req.push("HELLO", 3);
|
||||
req.push("PING", "Hello world");
|
||||
req.push("QUIT");
|
||||
resp3::write(socket, req);
|
||||
redis::write(socket, req);
|
||||
|
||||
std::string buffer;
|
||||
result<std::string> resp;
|
||||
|
||||
// Reads the responses to all commands in the request.
|
||||
auto dbuffer = net::dynamic_buffer(buffer);
|
||||
resp3::read(socket, dbuffer);
|
||||
resp3::read(socket, dbuffer, adapt2(resp));
|
||||
resp3::read(socket, dbuffer);
|
||||
redis::read(socket, dbuffer);
|
||||
redis::read(socket, dbuffer, adapt2(resp));
|
||||
redis::read(socket, dbuffer);
|
||||
|
||||
std::cout << "Ping: " << resp.value() << std::endl;
|
||||
|
||||
|
||||
@@ -7,11 +7,12 @@
|
||||
#include <boost/asio.hpp>
|
||||
#if defined(BOOST_ASIO_HAS_CO_AWAIT)
|
||||
#include <boost/redis.hpp>
|
||||
#include <boost/redis/write.hpp>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
namespace net = boost::asio;
|
||||
namespace resp3 = boost::redis::resp3;
|
||||
namespace redis = boost::redis;
|
||||
using resolver = net::use_awaitable_t<>::as_default_on_t<net::ip::tcp::resolver>;
|
||||
using tcp_socket = net::use_awaitable_t<>::as_default_on_t<net::ip::tcp::socket>;
|
||||
using boost::redis::adapter::adapt2;
|
||||
@@ -33,7 +34,7 @@ auto co_main(std::string host, std::string port) -> net::awaitable<void>
|
||||
req.push("HELLO", 3);
|
||||
req.push("PING", "Hello world");
|
||||
req.push("QUIT");
|
||||
co_await resp3::async_write(socket, req);
|
||||
co_await redis::async_write(socket, req);
|
||||
|
||||
// Responses
|
||||
std::string buffer;
|
||||
@@ -41,9 +42,9 @@ auto co_main(std::string host, std::string port) -> net::awaitable<void>
|
||||
|
||||
// Reads the responses to all commands in the request.
|
||||
auto dbuffer = net::dynamic_buffer(buffer);
|
||||
co_await resp3::async_read(socket, dbuffer);
|
||||
co_await resp3::async_read(socket, dbuffer, adapt2(resp));
|
||||
co_await resp3::async_read(socket, dbuffer);
|
||||
co_await redis::async_read(socket, dbuffer);
|
||||
co_await redis::async_read(socket, dbuffer, adapt2(resp));
|
||||
co_await redis::async_read(socket, dbuffer);
|
||||
|
||||
std::cout << "Ping: " << resp.value() << std::endl;
|
||||
}
|
||||
|
||||
@@ -7,13 +7,38 @@
|
||||
#ifndef BOOST_REDIS_ADAPTER_ADAPT_HPP
|
||||
#define BOOST_REDIS_ADAPTER_ADAPT_HPP
|
||||
|
||||
#include <boost/redis/resp3/node.hpp>
|
||||
#include <boost/redis/response.hpp>
|
||||
#include <boost/redis/adapter/detail/result_traits.hpp>
|
||||
#include <boost/redis/adapter/detail/response_traits.hpp>
|
||||
#include <boost/mp11.hpp>
|
||||
#include <boost/system.hpp>
|
||||
|
||||
#include <tuple>
|
||||
#include <limits>
|
||||
#include <string_view>
|
||||
#include <variant>
|
||||
|
||||
namespace boost::redis::adapter
|
||||
{
|
||||
|
||||
template <class T>
|
||||
using adapter_t = typename detail::adapter_t<T>;
|
||||
/** @brief Adapts a type to be used as a response.
|
||||
*
|
||||
* The type T must be either
|
||||
*
|
||||
* 1. a response<T1, T2, T3, ...> or
|
||||
* 2. std::vector<node<String>>
|
||||
*
|
||||
* The types T1, T2, etc can be any STL container, any integer type
|
||||
* and `std::string`.
|
||||
*
|
||||
* @param t Tuple containing the responses.
|
||||
*/
|
||||
template<class T>
|
||||
auto boost_redis_adapt(T& t) noexcept
|
||||
{
|
||||
return detail::response_traits<T>::adapt(t);
|
||||
}
|
||||
|
||||
/** @brief Adapts user data to read operations.
|
||||
* @ingroup low-level-api
|
||||
@@ -48,7 +73,7 @@ using adapter_t = typename detail::adapter_t<T>;
|
||||
*/
|
||||
template<class T>
|
||||
auto adapt2(T& t = redis::ignore) noexcept
|
||||
{ return detail::response_traits<T>::adapt(t); }
|
||||
{ return detail::result_traits<T>::adapt(t); }
|
||||
|
||||
} // boost::redis::adapter
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include <boost/redis/error.hpp>
|
||||
#include <boost/redis/resp3/type.hpp>
|
||||
#include <boost/redis/resp3/serialization.hpp>
|
||||
#include <boost/redis/resp3/detail/parser.hpp>
|
||||
#include <boost/redis/resp3/node.hpp>
|
||||
#include <boost/redis/adapter/result.hpp>
|
||||
#include <boost/redis/adapter/ignore.hpp>
|
||||
|
||||
@@ -4,157 +4,162 @@
|
||||
* accompanying file LICENSE.txt)
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REDIS_ADAPTER_RESPONSE_TRAITS_HPP
|
||||
#define BOOST_REDIS_ADAPTER_RESPONSE_TRAITS_HPP
|
||||
#ifndef BOOST_REDIS_ADAPTER_DETAIL_RESPONSE_TRAITS_HPP
|
||||
#define BOOST_REDIS_ADAPTER_DETAIL_RESPONSE_TRAITS_HPP
|
||||
|
||||
#include <boost/redis/error.hpp>
|
||||
#include <boost/redis/resp3/type.hpp>
|
||||
#include <boost/redis/ignore.hpp>
|
||||
#include <boost/redis/adapter/detail/adapters.hpp>
|
||||
#include <boost/redis/adapter/result.hpp>
|
||||
#include <boost/redis/resp3/node.hpp>
|
||||
#include <boost/redis/response.hpp>
|
||||
#include <boost/redis/adapter/detail/result_traits.hpp>
|
||||
#include <boost/mp11.hpp>
|
||||
#include <boost/system.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <limits>
|
||||
#include <string_view>
|
||||
#include <variant>
|
||||
|
||||
namespace boost::redis::adapter::detail
|
||||
{
|
||||
|
||||
/* Traits class for response objects.
|
||||
*
|
||||
* Provides traits for all supported response types i.e. all STL
|
||||
* containers and C++ buil-in types.
|
||||
*/
|
||||
class ignore_adapter {
|
||||
public:
|
||||
void
|
||||
operator()(std::size_t, resp3::node<std::string_view> const& nd, system::error_code& ec)
|
||||
{
|
||||
switch (nd.data_type) {
|
||||
case resp3::type::simple_error: ec = redis::error::resp3_simple_error; break;
|
||||
case resp3::type::blob_error: ec = redis::error::resp3_blob_error; break;
|
||||
case resp3::type::null: ec = redis::error::resp3_null; break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
auto get_supported_response_size() const noexcept
|
||||
{ return static_cast<std::size_t>(-1);}
|
||||
};
|
||||
|
||||
template <class Response>
|
||||
struct response_traits {
|
||||
using adapter_type = adapter::detail::wrapper<typename std::decay<Response>::type>;
|
||||
static auto adapt(Response& r) noexcept { return adapter_type{&r}; }
|
||||
class static_adapter {
|
||||
private:
|
||||
static constexpr auto size = std::tuple_size<Response>::value;
|
||||
using adapter_tuple = mp11::mp_transform<adapter_t, Response>;
|
||||
using variant_type = mp11::mp_rename<adapter_tuple, std::variant>;
|
||||
using adapters_array_type = std::array<variant_type, size>;
|
||||
|
||||
adapters_array_type adapters_;
|
||||
|
||||
public:
|
||||
explicit static_adapter(Response& r)
|
||||
{
|
||||
assigner<size - 1>::assign(adapters_, r);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
auto get_supported_response_size() const noexcept
|
||||
{ return size;}
|
||||
|
||||
void
|
||||
operator()(
|
||||
std::size_t i,
|
||||
resp3::node<std::string_view> const& nd,
|
||||
system::error_code& ec)
|
||||
{
|
||||
using std::visit;
|
||||
// I am usure whether this should be an error or an assertion.
|
||||
BOOST_ASSERT(i < adapters_.size());
|
||||
visit([&](auto& arg){arg(nd, ec);}, adapters_.at(i));
|
||||
}
|
||||
};
|
||||
|
||||
template <class Vector>
|
||||
class vector_adapter {
|
||||
private:
|
||||
using adapter_type = typename result_traits<Vector>::adapter_type;
|
||||
adapter_type adapter_;
|
||||
|
||||
public:
|
||||
explicit vector_adapter(Vector& v)
|
||||
: adapter_{internal_adapt(v)}
|
||||
{ }
|
||||
|
||||
[[nodiscard]]
|
||||
auto
|
||||
get_supported_response_size() const noexcept
|
||||
{ return static_cast<std::size_t>(-1);}
|
||||
|
||||
void
|
||||
operator()(
|
||||
std::size_t,
|
||||
resp3::node<std::string_view> const& nd,
|
||||
system::error_code& ec)
|
||||
{
|
||||
adapter_(nd, ec);
|
||||
}
|
||||
};
|
||||
|
||||
template <class>
|
||||
struct response_traits;
|
||||
|
||||
template <>
|
||||
struct response_traits<ignore_t> {
|
||||
using response_type = ignore_t;
|
||||
using adapter_type = detail::ignore_adapter;
|
||||
|
||||
static auto adapt(response_type&) noexcept
|
||||
{ return detail::ignore_adapter{}; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct response_traits<result<ignore_t>> {
|
||||
using response_type = result<ignore_t>;
|
||||
using adapter_type = ignore;
|
||||
static auto adapt(response_type) noexcept { return adapter_type{}; }
|
||||
};
|
||||
using adapter_type = detail::ignore_adapter;
|
||||
|
||||
template <>
|
||||
struct response_traits<ignore_t> {
|
||||
using response_type = ignore_t;
|
||||
using adapter_type = ignore;
|
||||
static auto adapt(response_type) noexcept { return adapter_type{}; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct response_traits<result<resp3::node<T>>> {
|
||||
using response_type = result<resp3::node<T>>;
|
||||
using adapter_type = adapter::detail::general_simple<response_type>;
|
||||
static auto adapt(response_type& v) noexcept { return adapter_type{&v}; }
|
||||
static auto adapt(response_type&) noexcept
|
||||
{ return detail::ignore_adapter{}; }
|
||||
};
|
||||
|
||||
template <class String, class Allocator>
|
||||
struct response_traits<result<std::vector<resp3::node<String>, Allocator>>> {
|
||||
using response_type = result<std::vector<resp3::node<String>, Allocator>>;
|
||||
using adapter_type = adapter::detail::general_aggregate<response_type>;
|
||||
static auto adapt(response_type& v) noexcept { return adapter_type{&v}; }
|
||||
using adapter_type = vector_adapter<response_type>;
|
||||
|
||||
static auto adapt(response_type& v) noexcept
|
||||
{ return adapter_type{v}; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using adapter_t = typename response_traits<std::decay_t<T>>::adapter_type;
|
||||
template <class ...Ts>
|
||||
struct response_traits<response<Ts...>> {
|
||||
using response_type = response<Ts...>;
|
||||
using adapter_type = static_adapter<response_type>;
|
||||
|
||||
template<class T>
|
||||
auto internal_adapt(T& t) noexcept
|
||||
{ return response_traits<std::decay_t<T>>::adapt(t); }
|
||||
|
||||
template <std::size_t N>
|
||||
struct assigner {
|
||||
template <class T1, class T2>
|
||||
static void assign(T1& dest, T2& from)
|
||||
{
|
||||
dest[N].template emplace<N>(internal_adapt(std::get<N>(from)));
|
||||
assigner<N - 1>::assign(dest, from);
|
||||
}
|
||||
static auto adapt(response_type& r) noexcept
|
||||
{ return adapter_type{r}; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct assigner<0> {
|
||||
template <class T1, class T2>
|
||||
static void assign(T1& dest, T2& from)
|
||||
{
|
||||
dest[0].template emplace<0>(internal_adapt(std::get<0>(from)));
|
||||
}
|
||||
};
|
||||
|
||||
template <class Tuple>
|
||||
class static_aggregate_adapter;
|
||||
|
||||
template <class Tuple>
|
||||
class static_aggregate_adapter<result<Tuple>> {
|
||||
private:
|
||||
using adapters_array_type =
|
||||
std::array<
|
||||
mp11::mp_rename<
|
||||
mp11::mp_transform<
|
||||
adapter_t, Tuple>,
|
||||
std::variant>,
|
||||
std::tuple_size<Tuple>::value>;
|
||||
|
||||
std::size_t i_ = 0;
|
||||
std::size_t aggregate_size_ = 0;
|
||||
adapters_array_type adapters_;
|
||||
result<Tuple>* res_ = nullptr;
|
||||
|
||||
template <class Adapter>
|
||||
class wrapper {
|
||||
public:
|
||||
explicit static_aggregate_adapter(result<Tuple>* r = nullptr)
|
||||
{
|
||||
if (r) {
|
||||
res_ = r;
|
||||
detail::assigner<std::tuple_size<Tuple>::value - 1>::assign(adapters_, r->value());
|
||||
}
|
||||
}
|
||||
explicit wrapper(Adapter adapter) : adapter_{adapter} {}
|
||||
|
||||
void count(resp3::node<std::string_view> const& nd)
|
||||
{
|
||||
if (nd.depth == 1) {
|
||||
if (is_aggregate(nd.data_type))
|
||||
aggregate_size_ = element_multiplicity(nd.data_type) * nd.aggregate_size;
|
||||
else
|
||||
++i_;
|
||||
void operator()(resp3::node<std::string_view> const& node, system::error_code& ec)
|
||||
{ return adapter_(0, node, ec); }
|
||||
|
||||
return;
|
||||
}
|
||||
[[nodiscard]]
|
||||
auto get_supported_response_size() const noexcept
|
||||
{ return adapter_.get_supported_response_size();}
|
||||
|
||||
if (--aggregate_size_ == 0)
|
||||
++i_;
|
||||
}
|
||||
|
||||
void operator()(resp3::node<std::string_view> const& nd, system::error_code& ec)
|
||||
{
|
||||
using std::visit;
|
||||
|
||||
if (nd.depth == 0) {
|
||||
auto const real_aggr_size = nd.aggregate_size * element_multiplicity(nd.data_type);
|
||||
if (real_aggr_size != std::tuple_size<Tuple>::value)
|
||||
ec = redis::error::incompatible_size;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
visit([&](auto& arg){arg(nd, ec);}, adapters_[i_]);
|
||||
count(nd);
|
||||
}
|
||||
private:
|
||||
Adapter adapter_;
|
||||
};
|
||||
|
||||
template <class... Ts>
|
||||
struct response_traits<result<std::tuple<Ts...>>>
|
||||
// TODO: Move this to adapt.hpp.
|
||||
template <class Adapter>
|
||||
auto make_adapter_wrapper(Adapter adapter)
|
||||
{
|
||||
using response_type = result<std::tuple<Ts...>>;
|
||||
using adapter_type = static_aggregate_adapter<response_type>;
|
||||
static auto adapt(response_type& r) noexcept { return adapter_type{&r}; }
|
||||
};
|
||||
return wrapper{adapter};
|
||||
}
|
||||
|
||||
} // boost::redis::adapter::detail
|
||||
|
||||
#endif // BOOST_REDIS_ADAPTER_RESPONSE_TRAITS_HPP
|
||||
#endif // BOOST_REDIS_ADAPTER_DETAIL_RESPONSE_TRAITS_HPP
|
||||
|
||||
160
include/boost/redis/adapter/detail/result_traits.hpp
Normal file
160
include/boost/redis/adapter/detail/result_traits.hpp
Normal file
@@ -0,0 +1,160 @@
|
||||
/* Copyright (c) 2018-2022 Marcelo Zimbres Silva (mzimbres@gmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE.txt)
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REDIS_ADAPTER_RESPONSE_TRAITS_HPP
|
||||
#define BOOST_REDIS_ADAPTER_RESPONSE_TRAITS_HPP
|
||||
|
||||
#include <boost/redis/error.hpp>
|
||||
#include <boost/redis/resp3/type.hpp>
|
||||
#include <boost/redis/ignore.hpp>
|
||||
#include <boost/redis/adapter/detail/adapters.hpp>
|
||||
#include <boost/redis/adapter/result.hpp>
|
||||
#include <boost/mp11.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <string_view>
|
||||
#include <variant>
|
||||
|
||||
namespace boost::redis::adapter::detail
|
||||
{
|
||||
|
||||
/* Traits class for response objects.
|
||||
*
|
||||
* Provides traits for all supported response types i.e. all STL
|
||||
* containers and C++ buil-in types.
|
||||
*/
|
||||
template <class Result>
|
||||
struct result_traits {
|
||||
using adapter_type = adapter::detail::wrapper<typename std::decay<Result>::type>;
|
||||
static auto adapt(Result& r) noexcept { return adapter_type{&r}; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct result_traits<result<ignore_t>> {
|
||||
using response_type = result<ignore_t>;
|
||||
using adapter_type = ignore;
|
||||
static auto adapt(response_type) noexcept { return adapter_type{}; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct result_traits<ignore_t> {
|
||||
using response_type = ignore_t;
|
||||
using adapter_type = ignore;
|
||||
static auto adapt(response_type) noexcept { return adapter_type{}; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct result_traits<result<resp3::node<T>>> {
|
||||
using response_type = result<resp3::node<T>>;
|
||||
using adapter_type = adapter::detail::general_simple<response_type>;
|
||||
static auto adapt(response_type& v) noexcept { return adapter_type{&v}; }
|
||||
};
|
||||
|
||||
template <class String, class Allocator>
|
||||
struct result_traits<result<std::vector<resp3::node<String>, Allocator>>> {
|
||||
using response_type = result<std::vector<resp3::node<String>, Allocator>>;
|
||||
using adapter_type = adapter::detail::general_aggregate<response_type>;
|
||||
static auto adapt(response_type& v) noexcept { return adapter_type{&v}; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using adapter_t = typename result_traits<std::decay_t<T>>::adapter_type;
|
||||
|
||||
template<class T>
|
||||
auto internal_adapt(T& t) noexcept
|
||||
{ return result_traits<std::decay_t<T>>::adapt(t); }
|
||||
|
||||
template <std::size_t N>
|
||||
struct assigner {
|
||||
template <class T1, class T2>
|
||||
static void assign(T1& dest, T2& from)
|
||||
{
|
||||
dest[N].template emplace<N>(internal_adapt(std::get<N>(from)));
|
||||
assigner<N - 1>::assign(dest, from);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct assigner<0> {
|
||||
template <class T1, class T2>
|
||||
static void assign(T1& dest, T2& from)
|
||||
{
|
||||
dest[0].template emplace<0>(internal_adapt(std::get<0>(from)));
|
||||
}
|
||||
};
|
||||
|
||||
template <class Tuple>
|
||||
class static_aggregate_adapter;
|
||||
|
||||
template <class Tuple>
|
||||
class static_aggregate_adapter<result<Tuple>> {
|
||||
private:
|
||||
using adapters_array_type =
|
||||
std::array<
|
||||
mp11::mp_rename<
|
||||
mp11::mp_transform<
|
||||
adapter_t, Tuple>,
|
||||
std::variant>,
|
||||
std::tuple_size<Tuple>::value>;
|
||||
|
||||
std::size_t i_ = 0;
|
||||
std::size_t aggregate_size_ = 0;
|
||||
adapters_array_type adapters_;
|
||||
result<Tuple>* res_ = nullptr;
|
||||
|
||||
public:
|
||||
explicit static_aggregate_adapter(result<Tuple>* r = nullptr)
|
||||
{
|
||||
if (r) {
|
||||
res_ = r;
|
||||
detail::assigner<std::tuple_size<Tuple>::value - 1>::assign(adapters_, r->value());
|
||||
}
|
||||
}
|
||||
|
||||
void count(resp3::node<std::string_view> const& nd)
|
||||
{
|
||||
if (nd.depth == 1) {
|
||||
if (is_aggregate(nd.data_type))
|
||||
aggregate_size_ = element_multiplicity(nd.data_type) * nd.aggregate_size;
|
||||
else
|
||||
++i_;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (--aggregate_size_ == 0)
|
||||
++i_;
|
||||
}
|
||||
|
||||
void operator()(resp3::node<std::string_view> const& nd, system::error_code& ec)
|
||||
{
|
||||
using std::visit;
|
||||
|
||||
if (nd.depth == 0) {
|
||||
auto const real_aggr_size = nd.aggregate_size * element_multiplicity(nd.data_type);
|
||||
if (real_aggr_size != std::tuple_size<Tuple>::value)
|
||||
ec = redis::error::incompatible_size;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
visit([&](auto& arg){arg(nd, ec);}, adapters_[i_]);
|
||||
count(nd);
|
||||
}
|
||||
};
|
||||
|
||||
template <class... Ts>
|
||||
struct result_traits<result<std::tuple<Ts...>>>
|
||||
{
|
||||
using response_type = result<std::tuple<Ts...>>;
|
||||
using adapter_type = static_aggregate_adapter<response_type>;
|
||||
static auto adapt(response_type& r) noexcept { return adapter_type{&r}; }
|
||||
};
|
||||
|
||||
} // boost::redis::adapter::detail
|
||||
|
||||
#endif // BOOST_REDIS_ADAPTER_RESPONSE_TRAITS_HPP
|
||||
@@ -14,6 +14,11 @@
|
||||
namespace boost::redis::adapter
|
||||
{
|
||||
|
||||
/** @brief An adapter that ignores responses
|
||||
* @ingroup high-level-api
|
||||
*
|
||||
* RESP3 errors won't be ignored.
|
||||
*/
|
||||
struct ignore {
|
||||
void operator()(resp3::node<std::string_view> const& nd, system::error_code& ec)
|
||||
{
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
/* Copyright (c) 2018-2022 Marcelo Zimbres Silva (mzimbres@gmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE.txt)
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REDIS_DETAIL_ADAPT_HPP
|
||||
#define BOOST_REDIS_DETAIL_ADAPT_HPP
|
||||
|
||||
#include <boost/redis/resp3/node.hpp>
|
||||
#include <boost/redis/response.hpp>
|
||||
#include <boost/redis/adapter/adapt.hpp>
|
||||
#include <boost/redis/adapter/detail/response_traits.hpp>
|
||||
#include <boost/mp11.hpp>
|
||||
#include <boost/system.hpp>
|
||||
|
||||
#include <tuple>
|
||||
#include <limits>
|
||||
#include <string_view>
|
||||
#include <variant>
|
||||
|
||||
namespace boost::redis::detail
|
||||
{
|
||||
|
||||
class ignore_adapter {
|
||||
public:
|
||||
void
|
||||
operator()(std::size_t, resp3::node<std::string_view> const& nd, system::error_code& ec)
|
||||
{
|
||||
switch (nd.data_type) {
|
||||
case resp3::type::simple_error: ec = redis::error::resp3_simple_error; break;
|
||||
case resp3::type::blob_error: ec = redis::error::resp3_blob_error; break;
|
||||
case resp3::type::null: ec = redis::error::resp3_null; break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
auto get_supported_response_size() const noexcept
|
||||
{ return static_cast<std::size_t>(-1);}
|
||||
};
|
||||
|
||||
template <class Response>
|
||||
class static_adapter {
|
||||
private:
|
||||
static constexpr auto size = std::tuple_size<Response>::value;
|
||||
using adapter_tuple = mp11::mp_transform<adapter::adapter_t, Response>;
|
||||
using variant_type = mp11::mp_rename<adapter_tuple, std::variant>;
|
||||
using adapters_array_type = std::array<variant_type, size>;
|
||||
|
||||
adapters_array_type adapters_;
|
||||
|
||||
public:
|
||||
explicit static_adapter(Response& r)
|
||||
{
|
||||
adapter::detail::assigner<size - 1>::assign(adapters_, r);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
auto get_supported_response_size() const noexcept
|
||||
{ return size;}
|
||||
|
||||
void
|
||||
operator()(
|
||||
std::size_t i,
|
||||
resp3::node<std::string_view> const& nd,
|
||||
system::error_code& ec)
|
||||
{
|
||||
using std::visit;
|
||||
// I am usure whether this should be an error or an assertion.
|
||||
BOOST_ASSERT(i < adapters_.size());
|
||||
visit([&](auto& arg){arg(nd, ec);}, adapters_.at(i));
|
||||
}
|
||||
};
|
||||
|
||||
template <class Vector>
|
||||
class vector_adapter {
|
||||
private:
|
||||
using adapter_type = typename adapter::detail::response_traits<Vector>::adapter_type;
|
||||
adapter_type adapter_;
|
||||
|
||||
public:
|
||||
explicit vector_adapter(Vector& v)
|
||||
: adapter_{adapter::adapt2(v)}
|
||||
{ }
|
||||
|
||||
[[nodiscard]]
|
||||
auto
|
||||
get_supported_response_size() const noexcept
|
||||
{ return static_cast<std::size_t>(-1);}
|
||||
|
||||
void
|
||||
operator()(
|
||||
std::size_t,
|
||||
resp3::node<std::string_view> const& nd,
|
||||
system::error_code& ec)
|
||||
{
|
||||
adapter_(nd, ec);
|
||||
}
|
||||
};
|
||||
|
||||
template <class>
|
||||
struct response_traits;
|
||||
|
||||
template <>
|
||||
struct response_traits<ignore_t> {
|
||||
using response_type = ignore_t;
|
||||
using adapter_type = detail::ignore_adapter;
|
||||
|
||||
static auto adapt(response_type&) noexcept
|
||||
{ return detail::ignore_adapter{}; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct response_traits<adapter::result<ignore_t>> {
|
||||
using response_type = adapter::result<ignore_t>;
|
||||
using adapter_type = detail::ignore_adapter;
|
||||
|
||||
static auto adapt(response_type&) noexcept
|
||||
{ return detail::ignore_adapter{}; }
|
||||
};
|
||||
|
||||
template <class String, class Allocator>
|
||||
struct response_traits<adapter::result<std::vector<resp3::node<String>, Allocator>>> {
|
||||
using response_type = adapter::result<std::vector<resp3::node<String>, Allocator>>;
|
||||
using adapter_type = vector_adapter<response_type>;
|
||||
|
||||
static auto adapt(response_type& v) noexcept
|
||||
{ return adapter_type{v}; }
|
||||
};
|
||||
|
||||
template <class ...Ts>
|
||||
struct response_traits<response<Ts...>> {
|
||||
using response_type = response<Ts...>;
|
||||
using adapter_type = static_adapter<response_type>;
|
||||
|
||||
static auto adapt(response_type& r) noexcept
|
||||
{ return adapter_type{r}; }
|
||||
};
|
||||
|
||||
template <class Adapter>
|
||||
class wrapper {
|
||||
public:
|
||||
explicit wrapper(Adapter adapter) : adapter_{adapter} {}
|
||||
|
||||
void operator()(resp3::node<std::string_view> const& node, system::error_code& ec)
|
||||
{ return adapter_(0, node, ec); }
|
||||
|
||||
[[nodiscard]]
|
||||
auto get_supported_response_size() const noexcept
|
||||
{ return adapter_.get_supported_response_size();}
|
||||
|
||||
private:
|
||||
Adapter adapter_;
|
||||
};
|
||||
|
||||
template <class Adapter>
|
||||
auto make_adapter_wrapper(Adapter adapter)
|
||||
{
|
||||
return wrapper{adapter};
|
||||
}
|
||||
|
||||
/** @brief Adapts a type to be used as a response.
|
||||
*
|
||||
* The type T must be either
|
||||
*
|
||||
* 1. a response<T1, T2, T3, ...> or
|
||||
* 2. std::vector<node<String>>
|
||||
*
|
||||
* The types T1, T2, etc can be any STL container, any integer type
|
||||
* and `std::string`.
|
||||
*
|
||||
* @param t Tuple containing the responses.
|
||||
*/
|
||||
template<class T>
|
||||
auto boost_redis_adapt(T& t) noexcept
|
||||
{
|
||||
return response_traits<T>::adapt(t);
|
||||
}
|
||||
|
||||
} // boost::redis::detail
|
||||
|
||||
#endif // BOOST_REDIS_DETAIL_ADAPT_HPP
|
||||
@@ -7,7 +7,7 @@
|
||||
#ifndef BOOST_REDIS_CONNECTION_BASE_HPP
|
||||
#define BOOST_REDIS_CONNECTION_BASE_HPP
|
||||
|
||||
#include <boost/redis/detail/adapt.hpp>
|
||||
#include <boost/redis/adapter/adapt.hpp>
|
||||
#include <boost/redis/operation.hpp>
|
||||
#include <boost/redis/request.hpp>
|
||||
#include <boost/redis/detail/connection_ops.hpp>
|
||||
@@ -131,27 +131,27 @@ public:
|
||||
template <class Response, class CompletionToken>
|
||||
auto async_exec(request const& req, Response& resp, CompletionToken token)
|
||||
{
|
||||
using namespace boost::redis;
|
||||
auto adapter = boost_redis_adapt(resp);
|
||||
BOOST_ASSERT_MSG(req.size() <= adapter.get_supported_response_size(), "Request and response have incompatible sizes.");
|
||||
using namespace boost::redis::adapter;
|
||||
auto f = boost_redis_adapt(resp);
|
||||
BOOST_ASSERT_MSG(req.size() <= f.get_supported_response_size(), "Request and response have incompatible sizes.");
|
||||
|
||||
return asio::async_compose
|
||||
< CompletionToken
|
||||
, void(system::error_code, std::size_t)
|
||||
>(detail::exec_op<Derived, decltype(adapter)>{&derived(), &req, adapter}, token, writer_timer_);
|
||||
>(redis::detail::exec_op<Derived, decltype(f)>{&derived(), &req, f}, token, writer_timer_);
|
||||
}
|
||||
|
||||
template <class Response, class CompletionToken>
|
||||
auto async_receive(Response& response, CompletionToken token)
|
||||
{
|
||||
using namespace boost::redis;
|
||||
auto adapter = boost_redis_adapt(response);
|
||||
auto f = detail::make_adapter_wrapper(adapter);
|
||||
using namespace boost::redis::adapter;
|
||||
auto g = boost_redis_adapt(response);
|
||||
auto f = adapter::detail::make_adapter_wrapper(g);
|
||||
|
||||
return asio::async_compose
|
||||
< CompletionToken
|
||||
, void(system::error_code, std::size_t)
|
||||
>(detail::receive_op<Derived, decltype(f)>{&derived(), f}, token, channel_);
|
||||
>(redis::detail::receive_op<Derived, decltype(f)>{&derived(), f}, token, channel_);
|
||||
}
|
||||
|
||||
template <class CompletionToken>
|
||||
|
||||
@@ -7,12 +7,10 @@
|
||||
#ifndef BOOST_REDIS_CONNECTION_OPS_HPP
|
||||
#define BOOST_REDIS_CONNECTION_OPS_HPP
|
||||
|
||||
#include <boost/redis/detail/adapt.hpp>
|
||||
#include <boost/redis/adapter/adapt.hpp>
|
||||
#include <boost/redis/error.hpp>
|
||||
#include <boost/redis/resp3/type.hpp>
|
||||
#include <boost/redis/resp3/detail/parser.hpp>
|
||||
#include <boost/redis/resp3/read.hpp>
|
||||
#include <boost/redis/resp3/write.hpp>
|
||||
#include <boost/redis/read.hpp>
|
||||
#include <boost/redis/request.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/system.hpp>
|
||||
@@ -96,7 +94,7 @@ struct exec_read_op {
|
||||
//-----------------------------------
|
||||
|
||||
BOOST_ASIO_CORO_YIELD
|
||||
resp3::async_read(
|
||||
redis::async_read(
|
||||
conn->next_layer(),
|
||||
conn->make_dynamic_buffer(),
|
||||
[i = index, adpt = adapter] (resp3::node<std::string_view> const& nd, system::error_code& ec) mutable { adpt(i, nd, ec); },
|
||||
@@ -137,7 +135,7 @@ struct receive_op {
|
||||
AEDIS_CHECK_OP1(;);
|
||||
|
||||
BOOST_ASIO_CORO_YIELD
|
||||
resp3::async_read(conn->next_layer(), conn->make_dynamic_buffer(), adapter, std::move(self));
|
||||
redis::async_read(conn->next_layer(), conn->make_dynamic_buffer(), adapter, std::move(self));
|
||||
if (ec || is_cancelled(self)) {
|
||||
conn->cancel(operation::run);
|
||||
conn->cancel(operation::receive);
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
* accompanying file LICENSE.txt)
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REDIS_RESP3_READ_OPS_HPP
|
||||
#define BOOST_REDIS_RESP3_READ_OPS_HPP
|
||||
#ifndef BOOST_REDIS_READ_OPS_HPP
|
||||
#define BOOST_REDIS_READ_OPS_HPP
|
||||
|
||||
#include <boost/redis/resp3/detail/parser.hpp>
|
||||
#include <boost/redis/resp3/parser.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/asio/read.hpp>
|
||||
#include <boost/asio/read_until.hpp>
|
||||
@@ -23,7 +23,6 @@ auto is_cancelled(T const& self)
|
||||
{
|
||||
return self.get_cancellation_state().cancelled() != asio::cancellation_type_t::none;
|
||||
}
|
||||
}
|
||||
|
||||
#define AEDIS_CHECK_OP0(X)\
|
||||
if (ec || redis::detail::is_cancelled(self)) {\
|
||||
@@ -39,8 +38,6 @@ auto is_cancelled(T const& self)
|
||||
return;\
|
||||
}
|
||||
|
||||
namespace boost::redis::resp3::detail {
|
||||
|
||||
template <
|
||||
class AsyncReadStream,
|
||||
class DynamicBuffer,
|
||||
@@ -49,7 +46,7 @@ class parse_op {
|
||||
private:
|
||||
AsyncReadStream& stream_;
|
||||
DynamicBuffer buf_;
|
||||
parser parser_;
|
||||
resp3::parser parser_;
|
||||
ResponseAdapter adapter_;
|
||||
std::size_t consumed_ = 0;
|
||||
std::size_t buffer_size_ = 0;
|
||||
@@ -117,6 +114,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
} // boost::redis::resp3::detail
|
||||
} // boost::redis::detail
|
||||
|
||||
#endif // BOOST_REDIS_RESP3_READ_OPS_HPP
|
||||
#endif // BOOST_REDIS_READ_OPS_HPP
|
||||
@@ -4,18 +4,18 @@
|
||||
* accompanying file LICENSE.txt)
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REDIS_RESP3_READ_HPP
|
||||
#define BOOST_REDIS_RESP3_READ_HPP
|
||||
#ifndef BOOST_REDIS_READ_HPP
|
||||
#define BOOST_REDIS_READ_HPP
|
||||
|
||||
#include <boost/redis/resp3/type.hpp>
|
||||
#include <boost/redis/resp3/detail/parser.hpp>
|
||||
#include <boost/redis/resp3/detail/read_ops.hpp>
|
||||
#include <boost/redis/resp3/parser.hpp>
|
||||
#include <boost/redis/detail/read_ops.hpp>
|
||||
#include <boost/redis/adapter/ignore.hpp>
|
||||
#include <boost/asio/read.hpp>
|
||||
#include <boost/asio/compose.hpp>
|
||||
#include <boost/asio/async_result.hpp>
|
||||
|
||||
namespace boost::redis::resp3 {
|
||||
namespace boost::redis {
|
||||
|
||||
/** \brief Reads a complete response to a command sychronously.
|
||||
* \ingroup low-level-api
|
||||
@@ -59,7 +59,7 @@ read(
|
||||
ResponseAdapter adapter,
|
||||
system::error_code& ec) -> std::size_t
|
||||
{
|
||||
detail::parser p;
|
||||
resp3::parser p;
|
||||
std::size_t n = 0;
|
||||
std::size_t consumed = 0;
|
||||
do {
|
||||
@@ -114,7 +114,7 @@ read(
|
||||
ResponseAdapter adapter = ResponseAdapter{})
|
||||
{
|
||||
system::error_code ec;
|
||||
auto const n = resp3::read(stream, buf, adapter, ec);
|
||||
auto const n = redis::read(stream, buf, adapter, ec);
|
||||
|
||||
if (ec)
|
||||
BOOST_THROW_EXCEPTION(system::system_error{ec});
|
||||
@@ -181,6 +181,6 @@ auto async_read(
|
||||
stream);
|
||||
}
|
||||
|
||||
} // boost::redis::resp3
|
||||
} // boost::redis
|
||||
|
||||
#endif // BOOST_REDIS_RESP3_READ_HPP
|
||||
#endif // BOOST_REDIS_READ_HPP
|
||||
@@ -4,13 +4,13 @@
|
||||
* accompanying file LICENSE.txt)
|
||||
*/
|
||||
|
||||
#include <boost/redis/resp3/detail/parser.hpp>
|
||||
#include <boost/redis/resp3/parser.hpp>
|
||||
#include <boost/redis/error.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <charconv>
|
||||
|
||||
namespace boost::redis::resp3::detail {
|
||||
namespace boost::redis::resp3 {
|
||||
|
||||
void to_int(int_type& i, std::string_view sv, system::error_code& ec)
|
||||
{
|
||||
@@ -152,4 +152,4 @@ parser::consume(
|
||||
|
||||
return std::make_pair(ret, n);
|
||||
}
|
||||
} // boost::redis::resp3::detail
|
||||
} // boost::redis::resp3
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <string_view>
|
||||
#include <cstdint>
|
||||
|
||||
namespace boost::redis::resp3::detail {
|
||||
namespace boost::redis::resp3 {
|
||||
|
||||
using int_type = std::uint64_t;
|
||||
|
||||
@@ -64,6 +64,6 @@ public:
|
||||
{ return bulk_length_; }
|
||||
};
|
||||
|
||||
} // boost::redis::detail::resp3
|
||||
} // boost::redis::resp3
|
||||
|
||||
#endif // BOOST_REDIS_RESP3_PARSER_HPP
|
||||
@@ -8,4 +8,4 @@
|
||||
#include <boost/redis/impl/request.ipp>
|
||||
#include <boost/redis/impl/ignore.ipp>
|
||||
#include <boost/redis/resp3/impl/type.ipp>
|
||||
#include <boost/redis/resp3/detail/impl/parser.ipp>
|
||||
#include <boost/redis/resp3/impl/parser.ipp>
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
* accompanying file LICENSE.txt)
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REDIS_RESP3_WRITE_HPP
|
||||
#define BOOST_REDIS_RESP3_WRITE_HPP
|
||||
#ifndef BOOST_REDIS_WRITE_HPP
|
||||
#define BOOST_REDIS_WRITE_HPP
|
||||
|
||||
#include <boost/asio/write.hpp>
|
||||
|
||||
namespace boost::redis::resp3 {
|
||||
namespace boost::redis {
|
||||
|
||||
/** \brief Writes a request synchronously.
|
||||
* \ingroup low-level-api
|
||||
@@ -59,6 +59,6 @@ auto async_write(
|
||||
return asio::async_write(stream, asio::buffer(req.payload()), token);
|
||||
}
|
||||
|
||||
} // boost::redis::resp3
|
||||
} // boost::redis
|
||||
|
||||
#endif // BOOST_REDIS_RESP3_WRITE_HPP
|
||||
#endif // BOOST_REDIS_WRITE_HPP
|
||||
@@ -31,6 +31,7 @@ auto operator!=(boost::redis::ignore_t, boost::redis::ignore_t) noexcept {return
|
||||
}
|
||||
|
||||
namespace net = boost::asio;
|
||||
namespace redis = boost::redis;
|
||||
namespace resp3 = boost::redis::resp3;
|
||||
using boost::redis::request;
|
||||
using boost::redis::response;
|
||||
@@ -40,8 +41,8 @@ using boost::redis::adapter::result;
|
||||
|
||||
using test_stream = boost::beast::test::stream;
|
||||
using boost::redis::adapter::adapt2;
|
||||
using node_type = result<boost::redis::resp3::node<std::string>>;
|
||||
using vec_node_type = result<std::vector<boost::redis::resp3::node<std::string>>>;
|
||||
using node_type = result<resp3::node<std::string>>;
|
||||
using vec_node_type = result<std::vector<resp3::node<std::string>>>;
|
||||
using vec_type = result<std::vector<std::string>>;
|
||||
using op_vec_type = result<std::optional<std::vector<std::string>>>;
|
||||
|
||||
@@ -99,7 +100,7 @@ void test_sync(net::any_io_executor ex, expect<Result> e)
|
||||
ts.append(e.in);
|
||||
Result result;
|
||||
boost::system::error_code ec;
|
||||
resp3::read(ts, net::dynamic_buffer(rbuffer), adapt2(result), ec);
|
||||
redis::read(ts, net::dynamic_buffer(rbuffer), adapt2(result), ec);
|
||||
if (e.ec) {
|
||||
BOOST_CHECK_EQUAL(ec, e.ec);
|
||||
return;
|
||||
@@ -155,7 +156,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
resp3::async_read(
|
||||
redis::async_read(
|
||||
ts_,
|
||||
net::dynamic_buffer(rbuffer_),
|
||||
adapt2(result_),
|
||||
@@ -531,7 +532,7 @@ BOOST_AUTO_TEST_CASE(ignore_adapter_simple_error)
|
||||
|
||||
test_stream ts {ioc};
|
||||
ts.append(S10a);
|
||||
resp3::read(ts, net::dynamic_buffer(rbuffer), adapt2(ignore), ec);
|
||||
redis::read(ts, net::dynamic_buffer(rbuffer), adapt2(ignore), ec);
|
||||
BOOST_CHECK_EQUAL(ec, boost::redis::error::resp3_simple_error);
|
||||
BOOST_TEST(!rbuffer.empty());
|
||||
}
|
||||
@@ -544,7 +545,7 @@ BOOST_AUTO_TEST_CASE(ignore_adapter_blob_error)
|
||||
|
||||
test_stream ts {ioc};
|
||||
ts.append(S12a);
|
||||
resp3::read(ts, net::dynamic_buffer(rbuffer), adapt2(ignore), ec);
|
||||
redis::read(ts, net::dynamic_buffer(rbuffer), adapt2(ignore), ec);
|
||||
BOOST_CHECK_EQUAL(ec, boost::redis::error::resp3_blob_error);
|
||||
BOOST_TEST(!rbuffer.empty());
|
||||
}
|
||||
@@ -557,7 +558,7 @@ BOOST_AUTO_TEST_CASE(ignore_adapter_no_error)
|
||||
|
||||
test_stream ts {ioc};
|
||||
ts.append(S05b);
|
||||
resp3::read(ts, net::dynamic_buffer(rbuffer), adapt2(ignore), ec);
|
||||
redis::read(ts, net::dynamic_buffer(rbuffer), adapt2(ignore), ec);
|
||||
BOOST_TEST(!ec);
|
||||
BOOST_TEST(rbuffer.empty());
|
||||
}
|
||||
@@ -653,7 +654,7 @@ BOOST_AUTO_TEST_CASE(type_convert)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(adapter)
|
||||
{
|
||||
using boost::redis::detail::boost_redis_adapt;
|
||||
using boost::redis::adapter::boost_redis_adapt;
|
||||
using resp3::type;
|
||||
|
||||
boost::system::error_code ec;
|
||||
|
||||
Reference in New Issue
Block a user