2
0
mirror of https://github.com/boostorg/redis.git synced 2026-02-02 21:12:16 +00:00

Refactoring listed below:

- Improvements in the organization.
- Adds support for the default token on the consumer.
This commit is contained in:
Marcelo Zimbres
2021-10-10 15:00:22 +02:00
parent 62e34767ca
commit 05aff2f3c6
18 changed files with 540 additions and 439 deletions

View File

@@ -9,6 +9,8 @@
using namespace aedis;
using tcp_socket = net::use_awaitable_t<>::as_default_on_t<net::ip::tcp::socket>;
void print_event(std::pair<command, std::string> const& p)
{
std::cout << "Event: " << p.first << ".";
@@ -20,8 +22,9 @@ void print_event(std::pair<command, std::string> const& p)
}
net::awaitable<void>
example(net::ip::tcp::socket& socket,
std::queue<resp3::request>& requests)
example(
tcp_socket& socket,
std::queue<resp3::request>& requests)
{
requests.push({});
requests.back().hello("3");
@@ -31,7 +34,7 @@ example(net::ip::tcp::socket& socket,
for (;;) {
resp.clear();
co_await cs.async_consume(socket, requests, resp, net::use_awaitable);
co_await cs.async_consume(socket, requests, resp);
std::cout << resp << std::endl;
if (resp.get_type() == resp3::type::push)
@@ -66,7 +69,7 @@ int main()
net::ip::tcp::resolver resolver{ioc};
auto const res = resolver.resolve("127.0.0.1", "6379");
net::ip::tcp::socket socket{ioc};
tcp_socket socket{ioc};
net::connect(socket, res);
std::queue<resp3::request> requests;

View File

@@ -10,4 +10,5 @@
#include <aedis/version.hpp>
#include <aedis/resp3/write.hpp>
#include <aedis/resp3/request.hpp>
#include <aedis/resp3/read.hpp>
#include <aedis/resp3/consumer.hpp>
#include <aedis/resp3/response.hpp>

View File

@@ -11,7 +11,7 @@
namespace aedis {
/// Supported redis commands.
/// List of the supported redis commands.
enum class command
{ acl_load
, acl_save
@@ -75,7 +75,12 @@ enum class command
, unknown
};
/// Converts the command to a string.
std::string to_string(command c);
/** Writes the text representation of the command to the output
* stream.
*/
std::ostream& operator<<(std::ostream& os, command c);
} // aedis

View File

@@ -0,0 +1,48 @@
/* Copyright (c) 2019 - 2021 Marcelo Zimbres Silva (mzimbres at gmail dot com)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <aedis/net.hpp>
#include <aedis/resp3/request.hpp>
#include <aedis/resp3/type.hpp>
#include <aedis/resp3/response.hpp>
#include <aedis/resp3/detail/read.hpp>
namespace aedis {
namespace resp3 {
/** Reads and writes redis commands.
*/
struct consumer {
std::string buffer;
net::coroutine coro = net::coroutine();
type t = type::invalid;
template<
class AsyncReadWriteStream,
class CompletionToken =
net::default_completion_token_t<typename AsyncReadWriteStream::executor_type>
>
auto async_consume(
AsyncReadWriteStream& stream,
std::queue<request>& requests,
response& resp,
CompletionToken&& token =
net::default_completion_token_t<typename AsyncReadWriteStream::executor_type>{})
{
return net::async_compose<
CompletionToken,
void(boost::system::error_code, type)>(
detail::consumer_op{stream, buffer, requests, resp, t, coro},
token, stream);
}
};
} // resp3
} // aedis

View File

@@ -0,0 +1,112 @@
/* Copyright (c) 2019 - 2021 Marcelo Zimbres Silva (mzimbres at gmail dot com)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <queue>
#include <vector>
#include <string>
#include <numeric>
#include <algorithm>
#include <functional>
#include <type_traits>
#include <string_view>
#include <utility>
#include <aedis/command.hpp>
namespace aedis {
namespace resp3 {
namespace detail {
void add_bulk(std::string& to, std::string_view param);
void add_header(std::string& to, int size);
struct accumulator {
auto
operator()(
std::string a,
std::string_view b) const
{
add_bulk(a, b);
return a;
}
template <class T>
auto
operator()(
std::string a,
T b,
typename std::enable_if<(std::is_integral<T>::value || std::is_floating_point<T>::value), bool>::type = false) const
{
auto const v = std::to_string(b);
add_bulk(a, v);
return a;
}
auto
operator()(
std::string a,
std::pair<std::string, std::string_view> b) const
{
add_bulk(a, b.first);
add_bulk(a, b.second);
return a;
}
template <class T>
auto
operator()(
std::string a,
std::pair<T, std::string_view> b,
typename std::enable_if<(std::is_integral<T>::value || std::is_floating_point<T>::value), bool>::type = false) const
{
auto const v = std::to_string(b.first);
add_bulk(a, v);
add_bulk(a, b.second);
return a;
}
};
void assemble(std::string& ret, std::string_view cmd);
template <class Iter>
void assemble( std::string& ret
, std::string_view cmd
, std::initializer_list<std::string_view> key
, Iter begin
, Iter end
, int size = 1)
{
auto const d1 =
std::distance( std::cbegin(key)
, std::cend(key));
auto const d2 = std::distance(begin, end);
std::string a;
add_header(a, 1 + d1 + size * d2);
add_bulk(a, cmd);
auto b =
std::accumulate( std::cbegin(key)
, std::cend(key)
, std::move(a)
, accumulator{});
ret +=
std::accumulate( begin
, end
, std::move(b)
, accumulator{});
}
void assemble(std::string& ret, std::string_view cmd, std::string_view key);
} // detail
} // resp3
} // aedis

View File

@@ -0,0 +1,44 @@
/* Copyright (c) 2019 - 2021 Marcelo Zimbres Silva (mzimbres at gmail dot com)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include <aedis/command.hpp>
namespace aedis {
namespace resp3 {
namespace detail {
void add_bulk(std::string& to, std::string_view param)
{
to += "$";
to += std::to_string(std::size(param));
to += "\r\n";
to += param;
to += "\r\n";
}
void add_header(std::string& to, int size)
{
to += "*";
to += std::to_string(size);
to += "\r\n";
}
void assemble(std::string& ret, std::string_view cmd)
{
add_header(ret, 1);
add_bulk(ret, cmd);
}
void assemble(std::string& ret, std::string_view cmd, std::string_view key)
{
std::initializer_list<std::string_view> dummy;
assemble(ret, cmd, {key}, std::cbegin(dummy), std::cend(dummy));
}
} // detail
} // resp3
} // aedis

View File

@@ -10,7 +10,9 @@
#include <string_view>
#include <aedis/resp3/response_adapter_base.hpp>
namespace aedis { namespace resp3 { namespace detail {
namespace aedis {
namespace resp3 {
namespace detail {
// resp3 parser.
class parser {
@@ -48,6 +50,79 @@ public:
auto bulk_length() const noexcept { return bulk_length_; }
};
// The parser supports up to 5 levels of nested structures. The first
// element in the sizes stack is a sentinel and must be different from
// 1.
template <class AsyncReadStream, class Storage>
class parse_op {
private:
AsyncReadStream& stream_;
Storage* buf_ = nullptr;
detail::parser parser_;
int start_ = 1;
public:
parse_op(AsyncReadStream& stream, Storage* buf, response_adapter_base* res)
: stream_ {stream}
, buf_ {buf}
, parser_ {res}
{ }
template <class Self>
void operator()( Self& self
, boost::system::error_code ec = {}
, std::size_t n = 0)
{
switch (start_) {
for (;;) {
if (parser_.bulk() == detail::parser::bulk_type::none) {
case 1:
start_ = 0;
net::async_read_until(
stream_,
net::dynamic_buffer(*buf_),
"\r\n",
std::move(self));
return;
}
// On a bulk read we can't read until delimiter since the
// payload may contain the delimiter itself so we have to
// read the whole chunk. However if the bulk blob is small
// enough it may be already on the buffer buf_ we read
// last time. If it is, there is no need of initiating
// another async op otherwise we have to read the
// missing bytes.
if (std::ssize(*buf_) < (parser_.bulk_length() + 2)) {
start_ = 0;
auto const s = std::ssize(*buf_);
auto const l = parser_.bulk_length();
auto const to_read = static_cast<std::size_t>(l + 2 - s);
buf_->resize(l + 2);
net::async_read(
stream_,
net::buffer(buf_->data() + s, to_read),
net::transfer_all(),
std::move(self));
return;
}
default:
{
if (ec)
return self.complete(ec);
n = parser_.advance(buf_->data(), n);
buf_->erase(0, n);
if (parser_.done())
return self.complete({});
}
}
}
}
};
} // detail
} // resp3
} // aedis

View File

@@ -7,93 +7,20 @@
#pragma once
#include <iostream>
#include <aedis/net.hpp>
#include <aedis/resp3/write.hpp>
#include <aedis/resp3/request.hpp>
#include <aedis/resp3/type.hpp>
#include <aedis/resp3/response.hpp>
#include <aedis/resp3/detail/parser.hpp>
#include <aedis/resp3/response_adapter_base.hpp>
#include <aedis/resp3/detail/parser.hpp>
#include <aedis/resp3/detail/write.hpp>
#include <boost/asio/yield.hpp>
namespace aedis { namespace resp3 {
// The parser supports up to 5 levels of nested structures. The first
// element in the sizes stack is a sentinel and must be different from
// 1.
template <class AsyncReadStream, class Storage>
class parse_op {
private:
AsyncReadStream& stream_;
Storage* buf_ = nullptr;
detail::parser parser_;
int start_ = 1;
public:
parse_op(AsyncReadStream& stream, Storage* buf, response_adapter_base* res)
: stream_ {stream}
, buf_ {buf}
, parser_ {res}
{ }
template <class Self>
void operator()( Self& self
, boost::system::error_code ec = {}
, std::size_t n = 0)
{
switch (start_) {
for (;;) {
if (parser_.bulk() == detail::parser::bulk_type::none) {
case 1:
start_ = 0;
net::async_read_until(
stream_,
net::dynamic_buffer(*buf_),
"\r\n",
std::move(self));
return;
}
// On a bulk read we can't read until delimiter since the
// payload may contain the delimiter itself so we have to
// read the whole chunk. However if the bulk blob is small
// enough it may be already on the buffer buf_ we read
// last time. If it is, there is no need of initiating
// another async op otherwise we have to read the
// missing bytes.
if (std::ssize(*buf_) < (parser_.bulk_length() + 2)) {
start_ = 0;
auto const s = std::ssize(*buf_);
auto const l = parser_.bulk_length();
auto const to_read = static_cast<std::size_t>(l + 2 - s);
buf_->resize(l + 2);
net::async_read(
stream_,
net::buffer(buf_->data() + s, to_read),
net::transfer_all(),
std::move(self));
return;
}
default:
{
if (ec)
return self.complete(ec);
n = parser_.advance(buf_->data(), n);
buf_->erase(0, n);
if (parser_.done())
return self.complete({});
}
}
}
}
};
namespace aedis {
namespace resp3 {
namespace detail {
template <class SyncReadStream, class Storage>
auto read(
@@ -102,10 +29,10 @@ auto read(
response_adapter_base& res,
boost::system::error_code& ec)
{
detail::parser p {&res};
parser p {&res};
std::size_t n = 0;
do {
if (p.bulk() == detail::parser::bulk_type::none) {
if (p.bulk() == parser::bulk_type::none) {
n = net::read_until(stream, net::dynamic_buffer(buf), "\r\n", ec);
if (ec || n < 3)
return n;
@@ -226,8 +153,9 @@ auto async_read_type(
>(type_op<AsyncReadStream, Storage> {stream, &buffer}, token, stream);
}
template <class AsyncReadWriteStream>
struct consumer_op {
net::ip::tcp::socket& socket;
AsyncReadWriteStream& stream;
std::string& buffer;
std::queue<request>& requests;
response& resp;
@@ -242,7 +170,7 @@ struct consumer_op {
{
reenter (coro) for (;;)
{
yield async_write_some(socket, requests, std::move(self));
yield async_write_some(stream, requests, std::move(self));
if (ec) {
self.complete(ec, type::invalid);
return;
@@ -250,7 +178,7 @@ struct consumer_op {
do {
do {
yield async_read_type(socket, buffer, std::move(self));
yield async_read_type(stream, buffer, std::move(self));
if (ec) {
self.complete(ec, type::invalid);
return;
@@ -262,11 +190,11 @@ struct consumer_op {
{
if (m_type == type::push) {
auto* adapter = resp.select_adapter(m_type, command::unknown, {});
async_read_one(socket, buffer, *adapter, std::move(self));
async_read_one(stream, buffer, *adapter, std::move(self));
} else {
auto const& pair = requests.front().ids.front();
auto* adapter = resp.select_adapter(m_type, pair.first, pair.second);
async_read_one(socket, buffer, *adapter, std::move(self));
async_read_one(stream, buffer, *adapter, std::move(self));
}
}
@@ -287,26 +215,7 @@ struct consumer_op {
}
};
struct consumer {
std::string buffer;
response resp;
net::coroutine coro = net::coroutine();
type t = type::invalid;
template<class CompletionToken>
auto async_consume(
net::ip::tcp::socket& socket,
std::queue<request>& requests,
response& resp,
CompletionToken&& token)
{
return net::async_compose<
CompletionToken,
void(boost::system::error_code, type)>(
consumer_op{socket, buffer, requests, resp, t, coro}, token, socket);
}
};
} // detail
} // resp3
} // aedis

View File

@@ -0,0 +1,114 @@
/* Copyright (c) 2019 - 2021 Marcelo Zimbres Silva (mzimbres at gmail dot com)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <chrono>
#include <aedis/net.hpp>
#include <aedis/resp3/request.hpp>
#include <boost/beast/core/stream_traits.hpp>
#include <boost/asio/yield.hpp>
namespace aedis {
namespace resp3 {
namespace detail {
template<class SyncWriteStream>
std::size_t
write(
SyncWriteStream& stream,
request& req,
boost::system::error_code& ec)
{
static_assert(boost::beast::is_sync_write_stream<SyncWriteStream>::value,
"SyncWriteStream type requirements not met");
return write(stream, net::buffer(req.payload), ec);
}
template<class SyncWriteStream>
std::size_t write(
SyncWriteStream& stream,
request& req)
{
static_assert(boost::beast::is_sync_write_stream<SyncWriteStream>::value,
"SyncWriteStream type requirements not met");
boost::system::error_code ec;
auto const bytes_transferred = write(stream, req, ec);
if (ec)
BOOST_THROW_EXCEPTION(boost::system::system_error{ec});
return bytes_transferred;
}
/** Asynchronously writes one or more requests on the stream.
*/
template<class AsyncWriteStream>
struct write_some_op {
AsyncWriteStream& stream;
std::queue<request>& requests;
net::coroutine coro = net::coroutine();
void
operator()(
auto& self,
boost::system::error_code const& ec = {},
std::size_t n = 0)
{
reenter (coro) {
do {
assert(!std::empty(requests));
assert(!std::empty(requests.front().payload));
yield async_write(
stream,
net::buffer(requests.front().payload),
std::move(self));
if (ec)
break;
requests.front().sent = true;
if (std::empty(requests.front().ids)) {
// We only pop when all commands in the pipeline has push
// responses like subscribe, otherwise, pop is done when the
// response arrives.
requests.pop();
}
} while (!std::empty(requests) && std::empty(requests.front().ids));
self.complete(ec);
}
}
};
template<
class AsyncWriteStream,
class CompletionToken>
auto
async_write_some(
AsyncWriteStream& stream,
std::queue<request>& requests,
CompletionToken&& token)
{
return net::async_compose<
CompletionToken,
void(boost::system::error_code)>(
write_some_op{stream, requests},
token, stream);
}
} // detail
} // resp3
} // aedis
#include <boost/asio/unyield.hpp>

View File

@@ -1,41 +0,0 @@
/* Copyright (c) 2019 - 2021 Marcelo Zimbres Silva (mzimbres at gmail dot com)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include <aedis/command.hpp>
namespace aedis { namespace resp3 {
void add_bulk(std::string& to, std::string_view param)
{
to += "$";
to += std::to_string(std::size(param));
to += "\r\n";
to += param;
to += "\r\n";
}
void add_header(std::string& to, int size)
{
to += "*";
to += std::to_string(size);
to += "\r\n";
}
void assemble(std::string& ret, std::string_view cmd)
{
add_header(ret, 1);
add_bulk(ret, cmd);
}
void assemble(std::string& ret, std::string_view cmd, std::string_view key)
{
std::initializer_list<std::string_view> dummy;
assemble(ret, cmd, {key}, std::cbegin(dummy), std::cend(dummy));
}
} // resp3
} // aedis

View File

@@ -7,7 +7,8 @@
#include <aedis/resp3/write.hpp>
namespace aedis { namespace resp3 {
namespace aedis {
namespace resp3 {
bool prepare_next(std::queue<request>& reqs)
{

View File

@@ -34,7 +34,7 @@ bool operator==(node const& a, node const& b);
/** Writes the text representation of node to the output stream.
*
* NOTE: Be careful when printing binary data.
* NOTE: Bonary data is not converted to text.
*/
std::ostream& operator<<(std::ostream& os, node const& o);

View File

@@ -10,103 +10,15 @@
#include <queue>
#include <vector>
#include <string>
#include <numeric>
#include <algorithm>
#include <functional>
#include <type_traits>
#include <string_view>
#include <utility>
#include <aedis/command.hpp>
#include <aedis/resp3/detail/assemble.hpp>
namespace aedis {
namespace resp3 {
// TODO: Move to detail.
void add_bulk(std::string& to, std::string_view param);
void add_header(std::string& to, int size);
struct accumulator {
auto
operator()(
std::string a,
std::string_view b) const
{
add_bulk(a, b);
return a;
}
template <class T>
auto
operator()(
std::string a,
T b,
typename std::enable_if<(std::is_integral<T>::value || std::is_floating_point<T>::value), bool>::type = false) const
{
auto const v = std::to_string(b);
add_bulk(a, v);
return a;
}
auto
operator()(
std::string a,
std::pair<std::string, std::string_view> b) const
{
add_bulk(a, b.first);
add_bulk(a, b.second);
return a;
}
template <class T>
auto
operator()(
std::string a,
std::pair<T, std::string_view> b,
typename std::enable_if<(std::is_integral<T>::value || std::is_floating_point<T>::value), bool>::type = false) const
{
auto const v = std::to_string(b.first);
add_bulk(a, v);
add_bulk(a, b.second);
return a;
}
};
void assemble(std::string& ret, std::string_view cmd);
template <class Iter>
void assemble( std::string& ret
, std::string_view cmd
, std::initializer_list<std::string_view> key
, Iter begin
, Iter end
, int size = 1)
{
auto const d1 =
std::distance( std::cbegin(key)
, std::cend(key));
auto const d2 = std::distance(begin, end);
std::string a;
add_header(a, 1 + d1 + size * d2);
add_bulk(a, cmd);
auto b =
std::accumulate( std::cbegin(key)
, std::cend(key)
, std::move(a)
, accumulator{});
ret +=
std::accumulate( begin
, end
, std::move(b)
, accumulator{});
}
void assemble(std::string& ret, std::string_view cmd, std::string_view key);
/** A class to compose redis requests
*
* A request is composed of one or more redis commands and is
@@ -140,66 +52,66 @@ public:
void ping()
{
assemble(payload, "PING");
detail::assemble(payload, "PING");
ids.push(std::make_pair(command::ping, std::string{}));
}
void quit()
{
assemble(payload, "QUIT");
detail::assemble(payload, "QUIT");
ids.push(std::make_pair(command::quit, std::string{}));
}
void multi()
{
assemble(payload, "MULTI");
detail::assemble(payload, "MULTI");
ids.push(std::make_pair(command::multi, std::string{}));
}
void exec()
{
assemble(payload, "EXEC");
detail::assemble(payload, "EXEC");
ids.push(std::make_pair(command::exec, std::string{}));
}
void incr(std::string_view key)
{
assemble(payload, "INCR", key);
detail::assemble(payload, "INCR", key);
ids.push(std::make_pair(command::incr, std::string{key}));
}
/// Adds auth to the request, see https://redis.io/commands/bgrewriteaof
void auth(std::string_view pwd)
{
assemble(payload, "AUTH", pwd);
detail::assemble(payload, "AUTH", pwd);
ids.push(std::make_pair(command::auth, std::string{}));
}
/// Adds bgrewriteaof to the request, see https://redis.io/commands/bgrewriteaof
void bgrewriteaof()
{
assemble(payload, "BGREWRITEAOF");
detail::assemble(payload, "BGREWRITEAOF");
ids.push(std::make_pair(command::bgrewriteaof, std::string{}));
}
/// Adds role to the request, see https://redis.io/commands/role
void role()
{
assemble(payload, "ROLE");
detail::assemble(payload, "ROLE");
ids.push(std::make_pair(command::role, std::string{}));
}
/// Adds bgsave to the request, see //https://redis.io/commands/bgsave
void bgsave()
{
assemble(payload, "BGSAVE");
detail::assemble(payload, "BGSAVE");
ids.push(std::make_pair(command::bgsave, std::string{}));
}
/// Adds ping to the request, see https://redis.io/commands/flushall
void flushall()
{
assemble(payload, "FLUSHALL");
detail::assemble(payload, "FLUSHALL");
ids.push(std::make_pair(command::flushall, std::string{}));
}
@@ -207,10 +119,10 @@ public:
void lpop(std::string_view key, int count = 1)
{
//if (count == 1) {
assemble(payload, "LPOP", key);
detail::assemble(payload, "LPOP", key);
//} else {
//auto par = {std::to_string(count)};
//assemble(
//detail::assemble(
// payload,
// "LPOP",
// {key},
@@ -225,34 +137,34 @@ public:
void subscribe(std::string_view key)
{
// The response to this command is a push.
assemble(payload, "SUBSCRIBE", key);
detail::assemble(payload, "SUBSCRIBE", key);
}
/// Adds ping to the request, see https://redis.io/commands/unsubscribe
void unsubscribe(std::string_view key)
{
// The response to this command is a push.
assemble(payload, "UNSUBSCRIBE", key);
detail::assemble(payload, "UNSUBSCRIBE", key);
}
/// Adds ping to the request, see https://redis.io/commands/get
void get(std::string_view key)
{
assemble(payload, "GET", key);
detail::assemble(payload, "GET", key);
ids.push(std::make_pair(command::get, std::string{key}));
}
/// Adds ping to the request, see https://redis.io/commands/keys
void keys(std::string_view pattern)
{
assemble(payload, "KEYS", pattern);
detail::assemble(payload, "KEYS", pattern);
ids.push(std::make_pair(command::keys, std::string{}));
}
/// Adds ping to the request, see https://redis.io/commands/hello
void hello(std::string_view version = "3")
{
assemble(payload, "HELLO", version);
detail::assemble(payload, "HELLO", version);
ids.push(std::make_pair(command::hello, std::string{}));
}
@@ -260,7 +172,7 @@ public:
void sentinel(std::string_view arg, std::string_view name)
{
auto par = {name};
assemble(payload, "SENTINEL", {arg}, std::cbegin(par), std::cend(par));
detail::assemble(payload, "SENTINEL", {arg}, std::cbegin(par), std::cend(par));
ids.push(std::make_pair(command::sentinel, std::string{}));
}
@@ -268,7 +180,7 @@ public:
void append(std::string_view key, std::string_view msg)
{
auto par = {msg};
assemble(payload, "APPEND", {key}, std::cbegin(par), std::cend(par));
detail::assemble(payload, "APPEND", {key}, std::cbegin(par), std::cend(par));
ids.push(std::make_pair(command::append, std::string{key}));
}
@@ -279,7 +191,7 @@ public:
auto const end_str = std::to_string(end);
std::initializer_list<std::string_view> par {start_str, end_str};
assemble( payload
detail::assemble( payload
, "BITCOUNT"
, {key}
, std::cbegin(par)
@@ -291,7 +203,7 @@ public:
template <class Iter>
void rpush(std::string_view key, Iter begin, Iter end)
{
assemble(payload, "RPUSH", {key}, begin, end);
detail::assemble(payload, "RPUSH", {key}, begin, end);
ids.push(std::make_pair(command::rpush, std::string{key}));
}
@@ -315,21 +227,21 @@ public:
template <class Iter>
void lpush(std::string_view key, Iter begin, Iter end)
{
assemble(payload, "LPUSH", {key}, begin, end);
detail::assemble(payload, "LPUSH", {key}, begin, end);
ids.push(std::make_pair(command::lpush, std::string{key}));
}
void psubscribe( std::initializer_list<std::string_view> l)
{
std::initializer_list<std::string_view> dummy = {};
assemble(payload, "PSUBSCRIBE", l, std::cbegin(dummy), std::cend(dummy));
detail::assemble(payload, "PSUBSCRIBE", l, std::cbegin(dummy), std::cend(dummy));
}
/// Adds ping to the request, see https://redis.io/commands/publish
void publish(std::string_view key, std::string_view msg)
{
auto par = {msg};
assemble(payload, "PUBLISH", {key}, std::cbegin(par), std::cend(par));
detail::assemble(payload, "PUBLISH", {key}, std::cbegin(par), std::cend(par));
ids.push(std::make_pair(command::publish, std::string{key}));
}
@@ -337,7 +249,7 @@ public:
void set(std::string_view key,
std::initializer_list<std::string_view> args)
{
assemble(payload, "SET", {key}, std::cbegin(args), std::cend(args));
detail::assemble(payload, "SET", {key}, std::cbegin(args), std::cend(args));
ids.push(std::make_pair(command::set, std::string{key}));
}
@@ -350,7 +262,7 @@ public:
//error: ERR Protocol error: expected '$', got '*'
using std::cbegin;
using std::cend;
assemble(payload, "HSET", {key}, std::cbegin(r), std::cend(r), 2);
detail::assemble(payload, "HSET", {key}, std::cbegin(r), std::cend(r), 2);
ids.push(std::make_pair(command::hset, std::string{key}));
}
@@ -359,7 +271,7 @@ public:
{
auto by_str = std::to_string(by);
std::initializer_list<std::string_view> par {field, by_str};
assemble(payload, "HINCRBY", {key}, std::cbegin(par), std::cend(par));
detail::assemble(payload, "HINCRBY", {key}, std::cbegin(par), std::cend(par));
ids.push(std::make_pair(command::hincrby, std::string{key}));
}
@@ -367,28 +279,28 @@ public:
void hkeys(std::string_view key)
{
auto par = {""};
assemble(payload, "HKEYS", {key}, std::cbegin(par), std::cend(par));
detail::assemble(payload, "HKEYS", {key}, std::cbegin(par), std::cend(par));
ids.push(std::make_pair(command::hkeys, std::string{key}));
}
/// Adds ping to the request, see https://redis.io/commands/hlen
void hlen(std::string_view key)
{
assemble(payload, "HLEN", {key});
detail::assemble(payload, "HLEN", {key});
ids.push(std::make_pair(command::hlen, std::string{key}));
}
/// Adds ping to the request, see https://redis.io/commands/hgetall
void hgetall(std::string_view key)
{
assemble(payload, "HGETALL", {key});
detail::assemble(payload, "HGETALL", {key});
ids.push(std::make_pair(command::hgetall, std::string{key}));
}
/// Adds ping to the request, see https://redis.io/commands/hvals
void hvals( std::string_view key)
{
assemble(payload, "HVALS", {key});
detail::assemble(payload, "HVALS", {key});
ids.push(std::make_pair(command::hvals, std::string{key}));
}
@@ -396,7 +308,7 @@ public:
void hget(std::string_view key, std::string_view field)
{
auto par = {field};
assemble(payload, "HGET", {key}, std::cbegin(par), std::cend(par));
detail::assemble(payload, "HGET", {key}, std::cbegin(par), std::cend(par));
ids.push(std::make_pair(command::hget, std::string{key}));
}
@@ -405,7 +317,7 @@ public:
std::string_view key,
std::initializer_list<std::string_view> fields)
{
assemble( payload
detail::assemble( payload
, "HMGET"
, {key}
, std::cbegin(fields)
@@ -419,7 +331,7 @@ public:
hdel(std::string_view key,
std::initializer_list<std::string_view> fields)
{
assemble(
detail::assemble(
payload,
"HDEL",
{key},
@@ -434,7 +346,7 @@ public:
{
auto const str = std::to_string(secs);
std::initializer_list<std::string_view> par {str};
assemble(payload, "EXPIRE", {key}, std::cbegin(par), std::cend(par));
detail::assemble(payload, "EXPIRE", {key}, std::cbegin(par), std::cend(par));
ids.push(std::make_pair(command::expire, std::string{key}));
}
@@ -443,7 +355,7 @@ public:
{
auto const score_str = std::to_string(score);
std::initializer_list<std::string_view> par = {score_str, value};
assemble(payload, "ZADD", {key}, std::cbegin(par), std::cend(par));
detail::assemble(payload, "ZADD", {key}, std::cbegin(par), std::cend(par));
ids.push(std::make_pair(command::zadd, std::string{key}));
}
@@ -451,7 +363,7 @@ public:
template <class Range>
void zadd(std::initializer_list<std::string_view> key, Range const& r)
{
assemble(payload, "ZADD", key, std::cbegin(r), std::cend(r), 2);
detail::assemble(payload, "ZADD", key, std::cbegin(r), std::cend(r), 2);
ids.push(std::make_pair(command::zadd, std::string{key}));
}
@@ -462,7 +374,7 @@ public:
auto const max_str = std::to_string(max);
std::initializer_list<std::string_view> par {min_str, max_str};
assemble(payload, "ZRANGE", {key}, std::cbegin(par), std::cend(par));
detail::assemble(payload, "ZRANGE", {key}, std::cbegin(par), std::cend(par));
ids.push(std::make_pair(command::zrange, std::string{key}));
}
@@ -475,7 +387,7 @@ public:
auto const min_str = std::to_string(min);
auto par = {min_str , max_str};
assemble(payload, "ZRANGEBYSCORE", {key}, std::cbegin(par), std::cend(par));
detail::assemble(payload, "ZRANGEBYSCORE", {key}, std::cbegin(par), std::cend(par));
ids.push(std::make_pair(command::zrangebyscore, std::string{key}));
}
@@ -487,7 +399,7 @@ public:
std::string_view max)
{
auto par = {min, max};
assemble(payload, "ZREMRANGEBYSCORE", {key}, std::cbegin(par), std::cend(par));
detail::assemble(payload, "ZREMRANGEBYSCORE", {key}, std::cbegin(par), std::cend(par));
ids.push(std::make_pair(command::zremrangebyscore, std::string{key}));
}
@@ -497,7 +409,7 @@ public:
auto const min_str = std::to_string(min);
auto const max_str = std::to_string(max);
std::initializer_list<std::string_view> par {min_str, max_str};
assemble(payload, "LRANGE", {key}, std::cbegin(par), std::cend(par));
detail::assemble(payload, "LRANGE", {key}, std::cbegin(par), std::cend(par));
ids.push(std::make_pair(command::lrange, std::string{key}));
}
@@ -507,7 +419,7 @@ public:
auto const min_str = std::to_string(min);
auto const max_str = std::to_string(max);
std::initializer_list<std::string_view> par {min_str, max_str};
assemble(payload, "LTRIM", {key}, std::cbegin(par), std::cend(par));
detail::assemble(payload, "LTRIM", {key}, std::cbegin(par), std::cend(par));
ids.push(std::make_pair(command::ltrim, std::string{key}));
}
@@ -515,14 +427,14 @@ public:
/// Adds ping to the request, see https://redis.io/commands/del
void del(std::string_view key)
{
assemble(payload, "DEL", key);
detail::assemble(payload, "DEL", key);
ids.push(std::make_pair(command::del, std::string{key}));
}
/// Adds ping to the request, see https://redis.io/commands/llen
void llen(std::string_view key)
{
assemble(payload, "LLEN", key);
detail::assemble(payload, "LLEN", key);
ids.push(std::make_pair(command::llen, std::string{key}));
}
@@ -530,7 +442,7 @@ public:
template <class Iter>
void sadd(std::string_view key, Iter begin, Iter end)
{
assemble(payload, "SADD", {key}, begin, end);
detail::assemble(payload, "SADD", {key}, begin, end);
ids.push(std::make_pair(command::sadd, std::string{key}));
}
@@ -546,28 +458,28 @@ public:
/// Adds ping to the request, see https://redis.io/commands/smembers
void smembers(std::string_view key)
{
assemble(payload, "SMEMBERS", key);
detail::assemble(payload, "SMEMBERS", key);
ids.push(std::make_pair(command::smembers, std::string{key}));
}
/// Adds ping to the request, see https://redis.io/commands/scard
void scard(std::string_view key)
{
assemble(payload, "SCARD", key);
detail::assemble(payload, "SCARD", key);
ids.push(std::make_pair(command::scard, std::string{key}));
}
/// Adds ping to the request, see https://redis.io/commands/scard
void scard(std::string_view key, std::initializer_list<std::string_view> l)
{
assemble(payload, "SDIFF", {key}, std::cbegin(l), std::cend(l));
detail::assemble(payload, "SDIFF", {key}, std::cbegin(l), std::cend(l));
ids.push(std::make_pair(command::sdiff, std::string{key}));
}
/// Adds ping to the request, see https://redis.io/commands/client_id
void client_id(std::string_view parameters)
{
assemble(payload, "CLIENT ID", {parameters});
detail::assemble(payload, "CLIENT ID", {parameters});
ids.push(std::make_pair(command::client_id, std::string{}));
}
};

View File

@@ -11,7 +11,8 @@
#include <vector>
#include <string>
namespace aedis { namespace resp3 {
namespace aedis {
namespace resp3 {
/// RESP3 message types.
enum class type
@@ -40,7 +41,7 @@ std::string to_string(type t);
// TODO: Move to detail?
type to_type(char c);
/// Writes the string representation of type to the stream.
/// Writes the string representation of type to the output stream.
std::ostream& operator<<(std::ostream& os, type t);
} // resp3

View File

@@ -15,97 +15,13 @@
#include <boost/beast/core/stream_traits.hpp>
#include <boost/asio/yield.hpp>
namespace aedis { namespace resp3 {
namespace aedis {
namespace resp3 {
bool prepare_next(std::queue<request>& reqs);
template<class SyncWriteStream>
std::size_t
write(
SyncWriteStream& stream,
request& req,
boost::system::error_code& ec)
{
static_assert(boost::beast::is_sync_write_stream<SyncWriteStream>::value,
"SyncWriteStream type requirements not met");
return write(stream, net::buffer(req.payload), ec);
}
template<class SyncWriteStream>
std::size_t write(
SyncWriteStream& stream,
request& req)
{
static_assert(boost::beast::is_sync_write_stream<SyncWriteStream>::value,
"SyncWriteStream type requirements not met");
boost::system::error_code ec;
auto const bytes_transferred = write(stream, req, ec);
if (ec)
BOOST_THROW_EXCEPTION(boost::system::system_error{ec});
return bytes_transferred;
}
/** Asynchronously writes one or more requests on the stream.
/** Prepares the back of a queue to receive further commands and
* returns true if a write is possible.
*/
template<class AsyncWriteStream>
struct write_some_op {
AsyncWriteStream& stream;
std::queue<request>& requests;
net::coroutine coro = net::coroutine();
void
operator()(
auto& self,
boost::system::error_code const& ec = {},
std::size_t n = 0)
{
reenter (coro) {
do {
assert(!std::empty(requests));
assert(!std::empty(requests.front().payload));
yield async_write(
stream,
net::buffer(requests.front().payload),
std::move(self));
if (ec)
break;
requests.front().sent = true;
if (std::empty(requests.front().ids)) {
// We only pop when all commands in the pipeline has push
// responses like subscribe, otherwise, pop is done when the
// response arrives.
requests.pop();
}
} while (!std::empty(requests) && std::empty(requests.front().ids));
self.complete(ec);
}
}
};
template<
class AsyncWriteStream,
class CompletionToken>
auto
async_write_some(
AsyncWriteStream& stream,
std::queue<request>& requests,
CompletionToken&& token)
{
return net::async_compose<
CompletionToken,
void(boost::system::error_code)>(
write_some_op{stream, requests},
token, stream);
}
bool prepare_next(std::queue<request>& reqs);
} // resp3
} // aedis

View File

@@ -7,8 +7,8 @@
#include <aedis/impl/command.ipp>
#include <aedis/resp3/impl/write.ipp>
#include <aedis/resp3/impl/request.ipp>
#include <aedis/resp3/impl/response.ipp>
#include <aedis/resp3/impl/type.ipp>
#include <aedis/resp3/impl/node.ipp>
#include <aedis/resp3/detail/impl/assemble.ipp>
#include <aedis/resp3/detail/impl/parser.ipp>

View File

@@ -5,5 +5,5 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#define AEDIS_VERSION 4
#define AEDIS_VERSION 5

View File

@@ -6,6 +6,7 @@
*/
#include <aedis/aedis.hpp>
#include <aedis/resp3/detail/read.hpp>
#include "test_stream.hpp"
@@ -31,6 +32,7 @@ using flat_array_int_type = detail::basic_flat_array<int>;
} // aedis
using namespace aedis;
using namespace aedis::resp3;
resp3::response::storage_type array_buffer;
resp3::detail::response_adapter radapter{&array_buffer};
@@ -131,10 +133,9 @@ test_general(net::ip::tcp::resolver::results_type const& res)
int push_counter = 0;
for (;;) {
resp.clear();
auto const t =
co_await cs.async_consume(socket, requests, resp, net::use_awaitable);
co_await cs.async_consume(socket, requests, resp, net::use_awaitable);
if (t == resp3::type::push) {
if (resp.get_type() == resp3::type::push) {
switch (push_counter) {
case 0:
{
@@ -368,7 +369,7 @@ test_general(net::ip::tcp::resolver::results_type const& res)
} break;
case command::lpop:
{
switch (t)
switch (resp.get_type())
{
case resp3::type::blob_string:
{
@@ -428,7 +429,7 @@ test_general(net::ip::tcp::resolver::results_type const& res)
};
check_equal(resp.raw(), expected, "smembers (value)");
} break;
default: { std::cout << "Error: " << t << " " << id.first << std::endl; }
default: { std::cout << "Error: " << resp.get_type() << " " << id.first << std::endl; }
}
resp.raw().clear();
@@ -461,13 +462,13 @@ test_list(net::ip::tcp::resolver::results_type const& results)
{ // hello
array_buffer.clear();
radapter.clear();
co_await async_read_one(socket, buf, radapter);
co_await detail::async_read_one(socket, buf, radapter);
}
{ // flushall
array_buffer.clear();
radapter.clear();
co_await async_read_one(socket, buf, radapter);
co_await detail::async_read_one(socket, buf, radapter);
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::simple_string, {"OK"}} };
check_equal(array_buffer, expected, "flushall");
@@ -478,21 +479,21 @@ test_list(net::ip::tcp::resolver::results_type const& results)
radapter.clear();
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::number, {"6"}} };
co_await async_read_one(socket, buf, radapter);
co_await detail::async_read_one(socket, buf, radapter);
check_equal(array_buffer, expected, "rpush");
}
{ // lrange
resp3::flat_array_int_type buffer;
resp3::detail::basic_flat_array_adapter<int> res{&buffer};
co_await async_read_one(socket, buf, res);
co_await detail::async_read_one(socket, buf, res);
check_equal(buffer, list, "lrange-1");
}
{ // lrange
resp3::flat_array_int_type buffer;
resp3::detail::basic_flat_array_adapter<int> res{&buffer};
co_await async_read_one(socket, buf, res);
co_await detail::async_read_one(socket, buf, res);
check_equal(buffer, std::vector<int>{3, 4, 5}, "lrange-2");
}
@@ -502,7 +503,7 @@ test_list(net::ip::tcp::resolver::results_type const& results)
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::simple_string, {"OK"}} };
co_await async_read_one(socket, buf, radapter);
co_await detail::async_read_one(socket, buf, radapter);
check_equal(array_buffer, expected, "ltrim");
}
@@ -512,14 +513,14 @@ test_list(net::ip::tcp::resolver::results_type const& results)
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::blob_string, {"3"}} };
co_await async_read_one(socket, buf, radapter);
co_await detail::async_read_one(socket, buf, radapter);
check_equal(array_buffer, expected, "lpop");
}
{ // quit
array_buffer.clear();
radapter.clear();
co_await async_read_one(socket, buf, radapter);
co_await detail::async_read_one(socket, buf, radapter);
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::simple_string, {"OK"}} };
check_equal(array_buffer, expected, "ltrim");
@@ -560,14 +561,14 @@ test_set(net::ip::tcp::resolver::results_type const& results)
{ // hello, flushall
array_buffer.clear();
radapter.clear();
co_await async_read_one(socket, buf, radapter);
co_await async_read_one(socket, buf, radapter);
co_await detail::async_read_one(socket, buf, radapter);
co_await detail::async_read_one(socket, buf, radapter);
}
{ // set
array_buffer.clear();
radapter.clear();
co_await async_read_one(socket, buf, radapter);
co_await detail::async_read_one(socket, buf, radapter);
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::simple_string, {"OK"}} };
check_equal(array_buffer, expected, "set1");
@@ -579,14 +580,14 @@ test_set(net::ip::tcp::resolver::results_type const& results)
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::blob_string, test_bulk1} };
co_await async_read_one(socket, buf, radapter);
co_await detail::async_read_one(socket, buf, radapter);
check_equal(array_buffer, expected, "get1");
}
{ // set
array_buffer.clear();
radapter.clear();
co_await async_read_one(socket, buf, radapter);
co_await detail::async_read_one(socket, buf, radapter);
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::simple_string, {"OK"}} };
check_equal(array_buffer, expected, "ltrim");
@@ -597,14 +598,14 @@ test_set(net::ip::tcp::resolver::results_type const& results)
radapter.clear();
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::blob_string, test_bulk2} };
co_await async_read_one(socket, buf, radapter);
co_await detail::async_read_one(socket, buf, radapter);
check_equal(array_buffer, expected, "get2");
}
{ // set
array_buffer.clear();
radapter.clear();
co_await async_read_one(socket, buf, radapter);
co_await detail::async_read_one(socket, buf, radapter);
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::simple_string, {"OK"}} };
check_equal(array_buffer, expected, "set3");
@@ -616,14 +617,14 @@ test_set(net::ip::tcp::resolver::results_type const& results)
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::blob_string, {}} };
co_await async_read_one(socket, buf, radapter);
co_await detail::async_read_one(socket, buf, radapter);
check_equal(array_buffer, expected, "get3");
}
{ // quit
array_buffer.clear();
radapter.clear();
co_await async_read_one(socket, buf, radapter);
co_await detail::async_read_one(socket, buf, radapter);
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::simple_string, {"OK"}} };
check_equal(array_buffer, expected, "quit");
@@ -647,7 +648,7 @@ net::awaitable<void> test_simple_string()
test_tcp_socket ts {cmd};
array_buffer.clear();
radapter.clear();
co_await async_read_one(ts, buf, radapter);
co_await detail::async_read_one(ts, buf, radapter);
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::simple_string, {"OK"}} };
check_equal(array_buffer, expected, "simple_string");
@@ -659,7 +660,7 @@ net::awaitable<void> test_simple_string()
test_tcp_socket ts {cmd};
array_buffer.clear();
radapter.clear();
co_await async_read_one(ts, buf, radapter);
co_await detail::async_read_one(ts, buf, radapter);
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::simple_string, {}} };
check_equal(array_buffer, expected, "simple_string (empty)");
@@ -675,7 +676,7 @@ net::awaitable<void> test_simple_string()
// cmd += "\r\n";
// test_tcp_socket ts {cmd};
// resp3::detail::simple_string_adapter res;
// co_await async_read_one(ts, buffer, res);
// co_await detail::async_read_one(ts, buffer, res);
// check_equal(res.result, str, "simple_string (large)");
// //check_equal(res.attribute.value, {}, "simple_string (empty attribute)");
//}
@@ -692,7 +693,7 @@ net::awaitable<void> test_number()
radapter.clear();
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::number, {"-3"}} };
co_await async_read_one(ts, buf, radapter);
co_await detail::async_read_one(ts, buf, radapter);
check_equal(array_buffer, expected, "number (int)");
}
@@ -703,7 +704,7 @@ net::awaitable<void> test_number()
radapter.clear();
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::number, {"3"}} };
co_await async_read_one(ts, buf, radapter);
co_await detail::async_read_one(ts, buf, radapter);
check_equal(array_buffer, expected, "number (unsigned)");
}
@@ -714,7 +715,7 @@ net::awaitable<void> test_number()
radapter.clear();
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::number, {"1111111"}} };
co_await async_read_one(ts, buf, radapter);
co_await detail::async_read_one(ts, buf, radapter);
check_equal(array_buffer, expected, "number (std::size_t)");
}
}
@@ -734,7 +735,7 @@ net::awaitable<void> test_array()
, {1UL, 1UL, resp3::type::blob_string, {"two"}}
, {1UL, 1UL, resp3::type::blob_string, {"three"}}
};
co_await async_read_one(ts, buf, radapter);
co_await detail::async_read_one(ts, buf, radapter);
check_equal(array_buffer, expected, "array");
}
@@ -743,7 +744,7 @@ net::awaitable<void> test_array()
test_tcp_socket ts {cmd};
resp3::flat_array_int_type buffer;
resp3::flat_array_int_adapter res{&buffer};
co_await async_read_one(ts, buf, res);
co_await detail::async_read_one(ts, buf, res);
check_equal(buffer, {1, 2, 3}, "array (int)");
}
@@ -754,7 +755,7 @@ net::awaitable<void> test_array()
radapter.clear();
resp3::response::storage_type expected
{ {0UL, 0UL, resp3::type::array, {}} };
co_await async_read_one(ts, buf, radapter);
co_await detail::async_read_one(ts, buf, radapter);
check_equal(array_buffer, expected, "array (empty)");
}
}
@@ -770,7 +771,7 @@ net::awaitable<void> test_blob_string()
radapter.clear();
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::blob_string, {"hh"}} };
co_await async_read_one(ts, buf, radapter);
co_await detail::async_read_one(ts, buf, radapter);
check_equal(array_buffer, expected, "blob_string");
}
@@ -781,7 +782,7 @@ net::awaitable<void> test_blob_string()
radapter.clear();
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::blob_string, {"hhaa\aaaa\raaaaa\r\naaaaaaaaaa"}} };
co_await async_read_one(ts, buf, radapter);
co_await detail::async_read_one(ts, buf, radapter);
check_equal(array_buffer, expected, "blob_string (with separator)");
}
@@ -792,7 +793,7 @@ net::awaitable<void> test_blob_string()
radapter.clear();
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::blob_string, {}} };
co_await async_read_one(ts, buf, radapter);
co_await detail::async_read_one(ts, buf, radapter);
check_equal(array_buffer, expected, "blob_string (size 0)");
}
}
@@ -808,7 +809,7 @@ net::awaitable<void> test_simple_error()
radapter.clear();
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::simple_error, {"Error"}} };
co_await async_read_one(ts, buf, radapter);
co_await detail::async_read_one(ts, buf, radapter);
check_equal(array_buffer, expected, "simple_error (message)");
}
}
@@ -824,7 +825,7 @@ net::awaitable<void> test_floating_point()
auto* adapter = resp.select_adapter(resp3::type::doublean);
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::doublean, {"1.23"}} };
co_await async_read_one(ts, buf, *adapter);
co_await detail::async_read_one(ts, buf, *adapter);
check_equal(resp.raw(), expected, "double");
}
@@ -833,7 +834,7 @@ net::awaitable<void> test_floating_point()
test_tcp_socket ts {cmd};
resp3::response resp;
auto* adapter = resp.select_adapter(resp3::type::doublean);
co_await async_read_one(ts, buf, *adapter);
co_await detail::async_read_one(ts, buf, *adapter);
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::doublean, {"inf"}} };
check_equal(resp.raw(), expected, "double (inf)");
@@ -844,7 +845,7 @@ net::awaitable<void> test_floating_point()
test_tcp_socket ts {cmd};
resp3::response resp;
auto* adapter = resp.select_adapter(resp3::type::doublean);
co_await async_read_one(ts, buf, *adapter);
co_await detail::async_read_one(ts, buf, *adapter);
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::doublean, {"-inf"}} };
check_equal(resp.raw(), expected, "double (-inf)");
@@ -864,7 +865,7 @@ net::awaitable<void> test_boolean()
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::boolean, {"f"}} };
co_await async_read_one(ts, buf, *adapter);
co_await detail::async_read_one(ts, buf, *adapter);
check_equal(resp.raw(), expected, "bool (false)");
}
@@ -876,7 +877,7 @@ net::awaitable<void> test_boolean()
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::boolean, {"t"}} };
co_await async_read_one(ts, buf, *adapter);
co_await detail::async_read_one(ts, buf, *adapter);
check_equal(resp.raw(), expected, "bool (true)");
}
}
@@ -892,7 +893,7 @@ net::awaitable<void> test_blob_error()
radapter.clear();
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::blob_error, {"SYNTAX invalid syntax"}} };
co_await async_read_one(ts, buf, radapter);
co_await detail::async_read_one(ts, buf, radapter);
check_equal(array_buffer, expected, "blob_error (message)");
}
@@ -904,7 +905,7 @@ net::awaitable<void> test_blob_error()
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::blob_error, {}} };
co_await async_read_one(ts, buf, radapter);
co_await detail::async_read_one(ts, buf, radapter);
check_equal(array_buffer, expected, "blob_error (empty message)");
}
}
@@ -920,7 +921,7 @@ net::awaitable<void> test_verbatim_string()
radapter.clear();
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::verbatim_string, {"txt:Some string"}} };
co_await async_read_one(ts, buf, radapter);
co_await detail::async_read_one(ts, buf, radapter);
check_equal(array_buffer, expected, "verbatim_string");
}
@@ -929,7 +930,7 @@ net::awaitable<void> test_verbatim_string()
test_tcp_socket ts {cmd};
array_buffer.clear();
radapter.clear();
co_await async_read_one(ts, buf, radapter);
co_await detail::async_read_one(ts, buf, radapter);
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::verbatim_string, {}} };
check_equal(array_buffer, expected, "verbatim_string (empty)");
@@ -954,7 +955,7 @@ net::awaitable<void> test_set2()
, { 1UL, 1UL, resp3::type::simple_string, {"three"}}
};
co_await async_read_one(ts, buf, radapter);
co_await detail::async_read_one(ts, buf, radapter);
check_equal(array_buffer, expected, "test set (1)");
}
@@ -967,7 +968,7 @@ net::awaitable<void> test_set2()
{ { 0UL, 0UL, resp3::type::set, {}}
};
co_await async_read_one(ts, buf, radapter);
co_await detail::async_read_one(ts, buf, radapter);
check_equal(array_buffer, expected, "test set (2)");
}
}
@@ -981,7 +982,7 @@ net::awaitable<void> test_map()
test_tcp_socket ts {cmd};
array_buffer.clear();
radapter.clear();
co_await async_read_one(ts, buf, radapter);
co_await detail::async_read_one(ts, buf, radapter);
resp3::response::storage_type expected
{ {14UL, 0UL, resp3::type::map, {}}
@@ -1008,7 +1009,7 @@ net::awaitable<void> test_map()
test_tcp_socket ts {cmd};
array_buffer.clear();
radapter.clear();
co_await async_read_one(ts, buf, radapter);
co_await detail::async_read_one(ts, buf, radapter);
resp3::response::storage_type expected
{ {0UL, 0UL, resp3::type::map, {}} };
check_equal(array_buffer, expected, "test map (empty)");
@@ -1026,7 +1027,7 @@ net::awaitable<void> test_streamed_string()
radapter.clear();
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::streamed_string_part, {"Hello world"}} };
co_await resp3::async_read_one(ts, buf, radapter);
co_await detail::async_read_one(ts, buf, radapter);
check_equal(array_buffer, expected, "streamed string");
}
@@ -1035,7 +1036,7 @@ net::awaitable<void> test_streamed_string()
test_tcp_socket ts {cmd};
resp3::response resp;
auto* adapter = resp.select_adapter(resp3::type::streamed_string_part, command::unknown, {});
co_await resp3::async_read_one(ts, buf, *adapter);
co_await detail::async_read_one(ts, buf, *adapter);
resp3::response::storage_type expected
{ {1UL, 0UL, resp3::type::streamed_string_part, {}} };
@@ -1050,7 +1051,7 @@ net::awaitable<void> offline()
// std::string cmd {"|1\r\n+key-popularity\r\n%2\r\n$1\r\na\r\n,0.1923\r\n$1\r\nb\r\n,0.0012\r\n"};
// test_tcp_socket ts {cmd};
// resp3::flat_radapter res;
// co_await async_read_one(ts, buf, res);
// co_await detail::async_read_one(ts, buf, res);
// check_equal(res.result, {"key-popularity", "a", "0.1923", "b", "0.0012"}, "attribute");
//}
@@ -1058,7 +1059,7 @@ net::awaitable<void> offline()
// std::string cmd {">4\r\n+pubsub\r\n+message\r\n+foo\r\n+bar\r\n"};
// test_tcp_socket ts {cmd};
// resp3::flat_radapter res;
// co_await async_read_one(ts, buf, res);
// co_await detail::async_read_one(ts, buf, res);
// check_equal(res.result, {"pubsub", "message", "foo", "bar"}, "push type");
//}
@@ -1066,7 +1067,7 @@ net::awaitable<void> offline()
// std::string cmd {">0\r\n"};
// test_tcp_socket ts {cmd};
// resp3::flat_radapter res;
// co_await async_read_one(ts, buf, res);
// co_await detail::async_read_one(ts, buf, res);
// check_equal(res.result, {}, "push type (empty)");
//}
}