2
0
mirror of https://github.com/boostorg/redis.git synced 2026-01-19 04:42:09 +00:00

Adds automatic formatting with clang-format

This commit is contained in:
Anarthal (Rubén Pérez)
2025-05-12 13:49:55 +02:00
committed by GitHub
parent 1060733b84
commit 328ad97a79
81 changed files with 1736 additions and 1589 deletions

176
.clang-format Normal file
View File

@@ -0,0 +1,176 @@
---
Language: Cpp
ColumnLimit: 100
IndentWidth: 3
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: true
AfterClass: false
AfterControlStatement: false
AfterEnum: true
AfterFunction: true
AfterNamespace: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: true
AccessModifierOffset: -3
BinPackArguments: false
BinPackParameters: false
AlignAfterOpenBracket: AlwaysBreak
PointerAlignment: Left
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<boost/redis.*>|<boost/redis/.*>'
Priority: -10
SortPriority: 1
- Regex: '^<boost/.*>'
Priority: -8
SortPriority: 3
- Regex: "^<.*"
Priority: -6
SortPriority: 5
- Regex: ".*"
Priority: -5
SortPriority: 4
IndentCaseLabels: true
AllowShortCaseLabelsOnASingleLine: true
AllowAllArgumentsOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlignArrayOfStructures: Left
DerivePointerAlignment: false
PenaltyBreakAssignment: 2000000
PenaltyBreakBeforeFirstCallParameter: 0
PenaltyBreakOpenParenthesis: 0
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyBreakScopeResolution: 1000000
PenaltyReturnTypeOnItsOwnLine: 200000000
# Defaults (based on Google)
AlignConsecutiveMacros: false
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllConstructorInitializersOnNextLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: Empty
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: ExceptShortType
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
BreakTemplateDeclarations: Leave
BreakBeforeBinaryOperators: None
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: true
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
CommentPragmas: '(^ IWYU pragma:)|(^\\copydoc )|(^ ?\\n)'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 0
ContinuationIndentWidth: 3
Cpp11BracedListStyle: true
DeriveLineEnding: true
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeIsMainRegex: null
IncludeIsMainSourceRegex: ""
IndentGotoLabels: false
IndentPPDirectives: None
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ""
MacroBlockEnd: ""
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- "c++"
- "C++"
CanonicalDelimiter: ""
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
CanonicalDelimiter: ""
BasedOnStyle: google
ReflowComments: false
SortIncludes: true
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
Standard: Auto
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseCRLF: false
UseTab: Never
AlignConsecutiveShortCaseStatements:
Enabled: true
AcrossEmptyLines: false
AcrossComments: true
AlignCaseColons: false
---

View File

@@ -4,8 +4,9 @@
* accompanying file LICENSE.txt) * accompanying file LICENSE.txt)
*/ */
#include <iostream>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <iostream>
#if defined(BOOST_ASIO_HAS_CO_AWAIT) #if defined(BOOST_ASIO_HAS_CO_AWAIT)
namespace net = boost::asio; namespace net = boost::asio;
@@ -62,6 +63,10 @@ int main(int argc, char* argv[])
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
} }
} }
#else // defined(BOOST_ASIO_HAS_CO_AWAIT) #else // defined(BOOST_ASIO_HAS_CO_AWAIT)
auto main() -> int {std::cout << "Requires coroutine support." << std::endl; return 1;} auto main() -> int
#endif // defined(BOOST_ASIO_HAS_CO_AWAIT) {
std::cout << "Requires coroutine support." << std::endl;
return 1;
}
#endif // defined(BOOST_ASIO_HAS_CO_AWAIT)

View File

@@ -8,9 +8,10 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#include <boost/asio.hpp>
#include <cstdio> #include <cstdio>
#include <iostream> #include <iostream>
#include <boost/asio.hpp>
#if defined(BOOST_ASIO_HAS_CO_AWAIT) #if defined(BOOST_ASIO_HAS_CO_AWAIT)
namespace net = boost::asio; namespace net = boost::asio;
@@ -27,37 +28,41 @@ constexpr net::use_awaitable_t<executor_type> use_awaitable;
awaitable_type echo(tcp_socket socket) awaitable_type echo(tcp_socket socket)
{ {
try { try {
char data[1024]; char data[1024];
for (;;) { for (;;) {
std::size_t n = co_await socket.async_read_some(net::buffer(data), use_awaitable); std::size_t n = co_await socket.async_read_some(net::buffer(data), use_awaitable);
co_await async_write(socket, net::buffer(data, n), use_awaitable); co_await async_write(socket, net::buffer(data, n), use_awaitable);
} }
} catch (std::exception const&) { } catch (std::exception const&) {
//std::printf("echo Exception: %s\n", e.what()); //std::printf("echo Exception: %s\n", e.what());
} }
} }
awaitable_type listener() awaitable_type listener()
{ {
auto ex = co_await this_coro::executor; auto ex = co_await this_coro::executor;
tcp_acceptor acceptor(ex, {tcp::v4(), 55555}); tcp_acceptor acceptor(ex, {tcp::v4(), 55555});
for (;;) { for (;;) {
tcp_socket socket = co_await acceptor.async_accept(use_awaitable); tcp_socket socket = co_await acceptor.async_accept(use_awaitable);
co_spawn(ex, echo(std::move(socket)), detached); co_spawn(ex, echo(std::move(socket)), detached);
} }
} }
int main() int main()
{ {
try { try {
net::io_context io_context{BOOST_ASIO_CONCURRENCY_HINT_UNSAFE_IO}; net::io_context io_context{BOOST_ASIO_CONCURRENCY_HINT_UNSAFE_IO};
co_spawn(io_context, listener(), detached); co_spawn(io_context, listener(), detached);
io_context.run(); io_context.run();
} catch (std::exception const& e) { } catch (std::exception const& e) {
std::printf("Exception: %s\n", e.what()); std::printf("Exception: %s\n", e.what());
} }
} }
#else // defined(BOOST_ASIO_HAS_CO_AWAIT) #else // defined(BOOST_ASIO_HAS_CO_AWAIT)
auto main() -> int {std::cout << "Requires coroutine support." << std::endl; return 1;} auto main() -> int
#endif // defined(BOOST_ASIO_HAS_CO_AWAIT) {
std::cout << "Requires coroutine support." << std::endl;
return 1;
}
#endif // defined(BOOST_ASIO_HAS_CO_AWAIT)

View File

@@ -5,7 +5,9 @@
*/ */
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/asio/detached.hpp> #include <boost/asio/detached.hpp>
#include <iostream> #include <iostream>
namespace asio = boost::asio; namespace asio = boost::asio;
@@ -14,7 +16,7 @@ using boost::redis::request;
using boost::redis::response; using boost::redis::response;
using boost::redis::config; using boost::redis::config;
auto main(int argc, char * argv[]) -> int auto main(int argc, char* argv[]) -> int
{ {
try { try {
config cfg; config cfg;
@@ -47,4 +49,3 @@ auto main(int argc, char * argv[]) -> int
return 1; return 1;
} }
} }

View File

@@ -6,15 +6,15 @@
#include "sync_connection.hpp" #include "sync_connection.hpp"
#include <string>
#include <iostream> #include <iostream>
#include <string>
using boost::redis::sync_connection; using boost::redis::sync_connection;
using boost::redis::request; using boost::redis::request;
using boost::redis::response; using boost::redis::response;
using boost::redis::config; using boost::redis::config;
auto main(int argc, char * argv[]) -> int auto main(int argc, char* argv[]) -> int
{ {
try { try {
config cfg; config cfg;

View File

@@ -5,13 +5,15 @@
*/ */
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/asio/co_spawn.hpp> #include <boost/asio/co_spawn.hpp>
#include <boost/asio/detached.hpp> #include <boost/asio/detached.hpp>
#include <boost/asio/redirect_error.hpp>
#include <boost/asio/posix/stream_descriptor.hpp> #include <boost/asio/posix/stream_descriptor.hpp>
#include <unistd.h> #include <boost/asio/redirect_error.hpp>
#include <boost/asio/signal_set.hpp>
#include <iostream> #include <iostream>
#include <unistd.h>
#if defined(BOOST_ASIO_HAS_CO_AWAIT) #if defined(BOOST_ASIO_HAS_CO_AWAIT)
#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
@@ -38,8 +40,7 @@ using namespace std::chrono_literals;
// Chat over Redis pubsub. To test, run this program from multiple // Chat over Redis pubsub. To test, run this program from multiple
// terminals and type messages to stdin. // terminals and type messages to stdin.
auto auto receiver(std::shared_ptr<connection> conn) -> awaitable<void>
receiver(std::shared_ptr<connection> conn) -> awaitable<void>
{ {
request req; request req;
req.push("SUBSCRIBE", "channel"); req.push("SUBSCRIBE", "channel");
@@ -48,7 +49,6 @@ receiver(std::shared_ptr<connection> conn) -> awaitable<void>
conn->set_receive_response(resp); conn->set_receive_response(resp);
while (conn->will_reconnect()) { while (conn->will_reconnect()) {
// Subscribe to channels. // Subscribe to channels.
co_await conn->async_exec(req, ignore); co_await conn->async_exec(req, ignore);
@@ -56,19 +56,17 @@ receiver(std::shared_ptr<connection> conn) -> awaitable<void>
for (error_code ec;;) { for (error_code ec;;) {
co_await conn->async_receive(redirect_error(use_awaitable, ec)); co_await conn->async_receive(redirect_error(use_awaitable, ec));
if (ec) if (ec)
break; // Connection lost, break so we can reconnect to channels. break; // Connection lost, break so we can reconnect to channels.
std::cout std::cout << resp.value().at(1).value << " " << resp.value().at(2).value << " "
<< resp.value().at(1).value << resp.value().at(3).value << std::endl;
<< " " << resp.value().at(2).value
<< " " << resp.value().at(3).value
<< std::endl;
resp.value().clear(); resp.value().clear();
} }
} }
} }
// Publishes stdin messages to a Redis channel. // Publishes stdin messages to a Redis channel.
auto publisher(std::shared_ptr<stream_descriptor> in, std::shared_ptr<connection> conn) -> awaitable<void> auto publisher(std::shared_ptr<stream_descriptor> in, std::shared_ptr<connection> conn)
-> awaitable<void>
{ {
for (std::string msg;;) { for (std::string msg;;) {
auto n = co_await async_read_until(*in, dynamic_buffer(msg, 1024), "\n"); auto n = co_await async_read_until(*in, dynamic_buffer(msg, 1024), "\n");
@@ -96,11 +94,11 @@ auto co_main(config cfg) -> awaitable<void>
stream->cancel(); stream->cancel();
} }
#else // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) #else // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
auto co_main(config const&) -> awaitable<void> auto co_main(config const&) -> awaitable<void>
{ {
std::cout << "Requires support for posix streams." << std::endl; std::cout << "Requires support for posix streams." << std::endl;
co_return; co_return;
} }
#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
#endif // defined(BOOST_ASIO_HAS_CO_AWAIT) #endif // defined(BOOST_ASIO_HAS_CO_AWAIT)

View File

@@ -5,11 +5,13 @@
*/ */
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/co_spawn.hpp> #include <boost/asio/co_spawn.hpp>
#include <boost/asio/detached.hpp>
#include <iostream>
#include <map> #include <map>
#include <vector> #include <vector>
#include <iostream>
#if defined(BOOST_ASIO_HAS_CO_AWAIT) #if defined(BOOST_ASIO_HAS_CO_AWAIT)
@@ -24,38 +26,41 @@ using boost::asio::awaitable;
using boost::asio::detached; using boost::asio::detached;
using boost::asio::consign; using boost::asio::consign;
template<class T> template <class T>
std::ostream& operator<<(std::ostream& os, std::optional<T> const& opt) std::ostream& operator<<(std::ostream& os, std::optional<T> const& opt)
{ {
if (opt.has_value()) if (opt.has_value())
std::cout << opt.value(); std::cout << opt.value();
else else
std::cout << "null"; std::cout << "null";
return os; return os;
} }
void print(std::map<std::string, std::string> const& cont) void print(std::map<std::string, std::string> const& cont)
{ {
for (auto const& e: cont) for (auto const& e : cont)
std::cout << e.first << ": " << e.second << "\n"; std::cout << e.first << ": " << e.second << "\n";
} }
template <class T> template <class T>
void print(std::vector<T> const& cont) void print(std::vector<T> const& cont)
{ {
for (auto const& e: cont) std::cout << e << " "; for (auto const& e : cont)
std::cout << e << " ";
std::cout << "\n"; std::cout << "\n";
} }
// Stores the content of some STL containers in Redis. // Stores the content of some STL containers in Redis.
auto store(std::shared_ptr<connection> conn) -> awaitable<void> auto store(std::shared_ptr<connection> conn) -> awaitable<void>
{ {
std::vector<int> vec std::vector<int> vec{1, 2, 3, 4, 5, 6};
{1, 2, 3, 4, 5, 6};
std::map<std::string, std::string> map std::map<std::string, std::string> map{
{{"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}}; {"key1", "value1"},
{"key2", "value2"},
{"key3", "value3"}
};
request req; request req;
req.push_range("RPUSH", "rpush-key", vec); req.push_range("RPUSH", "rpush-key", vec);
@@ -100,22 +105,22 @@ auto transaction(std::shared_ptr<connection> conn) -> awaitable<void>
{ {
request req; request req;
req.push("MULTI"); req.push("MULTI");
req.push("LRANGE", "rpush-key", 0, -1); // Retrieves req.push("LRANGE", "rpush-key", 0, -1); // Retrieves
req.push("HGETALL", "hset-key"); // Retrieves req.push("HGETALL", "hset-key"); // Retrieves
req.push("MGET", "key", "non-existing-key"); req.push("MGET", "key", "non-existing-key");
req.push("EXEC"); req.push("EXEC");
response< response<
ignore_t, // multi ignore_t, // multi
ignore_t, // lrange ignore_t, // lrange
ignore_t, // hgetall ignore_t, // hgetall
ignore_t, // mget ignore_t, // mget
response< response<
std::optional<std::vector<int>>, std::optional<std::vector<int>>,
std::optional<std::map<std::string, std::string>>, std::optional<std::map<std::string, std::string>>,
std::optional<std::vector<std::optional<std::string>>> std::optional<std::vector<std::optional<std::string>>>> // exec
> // exec >
> resp; resp;
co_await conn->async_exec(req, resp); co_await conn->async_exec(req, resp);
@@ -137,4 +142,4 @@ awaitable<void> co_main(config cfg)
conn->cancel(); conn->cancel();
} }
#endif // defined(BOOST_ASIO_HAS_CO_AWAIT) #endif // defined(BOOST_ASIO_HAS_CO_AWAIT)

View File

@@ -5,10 +5,12 @@
*/ */
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/detached.hpp> #include <boost/asio/detached.hpp>
#include <boost/asio/redirect_error.hpp> #include <boost/asio/redirect_error.hpp>
#include <boost/asio/co_spawn.hpp> #include <boost/asio/signal_set.hpp>
#include <iostream> #include <iostream>
#if defined(BOOST_ASIO_HAS_CO_AWAIT) #if defined(BOOST_ASIO_HAS_CO_AWAIT)
@@ -22,10 +24,8 @@ using boost::system::error_code;
using boost::redis::connection; using boost::redis::connection;
using namespace std::chrono_literals; using namespace std::chrono_literals;
auto auto echo_server_session(asio::ip::tcp::socket socket, std::shared_ptr<connection> conn)
echo_server_session( -> asio::awaitable<void>
asio::ip::tcp::socket socket,
std::shared_ptr<connection> conn) -> asio::awaitable<void>
{ {
request req; request req;
response<std::string> resp; response<std::string> resp;
@@ -67,4 +67,4 @@ auto co_main(config cfg) -> asio::awaitable<void>
conn->cancel(); conn->cancel();
} }
#endif // defined(BOOST_ASIO_HAS_CO_AWAIT) #endif // defined(BOOST_ASIO_HAS_CO_AWAIT)

View File

@@ -5,9 +5,11 @@
*/ */
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/asio/co_spawn.hpp> #include <boost/asio/co_spawn.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/consign.hpp> #include <boost/asio/consign.hpp>
#include <boost/asio/detached.hpp>
#include <iostream> #include <iostream>
#if defined(BOOST_ASIO_HAS_CO_AWAIT) #if defined(BOOST_ASIO_HAS_CO_AWAIT)
@@ -38,4 +40,4 @@ auto co_main(config cfg) -> asio::awaitable<void>
std::cout << "PING: " << std::get<0>(resp).value() << std::endl; std::cout << "PING: " << std::get<0>(resp).value() << std::endl;
} }
#endif // defined(BOOST_ASIO_HAS_CO_AWAIT) #endif // defined(BOOST_ASIO_HAS_CO_AWAIT)

View File

@@ -5,9 +5,11 @@
*/ */
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/asio/use_awaitable.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/consign.hpp> #include <boost/asio/consign.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/use_awaitable.hpp>
#include <iostream> #include <iostream>
#if defined(BOOST_ASIO_HAS_CO_AWAIT) #if defined(BOOST_ASIO_HAS_CO_AWAIT)
@@ -50,4 +52,4 @@ auto co_main(config cfg) -> asio::awaitable<void>
std::cout << "Response: " << std::get<0>(resp).value() << std::endl; std::cout << "Response: " << std::get<0>(resp).value() << std::endl;
} }
#endif // defined(BOOST_ASIO_HAS_CO_AWAIT) #endif // defined(BOOST_ASIO_HAS_CO_AWAIT)

View File

@@ -5,20 +5,23 @@
*/ */
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/asio/detached.hpp>
#include <boost/describe.hpp>
#include <boost/asio/consign.hpp> #include <boost/asio/consign.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/use_awaitable.hpp> #include <boost/asio/use_awaitable.hpp>
#include <string> #include <boost/describe.hpp>
#include <iostream> #include <iostream>
#include <string>
#if defined(BOOST_ASIO_HAS_CO_AWAIT) #if defined(BOOST_ASIO_HAS_CO_AWAIT)
#include <boost/json/serialize.hpp> #include <boost/redis/resp3/serialization.hpp>
#include <boost/json/parse.hpp> #include <boost/json/parse.hpp>
#include <boost/json/serialize.hpp>
#include <boost/json/value_from.hpp> #include <boost/json/value_from.hpp>
#include <boost/json/value_to.hpp> #include <boost/json/value_to.hpp>
#include <boost/redis/resp3/serialization.hpp>
namespace asio = boost::asio; namespace asio = boost::asio;
namespace resp3 = boost::redis::resp3; namespace resp3 = boost::redis::resp3;
@@ -30,7 +33,7 @@ using boost::redis::config;
using boost::redis::connection; using boost::redis::connection;
using boost::redis::resp3::node_view; using boost::redis::resp3::node_view;
// Struct that will be stored in Redis using json serialization. // Struct that will be stored in Redis using json serialization.
struct user { struct user {
std::string name; std::string name;
std::string age; std::string age;
@@ -46,11 +49,7 @@ void boost_redis_to_bulk(std::string& to, user const& u)
resp3::boost_redis_to_bulk(to, boost::json::serialize(boost::json::value_from(u))); resp3::boost_redis_to_bulk(to, boost::json::serialize(boost::json::value_from(u)));
} }
void void boost_redis_from_bulk(user& u, node_view const& node, boost::system::error_code&)
boost_redis_from_bulk(
user& u,
node_view const& node,
boost::system::error_code&)
{ {
u = boost::json::value_to<user>(boost::json::parse(node.value)); u = boost::json::value_to<user>(boost::json::parse(node.value));
} }
@@ -66,8 +65,8 @@ auto co_main(config cfg) -> asio::awaitable<void>
// Stores and retrieves in the same request. // Stores and retrieves in the same request.
request req; request req;
req.push("SET", "json-key", u); // Stores in Redis. req.push("SET", "json-key", u); // Stores in Redis.
req.push("GET", "json-key"); // Retrieves from Redis. req.push("GET", "json-key"); // Retrieves from Redis.
response<ignore_t, user> resp; response<ignore_t, user> resp;
@@ -75,10 +74,9 @@ auto co_main(config cfg) -> asio::awaitable<void>
conn->cancel(); conn->cancel();
// Prints the first ping // Prints the first ping
std::cout std::cout << "Name: " << std::get<1>(resp).value().name << "\n"
<< "Name: " << std::get<1>(resp).value().name << "\n" << "Age: " << std::get<1>(resp).value().age << "\n"
<< "Age: " << std::get<1>(resp).value().age << "\n" << "Country: " << std::get<1>(resp).value().country << "\n";
<< "Country: " << std::get<1>(resp).value().country << "\n";
} }
#endif // defined(BOOST_ASIO_HAS_CO_AWAIT) #endif // defined(BOOST_ASIO_HAS_CO_AWAIT)

View File

@@ -6,10 +6,12 @@
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/redis/resp3/serialization.hpp> #include <boost/redis/resp3/serialization.hpp>
#include <boost/asio/co_spawn.hpp> #include <boost/asio/co_spawn.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/consign.hpp> #include <boost/asio/consign.hpp>
#include <boost/asio/detached.hpp>
#include <boost/system/errc.hpp> #include <boost/system/errc.hpp>
#include <iostream> #include <iostream>
// See the definition in person.proto. This header is automatically // See the definition in person.proto. This header is automatically
@@ -32,8 +34,7 @@ using boost::redis::resp3::node_view;
using tutorial::person; using tutorial::person;
// Boost.Redis customization points (example/protobuf.hpp) // Boost.Redis customization points (example/protobuf.hpp)
namespace tutorial namespace tutorial {
{
// Below I am using a Boost.Redis to indicate a protobuf error, this // Below I am using a Boost.Redis to indicate a protobuf error, this
// is ok for an example, users however might want to define their own // is ok for an example, users however might want to define their own
@@ -47,18 +48,14 @@ void boost_redis_to_bulk(std::string& to, person const& u)
resp3::boost_redis_to_bulk(to, tmp); resp3::boost_redis_to_bulk(to, tmp);
} }
void void boost_redis_from_bulk(person& u, node_view const& node, boost::system::error_code& ec)
boost_redis_from_bulk(
person& u,
node_view const& node,
boost::system::error_code& ec)
{ {
std::string const tmp {node.value}; std::string const tmp{node.value};
if (!u.ParseFromString(tmp)) if (!u.ParseFromString(tmp))
ec = boost::redis::error::invalid_data_type; ec = boost::redis::error::invalid_data_type;
} }
} // tutorial } // namespace tutorial
using tutorial::boost_redis_to_bulk; using tutorial::boost_redis_to_bulk;
using tutorial::boost_redis_from_bulk; using tutorial::boost_redis_from_bulk;
@@ -84,10 +81,9 @@ asio::awaitable<void> co_main(config cfg)
co_await conn->async_exec(req, resp); co_await conn->async_exec(req, resp);
conn->cancel(); conn->cancel();
std::cout std::cout << "Name: " << std::get<1>(resp).value().name() << "\n"
<< "Name: " << std::get<1>(resp).value().name() << "\n" << "Age: " << std::get<1>(resp).value().id() << "\n"
<< "Age: " << std::get<1>(resp).value().id() << "\n" << "Email: " << std::get<1>(resp).value().email() << "\n";
<< "Email: " << std::get<1>(resp).value().email() << "\n";
} }
#endif // defined(BOOST_ASIO_HAS_CO_AWAIT) #endif // defined(BOOST_ASIO_HAS_CO_AWAIT)

View File

@@ -5,9 +5,11 @@
*/ */
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/asio/use_awaitable.hpp>
#include <boost/asio/redirect_error.hpp>
#include <boost/asio/detached.hpp> #include <boost/asio/detached.hpp>
#include <boost/asio/redirect_error.hpp>
#include <boost/asio/use_awaitable.hpp>
#include <iostream> #include <iostream>
#if defined(BOOST_ASIO_HAS_CO_AWAIT) #if defined(BOOST_ASIO_HAS_CO_AWAIT)
@@ -21,8 +23,7 @@ using boost::redis::config;
using boost::redis::address; using boost::redis::address;
using boost::redis::connection; using boost::redis::connection;
auto redir(boost::system::error_code& ec) auto redir(boost::system::error_code& ec) { return asio::redirect_error(asio::use_awaitable, ec); }
{ return asio::redirect_error(asio::use_awaitable, ec); }
// For more info see // For more info see
// - https://redis.io/docs/manual/sentinel. // - https://redis.io/docs/manual/sentinel.
@@ -48,7 +49,9 @@ auto resolve_master_address(std::vector<address> const& addresses) -> asio::awai
conn->cancel(); conn->cancel();
conn->reset_stream(); conn->reset_stream();
if (!ec && std::get<0>(resp)) if (!ec && std::get<0>(resp))
co_return address{std::get<0>(resp).value().value().at(0), std::get<0>(resp).value().value().at(1)}; co_return address{
std::get<0>(resp).value().value().at(0),
std::get<0>(resp).value().value().at(1)};
} }
co_return address{}; co_return address{};
@@ -58,18 +61,17 @@ auto co_main(config cfg) -> asio::awaitable<void>
{ {
// A list of sentinel addresses from which only one is responsive. // A list of sentinel addresses from which only one is responsive.
// This simulates sentinels that are down. // This simulates sentinels that are down.
std::vector<address> const addresses std::vector<address> const addresses{
{ address{"foo", "26379"} address{"foo", "26379"},
, address{"bar", "26379"} address{"bar", "26379"},
, cfg.addr cfg.addr
}; };
auto const ep = co_await resolve_master_address(addresses); auto const ep = co_await resolve_master_address(addresses);
std::clog std::clog << "Host: " << ep.host << "\n"
<< "Host: " << ep.host << "\n" << "Port: " << ep.port << "\n"
<< "Port: " << ep.port << "\n" << std::flush;
<< std::flush;
} }
#endif // defined(BOOST_ASIO_HAS_CO_AWAIT) #endif // defined(BOOST_ASIO_HAS_CO_AWAIT)

View File

@@ -5,11 +5,13 @@
*/ */
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/consign.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/asio/awaitable.hpp> #include <boost/asio/awaitable.hpp>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/consign.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/signal_set.hpp>
#include <iostream> #include <iostream>
#if defined(BOOST_ASIO_HAS_CO_AWAIT) #if defined(BOOST_ASIO_HAS_CO_AWAIT)
@@ -29,53 +31,51 @@ using net::signal_set;
auto stream_reader(std::shared_ptr<connection> conn) -> net::awaitable<void> auto stream_reader(std::shared_ptr<connection> conn) -> net::awaitable<void>
{ {
std::string redisStreamKey_; std::string redisStreamKey_;
request req; request req;
generic_response resp; generic_response resp;
std::string stream_id{"$"}; std::string stream_id{"$"};
std::string const field = "myfield"; std::string const field = "myfield";
for (;;) { for (;;) {
req.push("XREAD", "BLOCK", "0", "STREAMS", "test-topic", stream_id); req.push("XREAD", "BLOCK", "0", "STREAMS", "test-topic", stream_id);
co_await conn->async_exec(req, resp); co_await conn->async_exec(req, resp);
//std::cout << "Response: "; //std::cout << "Response: ";
//for (auto i = 0UL; i < resp->size(); ++i) { //for (auto i = 0UL; i < resp->size(); ++i) {
// std::cout << resp->at(i).value << ", "; // std::cout << resp->at(i).value << ", ";
//} //}
//std::cout << std::endl; //std::cout << std::endl;
// The following approach was taken in order to be able to // The following approach was taken in order to be able to
// deal with the responses, as generated by redis in the case // deal with the responses, as generated by redis in the case
// that there are multiple stream 'records' within a single // that there are multiple stream 'records' within a single
// generic_response. The nesting and number of values in // generic_response. The nesting and number of values in
// resp.value() are different, depending on the contents // resp.value() are different, depending on the contents
// of the stream in redis. Uncomment the above commented-out // of the stream in redis. Uncomment the above commented-out
// code for examples while running the XADD command. // code for examples while running the XADD command.
std::size_t item_index = 0; std::size_t item_index = 0;
while (item_index < std::size(resp.value())) { while (item_index < std::size(resp.value())) {
auto const& val = resp.value().at(item_index).value; auto const& val = resp.value().at(item_index).value;
if (field.compare(val) == 0) { if (field.compare(val) == 0) {
// We've hit a myfield field. // We've hit a myfield field.
// The streamId is located at item_index - 2 // The streamId is located at item_index - 2
// The payload is located at item_index + 1 // The payload is located at item_index + 1
stream_id = resp.value().at(item_index - 2).value; stream_id = resp.value().at(item_index - 2).value;
std::cout std::cout << "StreamId: " << stream_id << ", "
<< "StreamId: " << stream_id << ", " << "MyField: " << resp.value().at(item_index + 1).value << std::endl;
<< "MyField: " << resp.value().at(item_index + 1).value ++item_index; // We can increase so we don't read this again
<< std::endl; }
++item_index; // We can increase so we don't read this again
}
++item_index; ++item_index;
} }
req.clear(); req.clear();
resp.value().clear(); resp.value().clear();
} }
} }
// Run this in another terminal: // Run this in another terminal:
@@ -94,4 +94,4 @@ auto co_main(config cfg) -> net::awaitable<void>
co_await sig_set.async_wait(); co_await sig_set.async_wait();
conn->cancel(); conn->cancel();
} }
#endif // defined(BOOST_ASIO_HAS_CO_AWAIT) #endif // defined(BOOST_ASIO_HAS_CO_AWAIT)

View File

@@ -6,13 +6,15 @@
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/redis/logger.hpp> #include <boost/redis/logger.hpp>
#include <boost/asio/awaitable.hpp> #include <boost/asio/awaitable.hpp>
#include <boost/asio/use_awaitable.hpp>
#include <boost/asio/co_spawn.hpp> #include <boost/asio/co_spawn.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/consign.hpp> #include <boost/asio/consign.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/redirect_error.hpp> #include <boost/asio/redirect_error.hpp>
#include <boost/asio/signal_set.hpp> #include <boost/asio/signal_set.hpp>
#include <boost/asio/use_awaitable.hpp>
#include <iostream> #include <iostream>
#if defined(BOOST_ASIO_HAS_CO_AWAIT) #if defined(BOOST_ASIO_HAS_CO_AWAIT)
@@ -47,8 +49,7 @@ using asio::signal_set;
*/ */
// Receives server pushes. // Receives server pushes.
auto auto receiver(std::shared_ptr<connection> conn) -> asio::awaitable<void>
receiver(std::shared_ptr<connection> conn) -> asio::awaitable<void>
{ {
request req; request req;
req.push("SUBSCRIBE", "channel"); req.push("SUBSCRIBE", "channel");
@@ -58,7 +59,6 @@ receiver(std::shared_ptr<connection> conn) -> asio::awaitable<void>
// Loop while reconnection is enabled // Loop while reconnection is enabled
while (conn->will_reconnect()) { while (conn->will_reconnect()) {
// Reconnect to the channels. // Reconnect to the channels.
co_await conn->async_exec(req, ignore); co_await conn->async_exec(req, ignore);
@@ -72,13 +72,10 @@ receiver(std::shared_ptr<connection> conn) -> asio::awaitable<void>
} }
if (ec) if (ec)
break; // Connection lost, break so we can reconnect to channels. break; // Connection lost, break so we can reconnect to channels.
std::cout std::cout << resp.value().at(1).value << " " << resp.value().at(2).value << " "
<< resp.value().at(1).value << resp.value().at(3).value << std::endl;
<< " " << resp.value().at(2).value
<< " " << resp.value().at(3).value
<< std::endl;
consume_one(resp); consume_one(resp);
} }
@@ -98,4 +95,4 @@ auto co_main(config cfg) -> asio::awaitable<void>
conn->cancel(); conn->cancel();
} }
#endif // defined(BOOST_ASIO_HAS_CO_AWAIT) #endif // defined(BOOST_ASIO_HAS_CO_AWAIT)

View File

@@ -4,11 +4,13 @@
* accompanying file LICENSE.txt) * accompanying file LICENSE.txt)
*/ */
#include <boost/redis/connection.hpp>
#include <boost/redis/config.hpp> #include <boost/redis/config.hpp>
#include <boost/redis/connection.hpp>
#include <boost/asio/co_spawn.hpp> #include <boost/asio/co_spawn.hpp>
#include <boost/asio/use_awaitable.hpp>
#include <boost/asio/io_context.hpp> #include <boost/asio/io_context.hpp>
#include <boost/asio/use_awaitable.hpp>
#include <iostream> #include <iostream>
namespace asio = boost::asio; namespace asio = boost::asio;
@@ -19,7 +21,7 @@ using boost::redis::logger;
extern asio::awaitable<void> co_main(config); extern asio::awaitable<void> co_main(config);
auto main(int argc, char * argv[]) -> int auto main(int argc, char* argv[]) -> int
{ {
try { try {
config cfg; config cfg;
@@ -42,7 +44,7 @@ auto main(int argc, char * argv[]) -> int
} }
} }
#else // defined(BOOST_ASIO_HAS_CO_AWAIT) #else // defined(BOOST_ASIO_HAS_CO_AWAIT)
auto main() -> int auto main() -> int
{ {
@@ -50,4 +52,4 @@ auto main() -> int
return 0; return 0;
} }
#endif // defined(BOOST_ASIO_HAS_CO_AWAIT) #endif // defined(BOOST_ASIO_HAS_CO_AWAIT)

View File

@@ -7,16 +7,17 @@
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/redis/request.hpp> #include <boost/redis/request.hpp>
#include <boost/asio/deferred.hpp> #include <boost/asio/deferred.hpp>
#include <boost/asio/detached.hpp> #include <boost/asio/detached.hpp>
#include <boost/asio/use_future.hpp> #include <boost/asio/use_future.hpp>
#include <thread>
#include <chrono> #include <chrono>
#include <thread>
using namespace std::chrono_literals; using namespace std::chrono_literals;
namespace boost::redis namespace boost::redis {
{
class sync_connection { class sync_connection {
public: public:
@@ -25,10 +26,7 @@ public:
, conn_{std::make_shared<connection>(ioc_)} , conn_{std::make_shared<connection>(ioc_)}
{ } { }
~sync_connection() ~sync_connection() { thread_.join(); }
{
thread_.join();
}
void run(config cfg) void run(config cfg)
{ {
@@ -42,16 +40,18 @@ public:
void stop() void stop()
{ {
asio::dispatch(ioc_, [this]() { conn_->cancel(); }); asio::dispatch(ioc_, [this]() {
conn_->cancel();
});
} }
template <class Response> template <class Response>
auto exec(request const& req, Response& resp) auto exec(request const& req, Response& resp)
{ {
asio::dispatch( asio::dispatch(conn_->get_executor(), asio::deferred([this, &req, &resp]() {
conn_->get_executor(), return conn_->async_exec(req, resp, asio::deferred);
asio::deferred([this, &req, &resp]() { return conn_->async_exec(req, resp, asio::deferred); })) }))(asio::use_future)
(asio::use_future).get(); .get();
} }
private: private:
@@ -60,4 +60,4 @@ private:
std::thread thread_; std::thread thread_;
}; };
} } // namespace boost::redis

View File

@@ -8,12 +8,12 @@
#define BOOST_REDIS_HPP #define BOOST_REDIS_HPP
#include <boost/redis/config.hpp> #include <boost/redis/config.hpp>
#include <boost/redis/error.hpp>
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/redis/request.hpp> #include <boost/redis/error.hpp>
#include <boost/redis/response.hpp>
#include <boost/redis/ignore.hpp> #include <boost/redis/ignore.hpp>
#include <boost/redis/logger.hpp> #include <boost/redis/logger.hpp>
#include <boost/redis/request.hpp>
#include <boost/redis/response.hpp>
/** @defgroup high-level-api Reference /** @defgroup high-level-api Reference
* *
@@ -25,4 +25,4 @@
* This page contains the documentation of the Aedis low-level API. * This page contains the documentation of the Aedis low-level API.
*/ */
#endif // BOOST_REDIS_HPP #endif // BOOST_REDIS_HPP

View File

@@ -7,20 +7,20 @@
#ifndef BOOST_REDIS_ADAPTER_ADAPT_HPP #ifndef BOOST_REDIS_ADAPTER_ADAPT_HPP
#define BOOST_REDIS_ADAPTER_ADAPT_HPP #define BOOST_REDIS_ADAPTER_ADAPT_HPP
#include <boost/redis/adapter/detail/response_traits.hpp>
#include <boost/redis/adapter/detail/result_traits.hpp>
#include <boost/redis/resp3/node.hpp> #include <boost/redis/resp3/node.hpp>
#include <boost/redis/response.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/mp11.hpp>
#include <boost/system.hpp> #include <boost/system.hpp>
#include <tuple>
#include <limits> #include <limits>
#include <string_view> #include <string_view>
#include <tuple>
#include <variant> #include <variant>
namespace boost::redis::adapter namespace boost::redis::adapter {
{
/** @brief Adapts a type to be used as a response. /** @brief Adapts a type to be used as a response.
* *
@@ -34,7 +34,7 @@ namespace boost::redis::adapter
* *
* @param t Tuple containing the responses. * @param t Tuple containing the responses.
*/ */
template<class T> template <class T>
auto boost_redis_adapt(T& t) noexcept auto boost_redis_adapt(T& t) noexcept
{ {
return detail::response_traits<T>::adapt(t); return detail::response_traits<T>::adapt(t);
@@ -71,10 +71,12 @@ auto boost_redis_adapt(T& t) noexcept
* co_await resp3::async_read(socket, dynamic_buffer(buffer), adapt(execs)); * co_await resp3::async_read(socket, dynamic_buffer(buffer), adapt(execs));
* @endcode * @endcode
*/ */
template<class T> template <class T>
auto adapt2(T& t = redis::ignore) noexcept auto adapt2(T& t = redis::ignore) noexcept
{ return detail::result_traits<T>::adapt(t); } {
return detail::result_traits<T>::adapt(t);
}
} // boost::redis::adapter } // namespace boost::redis::adapter
#endif // BOOST_REDIS_ADAPTER_ADAPT_HPP #endif // BOOST_REDIS_ADAPTER_ADAPT_HPP

View File

@@ -7,10 +7,11 @@
#ifndef BOOST_REDIS_ANY_ADAPTER_HPP #ifndef BOOST_REDIS_ANY_ADAPTER_HPP
#define BOOST_REDIS_ANY_ADAPTER_HPP #define BOOST_REDIS_ANY_ADAPTER_HPP
#include <boost/redis/resp3/node.hpp>
#include <boost/redis/adapter/adapt.hpp> #include <boost/redis/adapter/adapt.hpp>
#include <boost/redis/resp3/node.hpp>
#include <boost/system/error_code.hpp> #include <boost/system/error_code.hpp>
#include <cstddef> #include <cstddef>
#include <functional> #include <functional>
#include <string_view> #include <string_view>
@@ -33,26 +34,26 @@ namespace boost::redis {
*/ */
class any_adapter { class any_adapter {
public: public:
using fn_type = std::function<void(std::size_t, resp3::node_view const&, system::error_code&)>; using fn_type = std::function<void(std::size_t, resp3::node_view const&, system::error_code&)>;
struct impl_t { struct impl_t {
fn_type adapt_fn; fn_type adapt_fn;
std::size_t supported_response_size; std::size_t supported_response_size;
} impl_; } impl_;
template <class T> template <class T>
static auto create_impl(T& resp) -> impl_t static auto create_impl(T& resp) -> impl_t
{ {
using namespace boost::redis::adapter; using namespace boost::redis::adapter;
auto adapter = boost_redis_adapt(resp); auto adapter = boost_redis_adapt(resp);
std::size_t size = adapter.get_supported_response_size(); std::size_t size = adapter.get_supported_response_size();
return { std::move(adapter), size }; return {std::move(adapter), size};
} }
template <class Executor> template <class Executor>
friend class basic_connection; friend class basic_connection;
/** /**
* @brief Constructor. * @brief Constructor.
* *
* Creates a type-erased response adapter from `resp` by calling * Creates a type-erased response adapter from `resp` by calling
@@ -62,10 +63,12 @@ public:
* This object stores a reference to `resp`, which must be kept alive * This object stores a reference to `resp`, which must be kept alive
* while `*this` is being used. * while `*this` is being used.
*/ */
template <class T, class = std::enable_if_t<!std::is_same_v<T, any_adapter>>> template <class T, class = std::enable_if_t<!std::is_same_v<T, any_adapter>>>
explicit any_adapter(T& resp) : impl_(create_impl(resp)) {} explicit any_adapter(T& resp)
: impl_(create_impl(resp))
{ }
}; };
} } // namespace boost::redis
#endif #endif

View File

@@ -7,27 +7,28 @@
#ifndef BOOST_REDIS_ADAPTER_ADAPTERS_HPP #ifndef BOOST_REDIS_ADAPTER_ADAPTERS_HPP
#define BOOST_REDIS_ADAPTER_ADAPTERS_HPP #define BOOST_REDIS_ADAPTER_ADAPTERS_HPP
#include <boost/redis/error.hpp>
#include <boost/redis/resp3/type.hpp>
#include <boost/redis/resp3/serialization.hpp>
#include <boost/redis/resp3/node.hpp>
#include <boost/redis/adapter/result.hpp> #include <boost/redis/adapter/result.hpp>
#include <boost/redis/error.hpp>
#include <boost/redis/resp3/node.hpp>
#include <boost/redis/resp3/serialization.hpp>
#include <boost/redis/resp3/type.hpp>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <set>
#include <optional>
#include <type_traits>
#include <unordered_set>
#include <forward_list>
#include <system_error>
#include <map>
#include <unordered_map>
#include <list>
#include <deque>
#include <vector>
#include <array> #include <array>
#include <string_view>
#include <charconv> #include <charconv>
#include <deque>
#include <forward_list>
#include <list>
#include <map>
#include <optional>
#include <set>
#include <string_view>
#include <system_error>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// See https://stackoverflow.com/a/31658120/1077832 // See https://stackoverflow.com/a/31658120/1077832
#ifdef _LIBCPP_VERSION #ifdef _LIBCPP_VERSION
@@ -35,60 +36,46 @@
#include <cstdlib> #include <cstdlib>
#endif #endif
namespace boost::redis::adapter::detail namespace boost::redis::adapter::detail {
{
// Exclude bools, char and charXY_t types // Exclude bools, char and charXY_t types
template <class T> struct is_integral_number : std::is_integral<T> {}; template <class T> struct is_integral_number : std::is_integral<T> { };
template <> struct is_integral_number<bool> : std::false_type {}; template <> struct is_integral_number<bool> : std::false_type { };
template <> struct is_integral_number<char> : std::false_type {}; template <> struct is_integral_number<char> : std::false_type { };
template <> struct is_integral_number<char16_t> : std::false_type {}; template <> struct is_integral_number<char16_t> : std::false_type { };
template <> struct is_integral_number<char32_t> : std::false_type {}; template <> struct is_integral_number<char32_t> : std::false_type { };
template <> struct is_integral_number<wchar_t> : std::false_type {}; template <> struct is_integral_number<wchar_t> : std::false_type { };
#ifdef __cpp_char8_t #ifdef __cpp_char8_t
template <> struct is_integral_number<char8_t> : std::false_type {}; template <> struct is_integral_number<char8_t> : std::false_type { };
#endif #endif
template<class T, bool = is_integral_number<T>::value> template <class T, bool = is_integral_number<T>::value>
struct converter; struct converter;
template<class T> template <class T>
struct converter<T, true> { struct converter<T, true> {
template <class String> template <class String>
static void static void apply(T& i, resp3::basic_node<String> const& node, system::error_code& ec)
apply(
T& i,
resp3::basic_node<String> const& node,
system::error_code& ec)
{ {
auto const res = auto const res = std::from_chars(node.value.data(), node.value.data() + node.value.size(), i);
std::from_chars(node.value.data(), node.value.data() + node.value.size(), i);
if (res.ec != std::errc()) if (res.ec != std::errc())
ec = redis::error::not_a_number; ec = redis::error::not_a_number;
} }
}; };
template<> template <>
struct converter<bool, false> { struct converter<bool, false> {
template <class String> template <class String>
static void static void apply(bool& t, resp3::basic_node<String> const& node, system::error_code& ec)
apply(
bool& t,
resp3::basic_node<String> const& node,
system::error_code& ec)
{ {
t = *node.value.data() == 't'; t = *node.value.data() == 't';
} }
}; };
template<> template <>
struct converter<double, false> { struct converter<double, false> {
template <class String> template <class String>
static void static void apply(double& d, resp3::basic_node<String> const& node, system::error_code& ec)
apply(
double& d,
resp3::basic_node<String> const& node,
system::error_code& ec)
{ {
#ifdef _LIBCPP_VERSION #ifdef _LIBCPP_VERSION
// The string in node.value is not null terminated and we also // The string in node.value is not null terminated and we also
@@ -103,15 +90,14 @@ struct converter<double, false> {
auto const res = std::from_chars(node.value.data(), node.value.data() + node.value.size(), d); auto const res = std::from_chars(node.value.data(), node.value.data() + node.value.size(), d);
if (res.ec != std::errc()) if (res.ec != std::errc())
ec = redis::error::not_a_double; ec = redis::error::not_a_double;
#endif // _LIBCPP_VERSION #endif // _LIBCPP_VERSION
} }
}; };
template <class CharT, class Traits, class Allocator> template <class CharT, class Traits, class Allocator>
struct converter<std::basic_string<CharT, Traits, Allocator>, false> { struct converter<std::basic_string<CharT, Traits, Allocator>, false> {
template <class String> template <class String>
static void static void apply(
apply(
std::basic_string<CharT, Traits, Allocator>& s, std::basic_string<CharT, Traits, Allocator>& s,
resp3::basic_node<String> const& node, resp3::basic_node<String> const& node,
system::error_code&) system::error_code&)
@@ -123,11 +109,7 @@ struct converter<std::basic_string<CharT, Traits, Allocator>, false> {
template <class T> template <class T>
struct from_bulk_impl { struct from_bulk_impl {
template <class String> template <class String>
static void static void apply(T& t, resp3::basic_node<String> const& node, system::error_code& ec)
apply(
T& t,
resp3::basic_node<String> const& node,
system::error_code& ec)
{ {
converter<T>::apply(t, node, ec); converter<T>::apply(t, node, ec);
} }
@@ -136,8 +118,7 @@ struct from_bulk_impl {
template <class T> template <class T>
struct from_bulk_impl<std::optional<T>> { struct from_bulk_impl<std::optional<T>> {
template <class String> template <class String>
static void static void apply(
apply(
std::optional<T>& op, std::optional<T>& op,
resp3::basic_node<String> const& node, resp3::basic_node<String> const& node,
system::error_code& ec) system::error_code& ec)
@@ -150,11 +131,7 @@ struct from_bulk_impl<std::optional<T>> {
}; };
template <class T, class String> template <class T, class String>
void void boost_redis_from_bulk(T& t, resp3::basic_node<String> const& node, system::error_code& ec)
boost_redis_from_bulk(
T& t,
resp3::basic_node<String> const& node,
system::error_code& ec)
{ {
from_bulk_impl<T>::apply(t, node, ec); from_bulk_impl<T>::apply(t, node, ec);
} }
@@ -167,7 +144,9 @@ private:
Result* result_; Result* result_;
public: public:
explicit general_aggregate(Result* c = nullptr): result_(c) {} explicit general_aggregate(Result* c = nullptr)
: result_(c)
{ }
template <class String> template <class String>
void operator()(resp3::basic_node<String> const& nd, system::error_code&) void operator()(resp3::basic_node<String> const& nd, system::error_code&)
{ {
@@ -175,10 +154,18 @@ public:
switch (nd.data_type) { switch (nd.data_type) {
case resp3::type::blob_error: case resp3::type::blob_error:
case resp3::type::simple_error: case resp3::type::simple_error:
*result_ = error{nd.data_type, std::string{std::cbegin(nd.value), std::cend(nd.value)}}; *result_ = error{
nd.data_type,
std::string{std::cbegin(nd.value), std::cend(nd.value)}
};
break; break;
default: default:
result_->value().push_back({nd.data_type, nd.aggregate_size, nd.depth, std::string{std::cbegin(nd.value), std::cend(nd.value)}}); result_->value().push_back({
nd.data_type,
nd.aggregate_size,
nd.depth,
std::string{std::cbegin(nd.value), std::cend(nd.value)}
});
} }
} }
}; };
@@ -189,7 +176,9 @@ private:
Node* result_; Node* result_;
public: public:
explicit general_simple(Node* t = nullptr) : result_(t) {} explicit general_simple(Node* t = nullptr)
: result_(t)
{ }
template <class String> template <class String>
void operator()(resp3::basic_node<String> const& nd, system::error_code&) void operator()(resp3::basic_node<String> const& nd, system::error_code&)
@@ -198,7 +187,10 @@ public:
switch (nd.data_type) { switch (nd.data_type) {
case resp3::type::blob_error: case resp3::type::blob_error:
case resp3::type::simple_error: case resp3::type::simple_error:
*result_ = error{nd.data_type, std::string{std::cbegin(nd.value), std::cend(nd.value)}}; *result_ = error{
nd.data_type,
std::string{std::cbegin(nd.value), std::cend(nd.value)}
};
break; break;
default: default:
result_->value().data_type = nd.data_type; result_->value().data_type = nd.data_type;
@@ -212,7 +204,7 @@ public:
template <class Result> template <class Result>
class simple_impl { class simple_impl {
public: public:
void on_value_available(Result&) {} void on_value_available(Result&) { }
template <class String> template <class String>
void operator()(Result& result, resp3::basic_node<String> const& node, system::error_code& ec) void operator()(Result& result, resp3::basic_node<String> const& node, system::error_code& ec)
@@ -232,8 +224,7 @@ private:
typename Result::iterator hint_; typename Result::iterator hint_;
public: public:
void on_value_available(Result& result) void on_value_available(Result& result) { hint_ = std::end(result); }
{ hint_ = std::end(result); }
template <class String> template <class String>
void operator()(Result& result, resp3::basic_node<String> const& nd, system::error_code& ec) void operator()(Result& result, resp3::basic_node<String> const& nd, system::error_code& ec)
@@ -247,8 +238,8 @@ public:
BOOST_ASSERT(nd.aggregate_size == 1); BOOST_ASSERT(nd.aggregate_size == 1);
if (nd.depth < 1) { if (nd.depth < 1) {
ec = redis::error::expects_resp3_set; ec = redis::error::expects_resp3_set;
return; return;
} }
typename Result::key_type obj; typename Result::key_type obj;
@@ -264,23 +255,22 @@ private:
bool on_key_ = true; bool on_key_ = true;
public: public:
void on_value_available(Result& result) void on_value_available(Result& result) { current_ = std::end(result); }
{ current_ = std::end(result); }
template <class String> template <class String>
void operator()(Result& result, resp3::basic_node<String> const& nd, system::error_code& ec) void operator()(Result& result, resp3::basic_node<String> const& nd, system::error_code& ec)
{ {
if (is_aggregate(nd.data_type)) { if (is_aggregate(nd.data_type)) {
if (element_multiplicity(nd.data_type) != 2) if (element_multiplicity(nd.data_type) != 2)
ec = redis::error::expects_resp3_map; ec = redis::error::expects_resp3_map;
return; return;
} }
BOOST_ASSERT(nd.aggregate_size == 1); BOOST_ASSERT(nd.aggregate_size == 1);
if (nd.depth < 1) { if (nd.depth < 1) {
ec = redis::error::expects_resp3_map; ec = redis::error::expects_resp3_map;
return; return;
} }
if (on_key_) { if (on_key_) {
@@ -300,7 +290,7 @@ public:
template <class Result> template <class Result>
class vector_impl { class vector_impl {
public: public:
void on_value_available(Result& ) { } void on_value_available(Result&) { }
template <class String> template <class String>
void operator()(Result& result, resp3::basic_node<String> const& nd, system::error_code& ec) void operator()(Result& result, resp3::basic_node<String> const& nd, system::error_code& ec)
@@ -321,13 +311,13 @@ private:
int i_ = -1; int i_ = -1;
public: public:
void on_value_available(Result& ) { } void on_value_available(Result&) { }
template <class String> template <class String>
void operator()(Result& result, resp3::basic_node<String> const& nd, system::error_code& ec) void operator()(Result& result, resp3::basic_node<String> const& nd, system::error_code& ec)
{ {
if (is_aggregate(nd.data_type)) { if (is_aggregate(nd.data_type)) {
if (i_ != -1) { if (i_ != -1) {
ec = redis::error::nested_aggregate_not_supported; ec = redis::error::nested_aggregate_not_supported;
return; return;
} }
@@ -352,21 +342,20 @@ public:
template <class Result> template <class Result>
struct list_impl { struct list_impl {
void on_value_available(Result&) { }
void on_value_available(Result& ) { }
template <class String> template <class String>
void operator()(Result& result, resp3::basic_node<String> const& nd, system::error_code& ec) void operator()(Result& result, resp3::basic_node<String> const& nd, system::error_code& ec)
{ {
if (!is_aggregate(nd.data_type)) { if (!is_aggregate(nd.data_type)) {
BOOST_ASSERT(nd.aggregate_size == 1); BOOST_ASSERT(nd.aggregate_size == 1);
if (nd.depth < 1) { if (nd.depth < 1) {
ec = redis::error::expects_resp3_aggregate; ec = redis::error::expects_resp3_aggregate;
return; return;
} }
result.push_back({}); result.push_back({});
boost_redis_from_bulk(result.back(), nd, ec); boost_redis_from_bulk(result.back(), nd, ec);
} }
} }
}; };
@@ -374,43 +363,69 @@ struct list_impl {
//--------------------------------------------------- //---------------------------------------------------
template <class T> template <class T>
struct impl_map { using type = simple_impl<T>; }; struct impl_map {
using type = simple_impl<T>;
};
template <class Key, class Compare, class Allocator> template <class Key, class Compare, class Allocator>
struct impl_map<std::set<Key, Compare, Allocator>> { using type = set_impl<std::set<Key, Compare, Allocator>>; }; struct impl_map<std::set<Key, Compare, Allocator>> {
using type = set_impl<std::set<Key, Compare, Allocator>>;
};
template <class Key, class Compare, class Allocator> template <class Key, class Compare, class Allocator>
struct impl_map<std::multiset<Key, Compare, Allocator>> { using type = set_impl<std::multiset<Key, Compare, Allocator>>; }; struct impl_map<std::multiset<Key, Compare, Allocator>> {
using type = set_impl<std::multiset<Key, Compare, Allocator>>;
};
template <class Key, class Hash, class KeyEqual, class Allocator> template <class Key, class Hash, class KeyEqual, class Allocator>
struct impl_map<std::unordered_set<Key, Hash, KeyEqual, Allocator>> { using type = set_impl<std::unordered_set<Key, Hash, KeyEqual, Allocator>>; }; struct impl_map<std::unordered_set<Key, Hash, KeyEqual, Allocator>> {
using type = set_impl<std::unordered_set<Key, Hash, KeyEqual, Allocator>>;
};
template <class Key, class Hash, class KeyEqual, class Allocator> template <class Key, class Hash, class KeyEqual, class Allocator>
struct impl_map<std::unordered_multiset<Key, Hash, KeyEqual, Allocator>> { using type = set_impl<std::unordered_multiset<Key, Hash, KeyEqual, Allocator>>; }; struct impl_map<std::unordered_multiset<Key, Hash, KeyEqual, Allocator>> {
using type = set_impl<std::unordered_multiset<Key, Hash, KeyEqual, Allocator>>;
};
template <class Key, class T, class Compare, class Allocator> template <class Key, class T, class Compare, class Allocator>
struct impl_map<std::map<Key, T, Compare, Allocator>> { using type = map_impl<std::map<Key, T, Compare, Allocator>>; }; struct impl_map<std::map<Key, T, Compare, Allocator>> {
using type = map_impl<std::map<Key, T, Compare, Allocator>>;
};
template <class Key, class T, class Compare, class Allocator> template <class Key, class T, class Compare, class Allocator>
struct impl_map<std::multimap<Key, T, Compare, Allocator>> { using type = map_impl<std::multimap<Key, T, Compare, Allocator>>; }; struct impl_map<std::multimap<Key, T, Compare, Allocator>> {
using type = map_impl<std::multimap<Key, T, Compare, Allocator>>;
};
template <class Key, class Hash, class KeyEqual, class Allocator> template <class Key, class Hash, class KeyEqual, class Allocator>
struct impl_map<std::unordered_map<Key, Hash, KeyEqual, Allocator>> { using type = map_impl<std::unordered_map<Key, Hash, KeyEqual, Allocator>>; }; struct impl_map<std::unordered_map<Key, Hash, KeyEqual, Allocator>> {
using type = map_impl<std::unordered_map<Key, Hash, KeyEqual, Allocator>>;
};
template <class Key, class Hash, class KeyEqual, class Allocator> template <class Key, class Hash, class KeyEqual, class Allocator>
struct impl_map<std::unordered_multimap<Key, Hash, KeyEqual, Allocator>> { using type = map_impl<std::unordered_multimap<Key, Hash, KeyEqual, Allocator>>; }; struct impl_map<std::unordered_multimap<Key, Hash, KeyEqual, Allocator>> {
using type = map_impl<std::unordered_multimap<Key, Hash, KeyEqual, Allocator>>;
};
template <class T, class Allocator> template <class T, class Allocator>
struct impl_map<std::vector<T, Allocator>> { using type = vector_impl<std::vector<T, Allocator>>; }; struct impl_map<std::vector<T, Allocator>> {
using type = vector_impl<std::vector<T, Allocator>>;
};
template <class T, std::size_t N> template <class T, std::size_t N>
struct impl_map<std::array<T, N>> { using type = array_impl<std::array<T, N>>; }; struct impl_map<std::array<T, N>> {
using type = array_impl<std::array<T, N>>;
};
template <class T, class Allocator> template <class T, class Allocator>
struct impl_map<std::list<T, Allocator>> { using type = list_impl<std::list<T, Allocator>>; }; struct impl_map<std::list<T, Allocator>> {
using type = list_impl<std::list<T, Allocator>>;
};
template <class T, class Allocator> template <class T, class Allocator>
struct impl_map<std::deque<T, Allocator>> { using type = list_impl<std::deque<T, Allocator>>; }; struct impl_map<std::deque<T, Allocator>> {
using type = list_impl<std::deque<T, Allocator>>;
};
//--------------------------------------------------- //---------------------------------------------------
@@ -421,6 +436,7 @@ template <class T>
class wrapper<result<T>> { class wrapper<result<T>> {
public: public:
using response_type = result<T>; using response_type = result<T>;
private: private:
response_type* result_; response_type* result_;
typename impl_map<T>::type impl_; typename impl_map<T>::type impl_;
@@ -433,15 +449,18 @@ private:
case resp3::type::null: case resp3::type::null:
case resp3::type::simple_error: case resp3::type::simple_error:
case resp3::type::blob_error: case resp3::type::blob_error:
*result_ = error{nd.data_type, {std::cbegin(nd.value), std::cend(nd.value)}}; *result_ = error{
nd.data_type,
{std::cbegin(nd.value), std::cend(nd.value)}
};
return true; return true;
default: default: return false;
return false;
} }
} }
public: public:
explicit wrapper(response_type* t = nullptr) : result_(t) explicit wrapper(response_type* t = nullptr)
: result_(t)
{ {
if (result_) { if (result_) {
result_->value() = T{}; result_->value() = T{};
@@ -481,21 +500,22 @@ private:
switch (nd.data_type) { switch (nd.data_type) {
case resp3::type::blob_error: case resp3::type::blob_error:
case resp3::type::simple_error: case resp3::type::simple_error:
*result_ = error{nd.data_type, {std::cbegin(nd.value), std::cend(nd.value)}}; *result_ = error{
nd.data_type,
{std::cbegin(nd.value), std::cend(nd.value)}
};
return true; return true;
default: default: return false;
return false;
} }
} }
public: public:
explicit wrapper(response_type* o = nullptr) : result_(o) {} explicit wrapper(response_type* o = nullptr)
: result_(o)
{ }
template <class String> template <class String>
void void operator()(resp3::basic_node<String> const& nd, system::error_code& ec)
operator()(
resp3::basic_node<String> const& nd,
system::error_code& ec)
{ {
BOOST_ASSERT_MSG(!!result_, "Unexpected null pointer"); BOOST_ASSERT_MSG(!!result_, "Unexpected null pointer");
@@ -509,14 +529,14 @@ public:
return; return;
if (!result_->value().has_value()) { if (!result_->value().has_value()) {
result_->value() = T{}; result_->value() = T{};
impl_.on_value_available(result_->value().value()); impl_.on_value_available(result_->value().value());
} }
impl_(result_->value().value(), nd, ec); impl_(result_->value().value(), nd, ec);
} }
}; };
} // boost::redis::adapter::detail } // namespace boost::redis::adapter::detail
#endif // BOOST_REDIS_ADAPTER_ADAPTERS_HPP #endif // BOOST_REDIS_ADAPTER_ADAPTERS_HPP

View File

@@ -7,19 +7,19 @@
#ifndef BOOST_REDIS_ADAPTER_DETAIL_RESPONSE_TRAITS_HPP #ifndef BOOST_REDIS_ADAPTER_DETAIL_RESPONSE_TRAITS_HPP
#define BOOST_REDIS_ADAPTER_DETAIL_RESPONSE_TRAITS_HPP #define BOOST_REDIS_ADAPTER_DETAIL_RESPONSE_TRAITS_HPP
#include <boost/redis/adapter/detail/result_traits.hpp>
#include <boost/redis/resp3/node.hpp> #include <boost/redis/resp3/node.hpp>
#include <boost/redis/response.hpp> #include <boost/redis/response.hpp>
#include <boost/redis/adapter/detail/result_traits.hpp>
#include <boost/mp11.hpp> #include <boost/mp11.hpp>
#include <boost/system.hpp> #include <boost/system.hpp>
#include <tuple>
#include <limits> #include <limits>
#include <string_view> #include <string_view>
#include <tuple>
#include <variant> #include <variant>
namespace boost::redis::adapter::detail namespace boost::redis::adapter::detail {
{
class ignore_adapter { class ignore_adapter {
public: public:
@@ -28,15 +28,17 @@ public:
{ {
switch (nd.data_type) { switch (nd.data_type) {
case resp3::type::simple_error: ec = redis::error::resp3_simple_error; break; 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::blob_error: ec = redis::error::resp3_blob_error; break;
case resp3::type::null: ec = redis::error::resp3_null; break; case resp3::type::null: ec = redis::error::resp3_null; break;
default:; default: ;
} }
} }
[[nodiscard]] [[nodiscard]]
auto get_supported_response_size() const noexcept auto get_supported_response_size() const noexcept
{ return static_cast<std::size_t>(-1);} {
return static_cast<std::size_t>(-1);
}
}; };
template <class Response> template <class Response>
@@ -50,14 +52,13 @@ private:
adapters_array_type adapters_; adapters_array_type adapters_;
public: public:
explicit static_adapter(Response& r) explicit static_adapter(Response& r) { assigner<size - 1>::assign(adapters_, r); }
{
assigner<size - 1>::assign(adapters_, r);
}
[[nodiscard]] [[nodiscard]]
auto get_supported_response_size() const noexcept auto get_supported_response_size() const noexcept
{ return size;} {
return size;
}
template <class String> template <class String>
void operator()(std::size_t i, resp3::basic_node<String> const& nd, system::error_code& ec) void operator()(std::size_t i, resp3::basic_node<String> const& nd, system::error_code& ec)
@@ -65,7 +66,11 @@ public:
using std::visit; using std::visit;
// I am usure whether this should be an error or an assertion. // I am usure whether this should be an error or an assertion.
BOOST_ASSERT(i < adapters_.size()); BOOST_ASSERT(i < adapters_.size());
visit([&](auto& arg){arg(nd, ec);}, adapters_.at(i)); visit(
[&](auto& arg) {
arg(nd, ec);
},
adapters_.at(i));
} }
}; };
@@ -81,9 +86,10 @@ public:
{ } { }
[[nodiscard]] [[nodiscard]]
auto auto get_supported_response_size() const noexcept
get_supported_response_size() const noexcept {
{ return static_cast<std::size_t>(-1);} return static_cast<std::size_t>(-1);
}
template <class String> template <class String>
void operator()(std::size_t, resp3::basic_node<String> const& nd, system::error_code& ec) void operator()(std::size_t, resp3::basic_node<String> const& nd, system::error_code& ec)
@@ -100,8 +106,7 @@ struct response_traits<ignore_t> {
using response_type = ignore_t; using response_type = ignore_t;
using adapter_type = detail::ignore_adapter; using adapter_type = detail::ignore_adapter;
static auto adapt(response_type&) noexcept static auto adapt(response_type&) noexcept { return detail::ignore_adapter{}; }
{ return detail::ignore_adapter{}; }
}; };
template <> template <>
@@ -109,8 +114,7 @@ struct response_traits<result<ignore_t>> {
using response_type = result<ignore_t>; using response_type = result<ignore_t>;
using adapter_type = detail::ignore_adapter; using adapter_type = detail::ignore_adapter;
static auto adapt(response_type&) noexcept static auto adapt(response_type&) noexcept { return detail::ignore_adapter{}; }
{ return detail::ignore_adapter{}; }
}; };
template <class String, class Allocator> template <class String, class Allocator>
@@ -118,31 +122,35 @@ struct response_traits<result<std::vector<resp3::basic_node<String>, Allocator>>
using response_type = result<std::vector<resp3::basic_node<String>, Allocator>>; using response_type = result<std::vector<resp3::basic_node<String>, Allocator>>;
using adapter_type = vector_adapter<response_type>; using adapter_type = vector_adapter<response_type>;
static auto adapt(response_type& v) noexcept static auto adapt(response_type& v) noexcept { return adapter_type{v}; }
{ return adapter_type{v}; }
}; };
template <class ...Ts> template <class... Ts>
struct response_traits<response<Ts...>> { struct response_traits<response<Ts...>> {
using response_type = response<Ts...>; using response_type = response<Ts...>;
using adapter_type = static_adapter<response_type>; using adapter_type = static_adapter<response_type>;
static auto adapt(response_type& r) noexcept static auto adapt(response_type& r) noexcept { return adapter_type{r}; }
{ return adapter_type{r}; }
}; };
template <class Adapter> template <class Adapter>
class wrapper { class wrapper {
public: public:
explicit wrapper(Adapter adapter) : adapter_{adapter} {} explicit wrapper(Adapter adapter)
: adapter_{adapter}
{ }
template <class String> template <class String>
void operator()(resp3::basic_node<String> const& nd, system::error_code& ec) void operator()(resp3::basic_node<String> const& nd, system::error_code& ec)
{ return adapter_(0, nd, ec); } {
return adapter_(0, nd, ec);
}
[[nodiscard]] [[nodiscard]]
auto get_supported_response_size() const noexcept auto get_supported_response_size() const noexcept
{ return adapter_.get_supported_response_size();} {
return adapter_.get_supported_response_size();
}
private: private:
Adapter adapter_; Adapter adapter_;
@@ -154,6 +162,6 @@ auto make_adapter_wrapper(Adapter adapter)
return wrapper{adapter}; return wrapper{adapter};
} }
} // boost::redis::adapter::detail } // namespace boost::redis::adapter::detail
#endif // BOOST_REDIS_ADAPTER_DETAIL_RESPONSE_TRAITS_HPP #endif // BOOST_REDIS_ADAPTER_DETAIL_RESPONSE_TRAITS_HPP

View File

@@ -7,21 +7,21 @@
#ifndef BOOST_REDIS_ADAPTER_RESPONSE_TRAITS_HPP #ifndef BOOST_REDIS_ADAPTER_RESPONSE_TRAITS_HPP
#define 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/detail/adapters.hpp>
#include <boost/redis/adapter/result.hpp>
#include <boost/redis/adapter/ignore.hpp> #include <boost/redis/adapter/ignore.hpp>
#include <boost/redis/adapter/result.hpp>
#include <boost/redis/error.hpp>
#include <boost/redis/ignore.hpp>
#include <boost/redis/resp3/type.hpp>
#include <boost/mp11.hpp> #include <boost/mp11.hpp>
#include <vector>
#include <tuple>
#include <string_view> #include <string_view>
#include <tuple>
#include <variant> #include <variant>
#include <vector>
namespace boost::redis::adapter::detail namespace boost::redis::adapter::detail {
{
/* Traits class for response objects. /* Traits class for response objects.
* *
@@ -65,27 +65,29 @@ struct result_traits<result<std::vector<resp3::basic_node<String>, Allocator>>>
template <class T> template <class T>
using adapter_t = typename result_traits<std::decay_t<T>>::adapter_type; using adapter_t = typename result_traits<std::decay_t<T>>::adapter_type;
template<class T> template <class T>
auto internal_adapt(T& t) noexcept auto internal_adapt(T& t) noexcept
{ return result_traits<std::decay_t<T>>::adapt(t); } {
return result_traits<std::decay_t<T>>::adapt(t);
}
template <std::size_t N> template <std::size_t N>
struct assigner { struct assigner {
template <class T1, class T2> template <class T1, class T2>
static void assign(T1& dest, T2& from) static void assign(T1& dest, T2& from)
{ {
dest[N].template emplace<N>(internal_adapt(std::get<N>(from))); dest[N].template emplace<N>(internal_adapt(std::get<N>(from)));
assigner<N - 1>::assign(dest, from); assigner<N - 1>::assign(dest, from);
} }
}; };
template <> template <>
struct assigner<0> { struct assigner<0> {
template <class T1, class T2> template <class T1, class T2>
static void assign(T1& dest, T2& from) static void assign(T1& dest, T2& from)
{ {
dest[0].template emplace<0>(internal_adapt(std::get<0>(from))); dest[0].template emplace<0>(internal_adapt(std::get<0>(from)));
} }
}; };
template <class Tuple> template <class Tuple>
@@ -94,13 +96,9 @@ class static_aggregate_adapter;
template <class Tuple> template <class Tuple>
class static_aggregate_adapter<result<Tuple>> { class static_aggregate_adapter<result<Tuple>> {
private: private:
using adapters_array_type = using adapters_array_type = std::array<
std::array< mp11::mp_rename<mp11::mp_transform<adapter_t, Tuple>, std::variant>,
mp11::mp_rename< std::tuple_size<Tuple>::value>;
mp11::mp_transform<
adapter_t, Tuple>,
std::variant>,
std::tuple_size<Tuple>::value>;
// Tuple element we are currently on. // Tuple element we are currently on.
std::size_t i_ = 0; std::size_t i_ = 0;
@@ -148,19 +146,22 @@ public:
return; return;
} }
visit([&](auto& arg){arg(elem, ec);}, adapters_[i_]); visit(
[&](auto& arg) {
arg(elem, ec);
},
adapters_[i_]);
count(elem); count(elem);
} }
}; };
template <class... Ts> template <class... Ts>
struct result_traits<result<std::tuple<Ts...>>> struct result_traits<result<std::tuple<Ts...>>> {
{
using response_type = result<std::tuple<Ts...>>; using response_type = result<std::tuple<Ts...>>;
using adapter_type = static_aggregate_adapter<response_type>; using adapter_type = static_aggregate_adapter<response_type>;
static auto adapt(response_type& r) noexcept { return adapter_type{&r}; } static auto adapt(response_type& r) noexcept { return adapter_type{&r}; }
}; };
} // boost::redis::adapter::detail } // namespace boost::redis::adapter::detail
#endif // BOOST_REDIS_ADAPTER_RESPONSE_TRAITS_HPP #endif // BOOST_REDIS_ADAPTER_RESPONSE_TRAITS_HPP

View File

@@ -7,13 +7,14 @@
#ifndef BOOST_REDIS_ADAPTER_IGNORE_HPP #ifndef BOOST_REDIS_ADAPTER_IGNORE_HPP
#define BOOST_REDIS_ADAPTER_IGNORE_HPP #define BOOST_REDIS_ADAPTER_IGNORE_HPP
#include <boost/redis/resp3/node.hpp>
#include <boost/redis/error.hpp> #include <boost/redis/error.hpp>
#include <boost/redis/resp3/node.hpp>
#include <boost/system/error_code.hpp> #include <boost/system/error_code.hpp>
#include <string> #include <string>
namespace boost::redis::adapter namespace boost::redis::adapter {
{
/** @brief An adapter that ignores responses /** @brief An adapter that ignores responses
* @ingroup high-level-api * @ingroup high-level-api
@@ -25,13 +26,13 @@ struct ignore {
{ {
switch (nd.data_type) { switch (nd.data_type) {
case resp3::type::simple_error: ec = redis::error::resp3_simple_error; break; 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::blob_error: ec = redis::error::resp3_blob_error; break;
case resp3::type::null: ec = redis::error::resp3_null; break; case resp3::type::null: ec = redis::error::resp3_null; break;
default:; default: ;
} }
} }
}; };
} // boost::redis::adapter } // namespace boost::redis::adapter
#endif // BOOST_REDIS_ADAPTER_IGNORE_HPP #endif // BOOST_REDIS_ADAPTER_IGNORE_HPP

View File

@@ -8,13 +8,14 @@
#ifndef BOOST_REDIS_ADAPTER_RESULT_HPP #ifndef BOOST_REDIS_ADAPTER_RESULT_HPP
#define BOOST_REDIS_ADAPTER_RESULT_HPP #define BOOST_REDIS_ADAPTER_RESULT_HPP
#include <boost/redis/resp3/type.hpp>
#include <boost/redis/error.hpp> #include <boost/redis/error.hpp>
#include <boost/redis/resp3/type.hpp>
#include <boost/system/result.hpp> #include <boost/system/result.hpp>
#include <string> #include <string>
namespace boost::redis::adapter namespace boost::redis::adapter {
{
/** @brief Stores any resp3 error /** @brief Stores any resp3 error
* @ingroup high-level-api * @ingroup high-level-api
@@ -44,10 +45,7 @@ inline bool operator==(error const& a, error const& b)
* @param a Left hand side error object. * @param a Left hand side error object.
* @param b Right hand side error object. * @param b Right hand side error object.
*/ */
inline bool operator!=(error const& a, error const& b) inline bool operator!=(error const& a, error const& b) { return !(a == b); }
{
return !(a == b);
}
/** @brief Stores response to individual Redis commands /** @brief Stores response to individual Redis commands
* @ingroup high-level-api * @ingroup high-level-api
@@ -55,27 +53,19 @@ inline bool operator!=(error const& a, error const& b)
template <class Value> template <class Value>
using result = system::result<Value, error>; using result = system::result<Value, error>;
BOOST_NORETURN inline void BOOST_NORETURN inline void throw_exception_from_error(error const& e, boost::source_location const&)
throw_exception_from_error(error const & e, boost::source_location const &)
{ {
system::error_code ec; system::error_code ec;
switch (e.data_type) { switch (e.data_type) {
case resp3::type::simple_error: case resp3::type::simple_error: ec = redis::error::resp3_simple_error; break;
ec = redis::error::resp3_simple_error; case resp3::type::blob_error: ec = redis::error::resp3_blob_error; break;
break; case resp3::type::null: ec = redis::error::resp3_null; break;
case resp3::type::blob_error: default: BOOST_ASSERT_MSG(false, "Unexpected data type.");
ec = redis::error::resp3_blob_error;
break;
case resp3::type::null:
ec = redis::error::resp3_null;
break;
default:
BOOST_ASSERT_MSG(false, "Unexpected data type.");
} }
throw system::system_error(ec, e.diagnostic); throw system::system_error(ec, e.diagnostic);
} }
} // boost::redis::adapter } // namespace boost::redis::adapter
#endif // BOOST_REDIS_ADAPTER_RESULT_HPP #endif // BOOST_REDIS_ADAPTER_RESULT_HPP

View File

@@ -7,13 +7,12 @@
#ifndef BOOST_REDIS_CONFIG_HPP #ifndef BOOST_REDIS_CONFIG_HPP
#define BOOST_REDIS_CONFIG_HPP #define BOOST_REDIS_CONFIG_HPP
#include <string>
#include <chrono> #include <chrono>
#include <optional>
#include <limits> #include <limits>
#include <optional>
#include <string>
namespace boost::redis namespace boost::redis {
{
/** @brief Address of a Redis server /** @brief Address of a Redis server
* @ingroup high-level-api * @ingroup high-level-api
@@ -88,6 +87,6 @@ struct config {
std::size_t max_read_size = (std::numeric_limits<std::size_t>::max)(); std::size_t max_read_size = (std::numeric_limits<std::size_t>::max)();
}; };
} // boost::redis } // namespace boost::redis
#endif // BOOST_REDIS_CONFIG_HPP #endif // BOOST_REDIS_CONFIG_HPP

View File

@@ -42,7 +42,6 @@
#include <boost/asio/steady_timer.hpp> #include <boost/asio/steady_timer.hpp>
#include <boost/asio/write.hpp> #include <boost/asio/write.hpp>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/core/ignore_unused.hpp> #include <boost/core/ignore_unused.hpp>
#include <array> #include <array>
@@ -53,8 +52,7 @@
#include <memory> #include <memory>
namespace boost::redis { namespace boost::redis {
namespace detail namespace detail {
{
template <class AsyncReadStream, class DynamicBuffer> template <class AsyncReadStream, class DynamicBuffer>
class append_some_op { class append_some_op {
@@ -67,17 +65,15 @@ private:
public: public:
append_some_op(AsyncReadStream& stream, DynamicBuffer buf, std::size_t size) append_some_op(AsyncReadStream& stream, DynamicBuffer buf, std::size_t size)
: stream_ {stream} : stream_{stream}
, buf_ {std::move(buf)} , buf_{std::move(buf)}
, size_{size} , size_{size}
{ } { }
template <class Self> template <class Self>
void operator()( Self& self void operator()(Self& self, system::error_code ec = {}, std::size_t n = 0)
, system::error_code ec = {}
, std::size_t n = 0)
{ {
BOOST_ASIO_CORO_REENTER (coro_) BOOST_ASIO_CORO_REENTER(coro_)
{ {
tmp_ = buf_.size(); tmp_ = buf_.size();
buf_.grow(size_); buf_.grow(size_);
@@ -96,22 +92,22 @@ public:
}; };
template <class AsyncReadStream, class DynamicBuffer, class CompletionToken> template <class AsyncReadStream, class DynamicBuffer, class CompletionToken>
auto auto async_append_some(
async_append_some(
AsyncReadStream& stream, AsyncReadStream& stream,
DynamicBuffer buffer, DynamicBuffer buffer,
std::size_t size, std::size_t size,
CompletionToken&& token) CompletionToken&& token)
{ {
return asio::async_compose return asio::async_compose<CompletionToken, void(system::error_code, std::size_t)>(
< CompletionToken append_some_op<AsyncReadStream, DynamicBuffer>{stream, buffer, size},
, void(system::error_code, std::size_t) token,
>(append_some_op<AsyncReadStream, DynamicBuffer> {stream, buffer, size}, token, stream); stream);
} }
template <class Executor> template <class Executor>
using exec_notifier_type = using exec_notifier_type = asio::experimental::channel<
asio::experimental::channel<Executor, void(system::error_code, std::size_t)>; Executor,
void(system::error_code, std::size_t)>;
template <class Conn> template <class Conn>
struct exec_op { struct exec_op {
@@ -124,9 +120,9 @@ struct exec_op {
asio::coroutine coro_{}; asio::coroutine coro_{};
template <class Self> template <class Self>
void operator()(Self& self , system::error_code = {}, std::size_t = 0) void operator()(Self& self, system::error_code = {}, std::size_t = 0)
{ {
BOOST_ASIO_CORO_REENTER (coro_) BOOST_ASIO_CORO_REENTER(coro_)
{ {
// Check whether the user wants to wait for the connection to // Check whether the user wants to wait for the connection to
// be stablished. // be stablished.
@@ -188,21 +184,19 @@ struct writer_op {
asio::coroutine coro{}; asio::coroutine coro{};
template <class Self> template <class Self>
void operator()( Self& self void operator()(Self& self, system::error_code ec = {}, std::size_t n = 0)
, system::error_code ec = {}
, std::size_t n = 0)
{ {
ignore_unused(n); ignore_unused(n);
BOOST_ASIO_CORO_REENTER (coro) for (;;) BOOST_ASIO_CORO_REENTER(coro) for (;;)
{ {
while (conn_->mpx_.prepare_write() != 0) { while (conn_->mpx_.prepare_write() != 0) {
if (conn_->use_ssl()) { if (conn_->use_ssl()) {
BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD
asio::async_write( asio::async_write(
conn_->next_layer(), conn_->next_layer(),
asio::buffer(conn_->mpx_.get_write_buffer()), asio::buffer(conn_->mpx_.get_write_buffer()),
std::move(self)); std::move(self));
} else { } else {
BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD
asio::async_write( asio::async_write(
@@ -248,7 +242,10 @@ struct writer_op {
template <class Conn, class Logger> template <class Conn, class Logger>
struct reader_op { struct reader_op {
using dyn_buffer_type = asio::dynamic_string_buffer<char, std::char_traits<char>, std::allocator<char>>; using dyn_buffer_type = asio::dynamic_string_buffer<
char,
std::char_traits<char>,
std::allocator<char>>;
// TODO: Move this to config so the user can fine tune? // TODO: Move this to config so the user can fine tune?
static constexpr std::size_t buffer_growth_hint = 4096; static constexpr std::size_t buffer_growth_hint = 4096;
@@ -259,13 +256,11 @@ struct reader_op {
asio::coroutine coro{}; asio::coroutine coro{};
template <class Self> template <class Self>
void operator()( Self& self void operator()(Self& self, system::error_code ec = {}, std::size_t n = 0)
, system::error_code ec = {}
, std::size_t n = 0)
{ {
ignore_unused(n); ignore_unused(n);
BOOST_ASIO_CORO_REENTER (coro) for (;;) BOOST_ASIO_CORO_REENTER(coro) for (;;)
{ {
// Appends some data to the buffer if necessary. // Appends some data to the buffer if necessary.
if (!res_.first.has_value() || conn_->mpx_.is_data_needed()) { if (!res_.first.has_value() || conn_->mpx_.is_data_needed()) {
@@ -331,7 +326,6 @@ struct reader_op {
self.complete(asio::error::operation_aborted); self.complete(asio::error::operation_aborted);
return; return;
} }
} }
} }
} }
@@ -350,21 +344,22 @@ public:
run_op(Conn* conn, Logger l) run_op(Conn* conn, Logger l)
: conn_{conn} : conn_{conn}
, logger_{l} , logger_{l}
{} { }
template <class Self> template <class Self>
void operator()( Self& self void operator()(
, order_t order = {} Self& self,
, system::error_code ec0 = {} order_t order = {},
, system::error_code ec1 = {} system::error_code ec0 = {},
, system::error_code ec2 = {} system::error_code ec1 = {},
, system::error_code ec3 = {} system::error_code ec2 = {},
, system::error_code ec4 = {}) system::error_code ec3 = {},
system::error_code ec4 = {})
{ {
BOOST_ASIO_CORO_REENTER (coro_) for (;;) BOOST_ASIO_CORO_REENTER(coro_) for (;;)
{ {
BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD
conn_->resv_.async_resolve(asio::prepend(std::move(self), order_t {})); conn_->resv_.async_resolve(asio::prepend(std::move(self), order_t{}));
logger_.on_resolve(ec0, conn_->resv_.results()); logger_.on_resolve(ec0, conn_->resv_.results());
@@ -377,7 +372,7 @@ public:
conn_->ctor_.async_connect( conn_->ctor_.async_connect(
conn_->next_layer().next_layer(), conn_->next_layer().next_layer(),
conn_->resv_.results(), conn_->resv_.results(),
asio::prepend(std::move(self), order_t {})); asio::prepend(std::move(self), order_t{}));
logger_.on_connect(ec0, conn_->ctor_.endpoint()); logger_.on_connect(ec0, conn_->ctor_.endpoint());
@@ -391,13 +386,8 @@ public:
conn_->next_layer().async_handshake( conn_->next_layer().async_handshake(
asio::ssl::stream_base::client, asio::ssl::stream_base::client,
asio::prepend( asio::prepend(
asio::cancel_after( asio::cancel_after(conn_->cfg_.ssl_handshake_timeout, std::move(self)),
conn_->cfg_.ssl_handshake_timeout, order_t{}));
std::move(self)
),
order_t {}
)
);
logger_.on_ssl_handshake(ec0); logger_.on_ssl_handshake(ec0);
@@ -414,14 +404,22 @@ public:
// causing an authentication problem. // causing an authentication problem.
BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD
asio::experimental::make_parallel_group( asio::experimental::make_parallel_group(
[this](auto token) { return conn_->handshaker_.async_hello(*conn_, logger_, token); }, [this](auto token) {
[this](auto token) { return conn_->health_checker_.async_ping(*conn_, logger_, token); }, return conn_->handshaker_.async_hello(*conn_, logger_, token);
[this](auto token) { return conn_->health_checker_.async_check_timeout(*conn_, logger_, token);}, },
[this](auto token) { return conn_->reader(logger_, token);}, [this](auto token) {
[this](auto token) { return conn_->writer(logger_, token);} return conn_->health_checker_.async_ping(*conn_, logger_, token);
).async_wait( },
asio::experimental::wait_for_one_error(), [this](auto token) {
std::move(self)); return conn_->health_checker_.async_check_timeout(*conn_, logger_, token);
},
[this](auto token) {
return conn_->reader(logger_, token);
},
[this](auto token) {
return conn_->writer(logger_, token);
})
.async_wait(asio::experimental::wait_for_one_error(), std::move(self));
if (order[0] == 0 && !!ec0) { if (order[0] == 0 && !!ec0) {
self.complete(ec0); self.complete(ec0);
@@ -449,7 +447,7 @@ public:
conn_->writer_timer_.expires_after(conn_->cfg_.reconnect_wait_interval); conn_->writer_timer_.expires_after(conn_->cfg_.reconnect_wait_interval);
BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD
conn_->writer_timer_.async_wait(asio::prepend(std::move(self), order_t {})); conn_->writer_timer_.async_wait(asio::prepend(std::move(self), order_t{}));
if (ec0) { if (ec0) {
self.complete(ec0); self.complete(ec0);
return; return;
@@ -465,7 +463,7 @@ public:
} }
}; };
} // boost::redis::detail } // namespace detail
/** @brief A SSL connection to the Redis server. /** @brief A SSL connection to the Redis server.
* @ingroup high-level-api * @ingroup high-level-api
@@ -489,24 +487,21 @@ public:
using executor_type = Executor; using executor_type = Executor;
/// Returns the associated executor. /// Returns the associated executor.
executor_type get_executor() noexcept executor_type get_executor() noexcept { return writer_timer_.get_executor(); }
{return writer_timer_.get_executor();}
/// Rebinds the socket type to another executor. /// Rebinds the socket type to another executor.
template <class Executor1> template <class Executor1>
struct rebind_executor struct rebind_executor {
{
/// The connection type when rebound to the specified executor. /// The connection type when rebound to the specified executor.
using other = basic_connection<Executor1>; using other = basic_connection<Executor1>;
}; };
/** @brief Constructor /** @brief Constructor
* *
* @param ex Executor on which connection operation will run. * @param ex Executor on which connection operation will run.
* @param ctx SSL context. * @param ctx SSL context.
*/ */
explicit explicit basic_connection(
basic_connection(
executor_type ex, executor_type ex,
asio::ssl::context ctx = asio::ssl::context{asio::ssl::context::tlsv12_client}) asio::ssl::context ctx = asio::ssl::context{asio::ssl::context::tlsv12_client})
: ctx_{std::move(ctx)} : ctx_{std::move(ctx)}
@@ -521,8 +516,7 @@ public:
} }
/// Constructs from a context. /// Constructs from a context.
explicit explicit basic_connection(
basic_connection(
asio::io_context& ioc, asio::io_context& ioc,
asio::ssl::context ctx = asio::ssl::context{asio::ssl::context::tlsv12_client}) asio::ssl::context ctx = asio::ssl::context{asio::ssl::context::tlsv12_client})
: basic_connection(ioc.get_executor(), std::move(ctx)) : basic_connection(ioc.get_executor(), std::move(ctx))
@@ -568,11 +562,7 @@ public:
template < template <
class Logger = logger, class Logger = logger,
class CompletionToken = asio::default_completion_token_t<executor_type>> class CompletionToken = asio::default_completion_token_t<executor_type>>
auto auto async_run(config const& cfg = {}, Logger l = Logger{}, CompletionToken&& token = {})
async_run(
config const& cfg = {},
Logger l = Logger{},
CompletionToken&& token = {})
{ {
cfg_ = cfg; cfg_ = cfg;
resv_.set_config(cfg); resv_.set_config(cfg);
@@ -581,10 +571,10 @@ public:
handshaker_.set_config(cfg); handshaker_.set_config(cfg);
l.set_prefix(cfg.log_prefix); l.set_prefix(cfg.log_prefix);
return asio::async_compose return asio::async_compose<CompletionToken, void(system::error_code)>(
< CompletionToken detail::run_op<this_type, Logger>{this, l},
, void(system::error_code) token,
>(detail::run_op<this_type, Logger>{this, l}, token, writer_timer_); writer_timer_);
} }
/** @brief Receives server side pushes asynchronously. /** @brief Receives server side pushes asynchronously.
@@ -611,7 +601,9 @@ public:
*/ */
template <class CompletionToken = asio::default_completion_token_t<executor_type>> template <class CompletionToken = asio::default_completion_token_t<executor_type>>
auto async_receive(CompletionToken&& token = {}) auto async_receive(CompletionToken&& token = {})
{ return receive_channel_.async_receive(std::forward<CompletionToken>(token)); } {
return receive_channel_.async_receive(std::forward<CompletionToken>(token));
}
/** @brief Receives server pushes synchronously without blocking. /** @brief Receives server pushes synchronously without blocking.
* *
@@ -628,8 +620,7 @@ public:
{ {
std::size_t size = 0; std::size_t size = 0;
auto f = [&](system::error_code const& ec2, std::size_t n) auto f = [&](system::error_code const& ec2, std::size_t n) {
{
ec = ec2; ec = ec2;
size = n; size = n;
}; };
@@ -669,13 +660,8 @@ public:
*/ */
template < template <
class Response = ignore_t, class Response = ignore_t,
class CompletionToken = asio::default_completion_token_t<executor_type> class CompletionToken = asio::default_completion_token_t<executor_type>>
> auto async_exec(request const& req, Response& resp = ignore, CompletionToken&& token = {})
auto
async_exec(
request const& req,
Response& resp = ignore,
CompletionToken&& token = {})
{ {
return this->async_exec(req, any_adapter(resp), std::forward<CompletionToken>(token)); return this->async_exec(req, any_adapter(resp), std::forward<CompletionToken>(token));
} }
@@ -686,26 +672,26 @@ public:
* encapsulates a reference to a response object. * encapsulates a reference to a response object.
*/ */
template <class CompletionToken = asio::default_completion_token_t<executor_type>> template <class CompletionToken = asio::default_completion_token_t<executor_type>>
auto auto async_exec(request const& req, any_adapter adapter, CompletionToken&& token = {})
async_exec(
request const& req,
any_adapter adapter,
CompletionToken&& token = {})
{ {
auto& adapter_impl = adapter.impl_; auto& adapter_impl = adapter.impl_;
BOOST_ASSERT_MSG(req.get_expected_responses() <= adapter_impl.supported_response_size, "Request and response have incompatible sizes."); BOOST_ASSERT_MSG(
req.get_expected_responses() <= adapter_impl.supported_response_size,
"Request and response have incompatible sizes.");
auto notifier = std::make_shared<detail::exec_notifier_type<executor_type>>(get_executor(), 1); auto notifier = std::make_shared<detail::exec_notifier_type<executor_type>>(
get_executor(),
1);
auto info = detail::make_elem(req, std::move(adapter_impl.adapt_fn)); auto info = detail::make_elem(req, std::move(adapter_impl.adapt_fn));
info->set_done_callback([notifier]() { info->set_done_callback([notifier]() {
notifier->try_send(std::error_code{}, 0); notifier->try_send(std::error_code{}, 0);
}); });
return asio::async_compose return asio::async_compose<CompletionToken, void(system::error_code, std::size_t)>(
< CompletionToken detail::exec_op<this_type>{this, notifier, info},
, void(system::error_code, std::size_t) token,
>(detail::exec_op<this_type>{this, notifier, info}, token, writer_timer_); writer_timer_);
} }
/** @brief Cancel operations. /** @brief Cancel operations.
@@ -722,80 +708,72 @@ public:
void cancel(operation op = operation::all) void cancel(operation op = operation::all)
{ {
switch (op) { switch (op) {
case operation::resolve: case operation::resolve: resv_.cancel(); break;
resv_.cancel(); case operation::exec: mpx_.cancel_waiting(); break;
break;
case operation::exec:
mpx_.cancel_waiting();
break;
case operation::reconnection: case operation::reconnection:
cfg_.reconnect_wait_interval = std::chrono::seconds::zero(); cfg_.reconnect_wait_interval = std::chrono::seconds::zero();
break; break;
case operation::run: case operation::run: cancel_run(); break;
cancel_run(); case operation::receive: receive_channel_.cancel(); break;
break; case operation::health_check: health_checker_.cancel(); break;
case operation::receive:
receive_channel_.cancel();
break;
case operation::health_check:
health_checker_.cancel();
break;
case operation::all: case operation::all:
resv_.cancel(); resv_.cancel();
cfg_.reconnect_wait_interval = std::chrono::seconds::zero(); cfg_.reconnect_wait_interval = std::chrono::seconds::zero();
health_checker_.cancel(); health_checker_.cancel();
cancel_run(); // run cancel_run(); // run
receive_channel_.cancel(); // receive receive_channel_.cancel(); // receive
mpx_.cancel_waiting(); // exec mpx_.cancel_waiting(); // exec
break; break;
default: /* ignore */; default: /* ignore */;
} }
} }
auto run_is_canceled() const noexcept auto run_is_canceled() const noexcept { return mpx_.get_cancel_run_state(); }
{ return mpx_.get_cancel_run_state(); }
/// Returns true if the connection was canceled. /// Returns true if the connection was canceled.
bool will_reconnect() const noexcept bool will_reconnect() const noexcept
{ return cfg_.reconnect_wait_interval != std::chrono::seconds::zero();} {
return cfg_.reconnect_wait_interval != std::chrono::seconds::zero();
}
/// Returns the ssl context. /// Returns the ssl context.
auto const& get_ssl_context() const noexcept auto const& get_ssl_context() const noexcept { return ctx_; }
{ return ctx_;}
/// Resets the underlying stream. /// Resets the underlying stream.
void reset_stream() void reset_stream()
{ stream_ = std::make_unique<next_layer_type>(writer_timer_.get_executor(), ctx_); } {
stream_ = std::make_unique<next_layer_type>(writer_timer_.get_executor(), ctx_);
}
/// Returns a reference to the next layer. /// Returns a reference to the next layer.
auto& next_layer() noexcept auto& next_layer() noexcept { return *stream_; }
{ return *stream_; }
/// Returns a const reference to the next layer. /// Returns a const reference to the next layer.
auto const& next_layer() const noexcept auto const& next_layer() const noexcept { return *stream_; }
{ return *stream_; }
/// Sets the response object of `async_receive` operations. /// Sets the response object of `async_receive` operations.
template <class Response> template <class Response>
void set_receive_response(Response& response) void set_receive_response(Response& response)
{ mpx_.set_receive_response(response); } {
mpx_.set_receive_response(response);
}
/// Returns connection usage information. /// Returns connection usage information.
usage get_usage() const noexcept usage get_usage() const noexcept { return mpx_.get_usage(); }
{ return mpx_.get_usage(); }
private: private:
using clock_type = std::chrono::steady_clock; using clock_type = std::chrono::steady_clock;
using clock_traits_type = asio::wait_traits<clock_type>; using clock_traits_type = asio::wait_traits<clock_type>;
using timer_type = asio::basic_waitable_timer<clock_type, clock_traits_type, executor_type>; using timer_type = asio::basic_waitable_timer<clock_type, clock_traits_type, executor_type>;
using receive_channel_type = asio::experimental::channel<executor_type, void(system::error_code, std::size_t)>; using receive_channel_type = asio::experimental::channel<
executor_type,
void(system::error_code, std::size_t)>;
using resolver_type = detail::resolver<Executor>; using resolver_type = detail::resolver<Executor>;
using health_checker_type = detail::health_checker<Executor>; using health_checker_type = detail::health_checker<Executor>;
using resp3_handshaker_type = detail::resp3_handshaker<executor_type>; using resp3_handshaker_type = detail::resp3_handshaker<executor_type>;
auto use_ssl() const noexcept auto use_ssl() const noexcept { return cfg_.use_ssl; }
{ return cfg_.use_ssl;}
void cancel_run() void cancel_run()
{ {
@@ -813,20 +791,19 @@ private:
template <class CompletionToken, class Logger> template <class CompletionToken, class Logger>
auto reader(Logger l, CompletionToken&& token) auto reader(Logger l, CompletionToken&& token)
{ {
return asio::async_compose return asio::async_compose<CompletionToken, void(system::error_code)>(
< CompletionToken detail::reader_op<this_type, Logger>{this, l},
, void(system::error_code) std::forward<CompletionToken>(token),
>(detail::reader_op<this_type, Logger>{this, l}, writer_timer_);
std::forward<CompletionToken>(token), writer_timer_);
} }
template <class CompletionToken, class Logger> template <class CompletionToken, class Logger>
auto writer(Logger l, CompletionToken&& token) auto writer(Logger l, CompletionToken&& token)
{ {
return asio::async_compose return asio::async_compose<CompletionToken, void(system::error_code)>(
< CompletionToken detail::writer_op<this_type, Logger>{this, l},
, void(system::error_code) std::forward<CompletionToken>(token),
>(detail::writer_op<this_type, Logger>{this, l}, std::forward<CompletionToken>(token), writer_timer_); writer_timer_);
} }
void close() void close()
@@ -840,10 +817,7 @@ private:
auto is_open() const noexcept { return stream_->next_layer().is_open(); } auto is_open() const noexcept { return stream_->next_layer().is_open(); }
auto& lowest_layer() noexcept { return stream_->lowest_layer(); } auto& lowest_layer() noexcept { return stream_->lowest_layer(); }
[[nodiscard]] bool trigger_write() const noexcept [[nodiscard]] bool trigger_write() const noexcept { return is_open() && !mpx_.is_writing(); }
{
return is_open() && !mpx_.is_writing();
}
asio::ssl::context ctx_; asio::ssl::context ctx_;
std::unique_ptr<next_layer_type> stream_; std::unique_ptr<next_layer_type> stream_;
@@ -877,43 +851,41 @@ public:
using executor_type = asio::any_io_executor; using executor_type = asio::any_io_executor;
/// Contructs from an executor. /// Contructs from an executor.
explicit explicit connection(
connection(
executor_type ex, executor_type ex,
asio::ssl::context ctx = asio::ssl::context{asio::ssl::context::tlsv12_client}); asio::ssl::context ctx = asio::ssl::context{asio::ssl::context::tlsv12_client});
/// Contructs from a context. /// Contructs from a context.
explicit explicit connection(
connection(
asio::io_context& ioc, asio::io_context& ioc,
asio::ssl::context ctx = asio::ssl::context{asio::ssl::context::tlsv12_client}); asio::ssl::context ctx = asio::ssl::context{asio::ssl::context::tlsv12_client});
/// Returns the underlying executor. /// Returns the underlying executor.
executor_type get_executor() noexcept executor_type get_executor() noexcept { return impl_.get_executor(); }
{ return impl_.get_executor(); }
/// Calls `boost::redis::basic_connection::async_run`. /// Calls `boost::redis::basic_connection::async_run`.
template <class CompletionToken = asio::deferred_t> template <class CompletionToken = asio::deferred_t>
auto async_run(config const& cfg, logger l, CompletionToken&& token = {}) auto async_run(config const& cfg, logger l, CompletionToken&& token = {})
{ {
return asio::async_initiate< return asio::async_initiate<CompletionToken, void(boost::system::error_code)>(
CompletionToken, void(boost::system::error_code)>( [](auto handler, connection* self, config const* cfg, logger l) {
[](auto handler, connection* self, config const* cfg, logger l) self->async_run_impl(*cfg, l, std::move(handler));
{ },
self->async_run_impl(*cfg, l, std::move(handler)); token,
}, token, this, &cfg, l); this,
&cfg,
l);
} }
/// Calls `boost::redis::basic_connection::async_receive`. /// Calls `boost::redis::basic_connection::async_receive`.
template <class CompletionToken = asio::deferred_t> template <class CompletionToken = asio::deferred_t>
auto async_receive(CompletionToken&& token = {}) auto async_receive(CompletionToken&& token = {})
{ return impl_.async_receive(std::forward<CompletionToken>(token)); } {
return impl_.async_receive(std::forward<CompletionToken>(token));
}
/// Calls `boost::redis::basic_connection::receive`. /// Calls `boost::redis::basic_connection::receive`.
std::size_t receive(system::error_code& ec) std::size_t receive(system::error_code& ec) { return impl_.receive(ec); }
{
return impl_.receive(ec);
}
/// Calls `boost::redis::basic_connection::async_exec`. /// Calls `boost::redis::basic_connection::async_exec`.
template <class Response, class CompletionToken = asio::deferred_t> template <class Response, class CompletionToken = asio::deferred_t>
@@ -924,61 +896,53 @@ public:
/// Calls `boost::redis::basic_connection::async_exec`. /// Calls `boost::redis::basic_connection::async_exec`.
template <class CompletionToken = asio::deferred_t> template <class CompletionToken = asio::deferred_t>
auto auto async_exec(request const& req, any_adapter adapter, CompletionToken&& token = {})
async_exec(
request const& req,
any_adapter adapter,
CompletionToken&& token = {})
{ {
return asio::async_initiate< return asio::async_initiate<CompletionToken, void(boost::system::error_code, std::size_t)>(
CompletionToken, void(boost::system::error_code, std::size_t)>( [](auto handler, connection* self, request const* req, any_adapter&& adapter) {
[](auto handler, connection* self, request const* req, any_adapter&& adapter) self->async_exec_impl(*req, std::move(adapter), std::move(handler));
{ },
self->async_exec_impl(*req, std::move(adapter), std::move(handler)); token,
}, token, this, &req, std::move(adapter)); this,
&req,
std::move(adapter));
} }
/// Calls `boost::redis::basic_connection::cancel`. /// Calls `boost::redis::basic_connection::cancel`.
void cancel(operation op = operation::all); void cancel(operation op = operation::all);
/// Calls `boost::redis::basic_connection::will_reconnect`. /// Calls `boost::redis::basic_connection::will_reconnect`.
bool will_reconnect() const noexcept bool will_reconnect() const noexcept { return impl_.will_reconnect(); }
{ return impl_.will_reconnect();}
/// Calls `boost::redis::basic_connection::next_layer`. /// Calls `boost::redis::basic_connection::next_layer`.
auto& next_layer() noexcept auto& next_layer() noexcept { return impl_.next_layer(); }
{ return impl_.next_layer(); }
/// Calls `boost::redis::basic_connection::next_layer`. /// Calls `boost::redis::basic_connection::next_layer`.
auto const& next_layer() const noexcept auto const& next_layer() const noexcept { return impl_.next_layer(); }
{ return impl_.next_layer(); }
/// Calls `boost::redis::basic_connection::reset_stream`. /// Calls `boost::redis::basic_connection::reset_stream`.
void reset_stream() void reset_stream() { impl_.reset_stream(); }
{ impl_.reset_stream();}
/// Sets the response object of `async_receive` operations. /// Sets the response object of `async_receive` operations.
template <class Response> template <class Response>
void set_receive_response(Response& response) void set_receive_response(Response& response)
{ impl_.set_receive_response(response); } {
impl_.set_receive_response(response);
}
/// Returns connection usage information. /// Returns connection usage information.
usage get_usage() const noexcept usage get_usage() const noexcept { return impl_.get_usage(); }
{ return impl_.get_usage(); }
/// Returns the ssl context. /// Returns the ssl context.
auto const& get_ssl_context() const noexcept auto const& get_ssl_context() const noexcept { return impl_.get_ssl_context(); }
{ return impl_.get_ssl_context();}
private: private:
void void async_run_impl(
async_run_impl(
config const& cfg, config const& cfg,
logger l, logger l,
asio::any_completion_handler<void(boost::system::error_code)> token); asio::any_completion_handler<void(boost::system::error_code)> token);
void void async_exec_impl(
async_exec_impl(
request const& req, request const& req,
any_adapter&& adapter, any_adapter&& adapter,
asio::any_completion_handler<void(boost::system::error_code, std::size_t)> token); asio::any_completion_handler<void(boost::system::error_code, std::size_t)> token);
@@ -986,6 +950,6 @@ private:
basic_connection<executor_type> impl_; basic_connection<executor_type> impl_;
}; };
} // boost::redis } // namespace boost::redis
#endif // BOOST_REDIS_CONNECTION_HPP #endif // BOOST_REDIS_CONNECTION_HPP

View File

@@ -9,16 +9,17 @@
#include <boost/redis/detail/helper.hpp> #include <boost/redis/detail/helper.hpp>
#include <boost/redis/error.hpp> #include <boost/redis/error.hpp>
#include <boost/asio/cancel_after.hpp>
#include <boost/asio/compose.hpp> #include <boost/asio/compose.hpp>
#include <boost/asio/connect.hpp> #include <boost/asio/connect.hpp>
#include <boost/asio/coroutine.hpp> #include <boost/asio/coroutine.hpp>
#include <boost/asio/ip/tcp.hpp> #include <boost/asio/ip/tcp.hpp>
#include <boost/asio/cancel_after.hpp>
#include <string>
#include <chrono>
namespace boost::redis::detail #include <chrono>
{ #include <string>
namespace boost::redis::detail {
template <class Connector, class Stream> template <class Connector, class Stream>
struct connect_op { struct connect_op {
@@ -28,15 +29,20 @@ struct connect_op {
asio::coroutine coro{}; asio::coroutine coro{};
template <class Self> template <class Self>
void operator()( Self& self void operator()(
, system::error_code const& ec = {} Self& self,
, asio::ip::tcp::endpoint const& ep= {}) system::error_code const& ec = {},
asio::ip::tcp::endpoint const& ep = {})
{ {
BOOST_ASIO_CORO_REENTER (coro) BOOST_ASIO_CORO_REENTER(coro)
{ {
BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD
asio::async_connect(*stream, *res_, asio::async_connect(
[](system::error_code const&, auto const&) { return true; }, *stream,
*res_,
[](system::error_code const&, auto const&) {
return true;
},
asio::cancel_after(ctor_->timeout_, std::move(self))); asio::cancel_after(ctor_->timeout_, std::move(self)));
ctor_->endpoint_ = ep; ctor_->endpoint_ = ep;
@@ -52,23 +58,20 @@ struct connect_op {
class connector { class connector {
public: public:
void set_config(config const& cfg) void set_config(config const& cfg) { timeout_ = cfg.connect_timeout; }
{ timeout_ = cfg.connect_timeout; }
template <class Stream, class CompletionToken> template <class Stream, class CompletionToken>
auto auto async_connect(
async_connect( Stream& stream,
Stream& stream, asio::ip::tcp::resolver::results_type const& res,
asio::ip::tcp::resolver::results_type const& res, CompletionToken&& token)
CompletionToken&& token)
{ {
return asio::async_compose return asio::async_compose<CompletionToken, void(system::error_code)>(
< CompletionToken connect_op<connector, Stream>{this, &stream, &res},
, void(system::error_code) token);
>(connect_op<connector, Stream>{this, &stream, &res}, token);
} }
auto const& endpoint() const noexcept { return endpoint_;} auto const& endpoint() const noexcept { return endpoint_; }
private: private:
template <class, class> friend struct connect_op; template <class, class> friend struct connect_op;
@@ -77,6 +80,6 @@ private:
asio::ip::tcp::endpoint endpoint_; asio::ip::tcp::endpoint endpoint_;
}; };
} // boost::redis::detail } // namespace boost::redis::detail
#endif // BOOST_REDIS_CONNECTOR_HPP #endif // BOOST_REDIS_CONNECTOR_HPP

View File

@@ -7,19 +7,20 @@
#ifndef BOOST_REDIS_HEALTH_CHECKER_HPP #ifndef BOOST_REDIS_HEALTH_CHECKER_HPP
#define BOOST_REDIS_HEALTH_CHECKER_HPP #define BOOST_REDIS_HEALTH_CHECKER_HPP
#include <boost/redis/request.hpp>
#include <boost/redis/response.hpp>
#include <boost/redis/operation.hpp>
#include <boost/redis/adapter/any_adapter.hpp> #include <boost/redis/adapter/any_adapter.hpp>
#include <boost/redis/config.hpp> #include <boost/redis/config.hpp>
#include <boost/redis/operation.hpp> #include <boost/redis/operation.hpp>
#include <boost/asio/steady_timer.hpp> #include <boost/redis/request.hpp>
#include <boost/redis/response.hpp>
#include <boost/asio/compose.hpp> #include <boost/asio/compose.hpp>
#include <boost/asio/consign.hpp> #include <boost/asio/consign.hpp>
#include <boost/asio/coroutine.hpp> #include <boost/asio/coroutine.hpp>
#include <boost/asio/post.hpp> #include <boost/asio/post.hpp>
#include <memory> #include <boost/asio/steady_timer.hpp>
#include <chrono> #include <chrono>
#include <memory>
namespace boost::redis::detail { namespace boost::redis::detail {
@@ -34,7 +35,7 @@ public:
template <class Self> template <class Self>
void operator()(Self& self, system::error_code ec = {}, std::size_t = 0) void operator()(Self& self, system::error_code ec = {}, std::size_t = 0)
{ {
BOOST_ASIO_CORO_REENTER (coro_) for (;;) BOOST_ASIO_CORO_REENTER(coro_) for (;;)
{ {
if (checker_->ping_interval_ == std::chrono::seconds::zero()) { if (checker_->ping_interval_ == std::chrono::seconds::zero()) {
logger_.trace("ping_op (1): timeout disabled."); logger_.trace("ping_op (1): timeout disabled.");
@@ -84,7 +85,7 @@ public:
template <class Self> template <class Self>
void operator()(Self& self, system::error_code ec = {}) void operator()(Self& self, system::error_code ec = {})
{ {
BOOST_ASIO_CORO_REENTER (coro_) for (;;) BOOST_ASIO_CORO_REENTER(coro_) for (;;)
{ {
if (checker_->ping_interval_ == std::chrono::seconds::zero()) { if (checker_->ping_interval_ == std::chrono::seconds::zero()) {
logger_.trace("check_timeout_op (1): timeout disabled."); logger_.trace("check_timeout_op (1): timeout disabled.");
@@ -130,11 +131,10 @@ public:
template <class Executor> template <class Executor>
class health_checker { class health_checker {
private: private:
using timer_type = using timer_type = asio::basic_waitable_timer<
asio::basic_waitable_timer< std::chrono::steady_clock,
std::chrono::steady_clock, asio::wait_traits<std::chrono::steady_clock>,
asio::wait_traits<std::chrono::steady_clock>, Executor>;
Executor>;
public: public:
health_checker(Executor ex) health_checker(Executor ex)
@@ -160,20 +160,22 @@ public:
template <class Connection, class Logger, class CompletionToken> template <class Connection, class Logger, class CompletionToken>
auto async_ping(Connection& conn, Logger l, CompletionToken token) auto async_ping(Connection& conn, Logger l, CompletionToken token)
{ {
return asio::async_compose return asio::async_compose<CompletionToken, void(system::error_code)>(
< CompletionToken ping_op<health_checker, Connection, Logger>{this, &conn, l},
, void(system::error_code) token,
>(ping_op<health_checker, Connection, Logger>{this, &conn, l}, token, conn, ping_timer_); conn,
ping_timer_);
} }
template <class Connection, class Logger, class CompletionToken> template <class Connection, class Logger, class CompletionToken>
auto async_check_timeout(Connection& conn, Logger l, CompletionToken token) auto async_check_timeout(Connection& conn, Logger l, CompletionToken token)
{ {
checker_has_exited_ = false; checker_has_exited_ = false;
return asio::async_compose return asio::async_compose<CompletionToken, void(system::error_code)>(
< CompletionToken check_timeout_op<health_checker, Connection, Logger>{this, &conn, l},
, void(system::error_code) token,
>(check_timeout_op<health_checker, Connection, Logger>{this, &conn, l}, token, conn, wait_timer_); conn,
wait_timer_);
} }
private: private:
@@ -188,6 +190,6 @@ private:
bool checker_has_exited_ = false; bool checker_has_exited_ = false;
}; };
} // boost::redis::detail } // namespace boost::redis::detail
#endif // BOOST_REDIS_HEALTH_CHECKER_HPP #endif // BOOST_REDIS_HEALTH_CHECKER_HPP

View File

@@ -9,8 +9,7 @@
#include <boost/asio/cancellation_type.hpp> #include <boost/asio/cancellation_type.hpp>
namespace boost::redis::detail namespace boost::redis::detail {
{
template <class T> template <class T>
auto is_cancelled(T const& self) auto is_cancelled(T const& self)
@@ -18,20 +17,18 @@ auto is_cancelled(T const& self)
return self.get_cancellation_state().cancelled() != asio::cancellation_type_t::none; return self.get_cancellation_state().cancelled() != asio::cancellation_type_t::none;
} }
#define BOOST_REDIS_CHECK_OP0(X)\ #define BOOST_REDIS_CHECK_OP0(X) \
if (ec || redis::detail::is_cancelled(self)) {\ if (ec || redis::detail::is_cancelled(self)) { \
X\ X self.complete(!!ec ? ec : asio::error::operation_aborted); \
self.complete(!!ec ? ec : asio::error::operation_aborted);\ return; \
return;\
} }
#define BOOST_REDIS_CHECK_OP1(X)\ #define BOOST_REDIS_CHECK_OP1(X) \
if (ec || redis::detail::is_cancelled(self)) {\ if (ec || redis::detail::is_cancelled(self)) { \
X\ X self.complete(!!ec ? ec : asio::error::operation_aborted, {}); \
self.complete(!!ec ? ec : asio::error::operation_aborted, {});\ return; \
return;\
} }
} // boost::redis::detail } // namespace boost::redis::detail
#endif // BOOST_REDIS_HELPER_HPP #endif // BOOST_REDIS_HELPER_HPP

View File

@@ -20,12 +20,11 @@
#include <deque> #include <deque>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <optional>
#include <string_view> #include <string_view>
#include <utility> #include <utility>
#include <optional>
namespace boost::redis namespace boost::redis {
{
class request; class request;
@@ -35,63 +34,61 @@ using tribool = std::optional<bool>;
struct multiplexer { struct multiplexer {
using adapter_type = std::function<void(resp3::node_view const&, system::error_code&)>; using adapter_type = std::function<void(resp3::node_view const&, system::error_code&)>;
using pipeline_adapter_type = std::function<void(std::size_t, resp3::node_view const&, system::error_code&)>; using pipeline_adapter_type = std::function<
void(std::size_t, resp3::node_view const&, system::error_code&)>;
struct elem { struct elem {
public: public:
explicit elem(request const& req, pipeline_adapter_type adapter); explicit elem(request const& req, pipeline_adapter_type adapter);
void set_done_callback(std::function<void()> f) noexcept void set_done_callback(std::function<void()> f) noexcept { done_ = std::move(f); };
{ done_ = std::move(f); };
auto notify_done() noexcept auto notify_done() noexcept { done_(); }
{ done_(); }
auto notify_error(system::error_code ec) noexcept -> void; auto notify_error(system::error_code ec) noexcept -> void;
[[nodiscard]] [[nodiscard]]
auto is_waiting() const noexcept auto is_waiting() const noexcept
{ return status_ == status::waiting; } {
return status_ == status::waiting;
}
[[nodiscard]] [[nodiscard]]
auto is_written() const noexcept auto is_written() const noexcept
{ return status_ == status::written; } {
return status_ == status::written;
}
[[nodiscard]] [[nodiscard]]
auto is_staged() const noexcept auto is_staged() const noexcept
{ return status_ == status::staged; } {
return status_ == status::staged;
}
void mark_written() noexcept void mark_written() noexcept { status_ = status::written; }
{ status_ = status::written; }
void mark_staged() noexcept void mark_staged() noexcept { status_ = status::staged; }
{ status_ = status::staged; }
void mark_waiting() noexcept void mark_waiting() noexcept { status_ = status::waiting; }
{ status_ = status::waiting; }
auto get_error() const -> system::error_code const& auto get_error() const -> system::error_code const& { return ec_; }
{ return ec_; }
auto get_request() const -> request const& auto get_request() const -> request const& { return *req_; }
{ return *req_; }
auto get_read_size() const -> std::size_t auto get_read_size() const -> std::size_t { return read_size_; }
{ return read_size_; }
auto get_remaining_responses() const -> std::size_t auto get_remaining_responses() const -> std::size_t { return remaining_responses_; }
{ return remaining_responses_; }
auto commit_response(std::size_t read_size) -> void; auto commit_response(std::size_t read_size) -> void;
auto get_adapter() -> adapter_type& auto get_adapter() -> adapter_type& { return adapter_; }
{ return adapter_; }
private: private:
enum class status enum class status
{ waiting {
, staged waiting,
, written staged,
written
}; };
request const* req_; request const* req_;
@@ -124,7 +121,9 @@ struct multiplexer {
[[nodiscard]] [[nodiscard]]
auto const& get_parser() const noexcept auto const& get_parser() const noexcept
{ return parser_; } {
return parser_;
}
//[[nodiscard]] //[[nodiscard]]
auto cancel_waiting() -> std::size_t; auto cancel_waiting() -> std::size_t;
@@ -134,19 +133,27 @@ struct multiplexer {
[[nodiscard]] [[nodiscard]]
auto get_cancel_run_state() const noexcept -> bool auto get_cancel_run_state() const noexcept -> bool
{ return cancel_run_called_; } {
return cancel_run_called_;
}
[[nodiscard]] [[nodiscard]]
auto get_write_buffer() noexcept -> std::string_view auto get_write_buffer() noexcept -> std::string_view
{ return std::string_view{write_buffer_}; } {
return std::string_view{write_buffer_};
}
[[nodiscard]] [[nodiscard]]
auto get_read_buffer() noexcept -> std::string& auto get_read_buffer() noexcept -> std::string&
{ return read_buffer_; } {
return read_buffer_;
}
[[nodiscard]] [[nodiscard]]
auto is_data_needed() const noexcept -> bool auto is_data_needed() const noexcept -> bool
{ return std::empty(read_buffer_); } {
return std::empty(read_buffer_);
}
// TODO: Change signature to receive an adapter instead of a // TODO: Change signature to receive an adapter instead of a
// response. // response.
@@ -160,7 +167,9 @@ struct multiplexer {
[[nodiscard]] [[nodiscard]]
auto get_usage() const noexcept -> usage auto get_usage() const noexcept -> usage
{ return usage_;} {
return usage_;
}
[[nodiscard]] [[nodiscard]]
auto is_writing() const noexcept -> bool; auto is_writing() const noexcept -> bool;
@@ -189,12 +198,10 @@ private:
adapter_type receive_adapter_; adapter_type receive_adapter_;
}; };
auto auto make_elem(request const& req, multiplexer::pipeline_adapter_type adapter)
make_elem( -> std::shared_ptr<multiplexer::elem>;
request const& req,
multiplexer::pipeline_adapter_type adapter) -> std::shared_ptr<multiplexer::elem>;
} // detail } // namespace detail
} // boost::redis } // namespace boost::redis
#endif // BOOST_REDIS_MULTIPLEXER_HPP #endif // BOOST_REDIS_MULTIPLEXER_HPP

View File

@@ -9,15 +9,16 @@
#include <boost/redis/config.hpp> #include <boost/redis/config.hpp>
#include <boost/redis/error.hpp> #include <boost/redis/error.hpp>
#include <boost/asio/cancel_after.hpp>
#include <boost/asio/compose.hpp> #include <boost/asio/compose.hpp>
#include <boost/asio/coroutine.hpp> #include <boost/asio/coroutine.hpp>
#include <boost/asio/ip/tcp.hpp> #include <boost/asio/ip/tcp.hpp>
#include <boost/asio/cancel_after.hpp>
#include <string>
#include <chrono>
namespace boost::redis::detail #include <chrono>
{ #include <string>
namespace boost::redis::detail {
template <class Resolver> template <class Resolver>
struct resolve_op { struct resolve_op {
@@ -25,11 +26,12 @@ struct resolve_op {
asio::coroutine coro{}; asio::coroutine coro{};
template <class Self> template <class Self>
void operator()( Self& self void operator()(
, system::error_code ec = {} Self& self,
, asio::ip::tcp::resolver::results_type res = {}) system::error_code ec = {},
asio::ip::tcp::resolver::results_type res = {})
{ {
BOOST_ASIO_CORO_REENTER (coro) BOOST_ASIO_CORO_REENTER(coro)
{ {
BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD
resv_->resv_.async_resolve( resv_->resv_.async_resolve(
@@ -51,22 +53,22 @@ struct resolve_op {
template <class Executor> template <class Executor>
class resolver { class resolver {
public: public:
resolver(Executor ex) : resv_{ex} {} resolver(Executor ex)
: resv_{ex}
{ }
template <class CompletionToken> template <class CompletionToken>
auto async_resolve(CompletionToken&& token) auto async_resolve(CompletionToken&& token)
{ {
return asio::async_compose return asio::async_compose<CompletionToken, void(system::error_code)>(
< CompletionToken resolve_op<resolver>{this},
, void(system::error_code) token,
>(resolve_op<resolver>{this}, token, resv_); resv_);
} }
void cancel() void cancel() { resv_.cancel(); }
{ resv_.cancel(); }
auto const& results() const noexcept auto const& results() const noexcept { return results_; }
{ return results_;}
void set_config(config const& cfg) void set_config(config const& cfg)
{ {
@@ -84,6 +86,6 @@ private:
asio::ip::tcp::resolver::results_type results_; asio::ip::tcp::resolver::results_type results_;
}; };
} // boost::redis::detail } // namespace boost::redis::detail
#endif // BOOST_REDIS_RESOLVER_HPP #endif // BOOST_REDIS_RESOLVER_HPP

View File

@@ -8,20 +8,20 @@
#define BOOST_REDIS_RUNNER_HPP #define BOOST_REDIS_RUNNER_HPP
#include <boost/redis/config.hpp> #include <boost/redis/config.hpp>
#include <boost/redis/request.hpp>
#include <boost/redis/response.hpp>
#include <boost/redis/error.hpp> #include <boost/redis/error.hpp>
#include <boost/redis/logger.hpp> #include <boost/redis/logger.hpp>
#include <boost/redis/operation.hpp> #include <boost/redis/operation.hpp>
#include <boost/redis/request.hpp>
#include <boost/redis/response.hpp>
#include <boost/asio/compose.hpp> #include <boost/asio/compose.hpp>
#include <boost/asio/coroutine.hpp> #include <boost/asio/coroutine.hpp>
//#include <boost/asio/ip/tcp.hpp> //#include <boost/asio/ip/tcp.hpp>
#include <string>
#include <memory>
#include <chrono> #include <chrono>
#include <memory>
#include <string>
namespace boost::redis::detail namespace boost::redis::detail {
{
void push_hello(config const& cfg, request& req); void push_hello(config const& cfg, request& req);
@@ -38,12 +38,15 @@ struct hello_op {
template <class Self> template <class Self>
void operator()(Self& self, system::error_code ec = {}, std::size_t = 0) void operator()(Self& self, system::error_code ec = {}, std::size_t = 0)
{ {
BOOST_ASIO_CORO_REENTER (coro_) BOOST_ASIO_CORO_REENTER(coro_)
{ {
handshaker_->add_hello(); handshaker_->add_hello();
BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD
conn_->async_exec(handshaker_->hello_req_, any_adapter(handshaker_->hello_resp_), std::move(self)); conn_->async_exec(
handshaker_->hello_req_,
any_adapter(handshaker_->hello_resp_),
std::move(self));
logger_.on_hello(ec, handshaker_->hello_resp_); logger_.on_hello(ec, handshaker_->hello_resp_);
if (ec) { if (ec) {
@@ -66,16 +69,15 @@ struct hello_op {
template <class Executor> template <class Executor>
class resp3_handshaker { class resp3_handshaker {
public: public:
void set_config(config const& cfg) void set_config(config const& cfg) { cfg_ = cfg; }
{ cfg_ = cfg; }
template <class Connection, class Logger, class CompletionToken> template <class Connection, class Logger, class CompletionToken>
auto async_hello(Connection& conn, Logger l, CompletionToken token) auto async_hello(Connection& conn, Logger l, CompletionToken token)
{ {
return asio::async_compose return asio::async_compose<CompletionToken, void(system::error_code)>(
< CompletionToken hello_op<resp3_handshaker, Connection, Logger>{this, &conn, l},
, void(system::error_code) token,
>(hello_op<resp3_handshaker, Connection, Logger>{this, &conn, l}, token, conn); conn);
} }
private: private:
@@ -94,12 +96,11 @@ private:
if (!hello_resp_.has_value()) if (!hello_resp_.has_value())
return true; return true;
auto f = [](auto const& e) auto f = [](auto const& e) {
{
switch (e.data_type) { switch (e.data_type) {
case resp3::type::simple_error: case resp3::type::simple_error:
case resp3::type::blob_error: return true; case resp3::type::blob_error: return true;
default: return false; default: return false;
} }
}; };
@@ -111,6 +112,6 @@ private:
config cfg_; config cfg_;
}; };
} // boost::redis::detail } // namespace boost::redis::detail
#endif // BOOST_REDIS_RUNNER_HPP #endif // BOOST_REDIS_RUNNER_HPP

View File

@@ -9,26 +9,27 @@
#include <boost/redis/adapter/any_adapter.hpp> #include <boost/redis/adapter/any_adapter.hpp>
#include <boost/redis/config.hpp> #include <boost/redis/config.hpp>
#include <boost/redis/request.hpp>
#include <boost/redis/response.hpp>
#include <boost/redis/detail/helper.hpp> #include <boost/redis/detail/helper.hpp>
#include <boost/redis/error.hpp> #include <boost/redis/error.hpp>
#include <boost/redis/logger.hpp> #include <boost/redis/logger.hpp>
#include <boost/redis/operation.hpp> #include <boost/redis/operation.hpp>
#include <boost/redis/request.hpp>
#include <boost/redis/response.hpp>
#include <boost/asio/cancel_after.hpp>
#include <boost/asio/compose.hpp> #include <boost/asio/compose.hpp>
#include <boost/asio/coroutine.hpp> #include <boost/asio/coroutine.hpp>
#include <boost/asio/experimental/parallel_group.hpp> #include <boost/asio/experimental/parallel_group.hpp>
#include <boost/asio/ip/tcp.hpp> #include <boost/asio/ip/tcp.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/asio/prepend.hpp> #include <boost/asio/prepend.hpp>
#include <boost/asio/ssl.hpp> #include <boost/asio/ssl.hpp>
#include <boost/asio/cancel_after.hpp> #include <boost/asio/steady_timer.hpp>
#include <string>
#include <memory>
#include <chrono>
namespace boost::redis::detail #include <chrono>
{ #include <memory>
#include <string>
namespace boost::redis::detail {
void push_hello(config const& cfg, request& req); void push_hello(config const& cfg, request& req);
@@ -45,7 +46,7 @@ struct hello_op {
template <class Self> template <class Self>
void operator()(Self& self, system::error_code ec = {}, std::size_t = 0) void operator()(Self& self, system::error_code ec = {}, std::size_t = 0)
{ {
BOOST_ASIO_CORO_REENTER (coro_) BOOST_ASIO_CORO_REENTER(coro_)
{ {
runner_->add_hello(); runner_->add_hello();
@@ -85,21 +86,22 @@ public:
: runner_{runner} : runner_{runner}
, conn_{conn} , conn_{conn}
, logger_{l} , logger_{l}
{} { }
template <class Self> template <class Self>
void operator()( Self& self void operator()(
, order_t order = {} Self& self,
, system::error_code ec0 = {} order_t order = {},
, system::error_code ec1 = {} system::error_code ec0 = {},
, system::error_code ec2 = {} system::error_code ec1 = {},
, system::error_code ec3 = {} system::error_code ec2 = {},
, system::error_code ec4 = {}) system::error_code ec3 = {},
system::error_code ec4 = {})
{ {
BOOST_ASIO_CORO_REENTER (coro_) for (;;) BOOST_ASIO_CORO_REENTER(coro_) for (;;)
{ {
BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD
conn_->resv_.async_resolve(asio::prepend(std::move(self), order_t {})); conn_->resv_.async_resolve(asio::prepend(std::move(self), order_t{}));
logger_.on_resolve(ec0, conn_->resv_.results()); logger_.on_resolve(ec0, conn_->resv_.results());
@@ -112,7 +114,7 @@ public:
conn_->ctor_.async_connect( conn_->ctor_.async_connect(
conn_->next_layer().next_layer(), conn_->next_layer().next_layer(),
conn_->resv_.results(), conn_->resv_.results(),
asio::prepend(std::move(self), order_t {})); asio::prepend(std::move(self), order_t{}));
logger_.on_connect(ec0, conn_->ctor_.endpoint()); logger_.on_connect(ec0, conn_->ctor_.endpoint());
@@ -126,13 +128,8 @@ public:
conn_->next_layer().async_handshake( conn_->next_layer().async_handshake(
asio::ssl::stream_base::client, asio::ssl::stream_base::client,
asio::prepend( asio::prepend(
asio::cancel_after( asio::cancel_after(runner_->cfg_.ssl_handshake_timeout, std::move(self)),
runner_->cfg_.ssl_handshake_timeout, order_t{}));
std::move(self)
),
order_t {}
)
);
logger_.on_ssl_handshake(ec0); logger_.on_ssl_handshake(ec0);
@@ -149,14 +146,22 @@ public:
// causing an authentication problem. // causing an authentication problem.
BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD
asio::experimental::make_parallel_group( asio::experimental::make_parallel_group(
[this](auto token) { return runner_->async_hello(*conn_, logger_, token); }, [this](auto token) {
[this](auto token) { return conn_->health_checker_.async_ping(*conn_, logger_, token); }, return runner_->async_hello(*conn_, logger_, token);
[this](auto token) { return conn_->health_checker_.async_check_timeout(*conn_, logger_, token);}, },
[this](auto token) { return conn_->reader(logger_, token);}, [this](auto token) {
[this](auto token) { return conn_->writer(logger_, token);} return conn_->health_checker_.async_ping(*conn_, logger_, token);
).async_wait( },
asio::experimental::wait_for_one_error(), [this](auto token) {
std::move(self)); return conn_->health_checker_.async_check_timeout(*conn_, logger_, token);
},
[this](auto token) {
return conn_->reader(logger_, token);
},
[this](auto token) {
return conn_->writer(logger_, token);
})
.async_wait(asio::experimental::wait_for_one_error(), std::move(self));
if (order[0] == 0 && !!ec0) { if (order[0] == 0 && !!ec0) {
self.complete(ec0); self.complete(ec0);
@@ -184,7 +189,7 @@ public:
conn_->writer_timer_.expires_after(conn_->cfg_.reconnect_wait_interval); conn_->writer_timer_.expires_after(conn_->cfg_.reconnect_wait_interval);
BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD
conn_->writer_timer_.async_wait(asio::prepend(std::move(self), order_t {})); conn_->writer_timer_.async_wait(asio::prepend(std::move(self), order_t{}));
if (ec0) { if (ec0) {
self.complete(ec0); self.complete(ec0);
return; return;
@@ -207,32 +212,28 @@ public:
: cfg_{cfg} : cfg_{cfg}
{ } { }
void set_config(config const& cfg) void set_config(config const& cfg) { cfg_ = cfg; }
{
cfg_ = cfg;
}
template <class Connection, class Logger, class CompletionToken> template <class Connection, class Logger, class CompletionToken>
auto async_run(Connection& conn, Logger l, CompletionToken token) auto async_run(Connection& conn, Logger l, CompletionToken token)
{ {
return asio::async_compose return asio::async_compose<CompletionToken, void(system::error_code)>(
< CompletionToken runner_op<runner, Connection, Logger>{this, &conn, l},
, void(system::error_code) token,
>(runner_op<runner, Connection, Logger>{this, &conn, l}, token, conn); conn);
} }
private: private:
template <class, class, class> friend class runner_op; template <class, class, class> friend class runner_op;
template <class, class, class> friend struct hello_op; template <class, class, class> friend struct hello_op;
template <class Connection, class Logger, class CompletionToken> template <class Connection, class Logger, class CompletionToken>
auto async_hello(Connection& conn, Logger l, CompletionToken token) auto async_hello(Connection& conn, Logger l, CompletionToken token)
{ {
return asio::async_compose return asio::async_compose<CompletionToken, void(system::error_code)>(
< CompletionToken hello_op<runner, Connection, Logger>{this, &conn, l},
, void(system::error_code) token,
>(hello_op<runner, Connection, Logger>{this, &conn, l}, token, conn); conn);
} }
void add_hello() void add_hello()
@@ -248,12 +249,11 @@ private:
if (!hello_resp_.has_value()) if (!hello_resp_.has_value())
return true; return true;
auto f = [](auto const& e) auto f = [](auto const& e) {
{
switch (e.data_type) { switch (e.data_type) {
case resp3::type::simple_error: case resp3::type::simple_error:
case resp3::type::blob_error: return true; case resp3::type::blob_error: return true;
default: return false; default: return false;
} }
}; };
@@ -265,6 +265,6 @@ private:
config cfg_; config cfg_;
}; };
} // boost::redis::detail } // namespace boost::redis::detail
#endif // BOOST_REDIS_RUNNER_HPP #endif // BOOST_REDIS_RUNNER_HPP

View File

@@ -7,9 +7,10 @@
#ifndef BOOST_REDIS_WRITE_HPP #ifndef BOOST_REDIS_WRITE_HPP
#define BOOST_REDIS_WRITE_HPP #define BOOST_REDIS_WRITE_HPP
#include <boost/asio/write.hpp>
#include <boost/redis/request.hpp> #include <boost/redis/request.hpp>
#include <boost/asio/write.hpp>
namespace boost::redis::detail { namespace boost::redis::detail {
/** \brief Writes a request synchronously. /** \brief Writes a request synchronously.
@@ -18,13 +19,13 @@ namespace boost::redis::detail {
* \param stream Stream to write the request to. * \param stream Stream to write the request to.
* \param req Request to write. * \param req Request to write.
*/ */
template<class SyncWriteStream> template <class SyncWriteStream>
auto write(SyncWriteStream& stream, request const& req) auto write(SyncWriteStream& stream, request const& req)
{ {
return asio::write(stream, asio::buffer(req.payload())); return asio::write(stream, asio::buffer(req.payload()));
} }
template<class SyncWriteStream> template <class SyncWriteStream>
auto write(SyncWriteStream& stream, request const& req, system::error_code& ec) auto write(SyncWriteStream& stream, request const& req, system::error_code& ec)
{ {
return asio::write(stream, asio::buffer(req.payload()), ec); return asio::write(stream, asio::buffer(req.payload()), ec);
@@ -37,10 +38,10 @@ auto write(SyncWriteStream& stream, request const& req, system::error_code& ec)
* \param req Request to write. * \param req Request to write.
* \param token Asio completion token. * \param token Asio completion token.
*/ */
template< template <
class AsyncWriteStream, class AsyncWriteStream,
class CompletionToken = asio::default_completion_token_t<typename AsyncWriteStream::executor_type> class CompletionToken =
> asio::default_completion_token_t<typename AsyncWriteStream::executor_type> >
auto async_write( auto async_write(
AsyncWriteStream& stream, AsyncWriteStream& stream,
request const& req, request const& req,
@@ -50,6 +51,6 @@ auto async_write(
return asio::async_write(stream, asio::buffer(req.payload()), token); return asio::async_write(stream, asio::buffer(req.payload()), token);
} }
} // boost::redis::detail } // namespace boost::redis::detail
#endif // BOOST_REDIS_WRITE_HPP #endif // BOOST_REDIS_WRITE_HPP

View File

@@ -93,13 +93,13 @@ enum class error
*/ */
auto make_error_code(error e) -> system::error_code; auto make_error_code(error e) -> system::error_code;
} // boost::redis } // namespace boost::redis
namespace std { namespace std {
template<> template <>
struct is_error_code_enum<::boost::redis::error> : std::true_type {}; struct is_error_code_enum<::boost::redis::error> : std::true_type { };
} // std } // namespace std
#endif // BOOST_REDIS_ERROR_HPP #endif // BOOST_REDIS_ERROR_HPP

View File

@@ -13,8 +13,7 @@
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
namespace boost::redis namespace boost::redis {
{
/** @brief Type used to ignore responses. /** @brief Type used to ignore responses.
* @ingroup high-level-api * @ingroup high-level-api
@@ -44,6 +43,6 @@ using ignore_t = std::decay_t<decltype(std::ignore)>;
*/ */
extern ignore_t ignore; extern ignore_t ignore;
} // boost::redis } // namespace boost::redis
#endif // BOOST_REDIS_IGNORE_HPP #endif // BOOST_REDIS_IGNORE_HPP

View File

@@ -5,6 +5,7 @@
*/ */
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <cstddef> #include <cstddef>
namespace boost::redis { namespace boost::redis {
@@ -17,8 +18,7 @@ connection::connection(asio::io_context& ioc, asio::ssl::context ctx)
: impl_{ioc.get_executor(), std::move(ctx)} : impl_{ioc.get_executor(), std::move(ctx)}
{ } { }
void void connection::async_run_impl(
connection::async_run_impl(
config const& cfg, config const& cfg,
logger l, logger l,
asio::any_completion_handler<void(boost::system::error_code)> token) asio::any_completion_handler<void(boost::system::error_code)> token)
@@ -26,8 +26,7 @@ connection::async_run_impl(
impl_.async_run(cfg, l, std::move(token)); impl_.async_run(cfg, l, std::move(token));
} }
void void connection::async_exec_impl(
connection::async_exec_impl(
request const& req, request const& req,
any_adapter&& adapter, any_adapter&& adapter,
asio::any_completion_handler<void(boost::system::error_code, std::size_t)> token) asio::any_completion_handler<void(boost::system::error_code, std::size_t)> token)
@@ -35,9 +34,6 @@ connection::async_exec_impl(
impl_.async_exec(req, std::move(adapter), std::move(token)); impl_.async_exec(req, std::move(adapter), std::move(token));
} }
void connection::cancel(operation op) void connection::cancel(operation op) { impl_.cancel(op); }
{
impl_.cancel(op);
}
} // namespace boost::redis } // namespace boost::redis

View File

@@ -5,62 +5,62 @@
*/ */
#include <boost/redis/error.hpp> #include <boost/redis/error.hpp>
#include <boost/assert.hpp> #include <boost/assert.hpp>
namespace boost::redis { namespace boost::redis {
namespace detail { namespace detail {
struct error_category_impl : system::error_category { struct error_category_impl : system::error_category {
virtual ~error_category_impl() = default; virtual ~error_category_impl() = default;
auto name() const noexcept -> char const* override auto name() const noexcept -> char const* override { return "boost.redis"; }
{
return "boost.redis";
}
auto message(int ev) const -> std::string override auto message(int ev) const -> std::string override
{ {
switch(static_cast<error>(ev)) { switch (static_cast<error>(ev)) {
case error::invalid_data_type: return "Invalid resp3 type."; case error::invalid_data_type: return "Invalid resp3 type.";
case error::not_a_number: return "Can't convert string to number (maybe forgot to upgrade to RESP3?)."; case error::not_a_number:
case error::exceeeds_max_nested_depth: return "Exceeds the maximum number of nested responses."; return "Can't convert string to number (maybe forgot to upgrade to RESP3?).";
case error::unexpected_bool_value: return "Unexpected bool value."; case error::exceeeds_max_nested_depth:
case error::empty_field: return "Expected field value is empty."; return "Exceeds the maximum number of nested responses.";
case error::expects_resp3_simple_type: return "Expects a resp3 simple type."; case error::unexpected_bool_value: return "Unexpected bool value.";
case error::expects_resp3_aggregate: return "Expects resp3 aggregate."; case error::empty_field: return "Expected field value is empty.";
case error::expects_resp3_map: return "Expects resp3 map."; case error::expects_resp3_simple_type: return "Expects a resp3 simple type.";
case error::expects_resp3_set: return "Expects resp3 set."; case error::expects_resp3_aggregate: return "Expects resp3 aggregate.";
case error::nested_aggregate_not_supported: return "Nested aggregate not_supported."; case error::expects_resp3_map: return "Expects resp3 map.";
case error::resp3_simple_error: return "Got RESP3 simple-error."; case error::expects_resp3_set: return "Expects resp3 set.";
case error::resp3_blob_error: return "Got RESP3 blob-error."; case error::nested_aggregate_not_supported: return "Nested aggregate not_supported.";
case error::incompatible_size: return "Aggregate container has incompatible size."; case error::resp3_simple_error: return "Got RESP3 simple-error.";
case error::not_a_double: return "Not a double."; case error::resp3_blob_error: return "Got RESP3 blob-error.";
case error::resp3_null: return "Got RESP3 null."; case error::incompatible_size: return "Aggregate container has incompatible size.";
case error::not_connected: return "Not connected."; case error::not_a_double: return "Not a double.";
case error::resolve_timeout: return "Resolve timeout."; case error::resp3_null: return "Got RESP3 null.";
case error::connect_timeout: return "Connect timeout."; case error::not_connected: return "Not connected.";
case error::pong_timeout: return "Pong timeout."; case error::resolve_timeout: return "Resolve timeout.";
case error::ssl_handshake_timeout: return "SSL handshake timeout."; case error::connect_timeout: return "Connect timeout.";
case error::sync_receive_push_failed: return "Can't receive server push synchronously without blocking."; case error::pong_timeout: return "Pong timeout.";
case error::incompatible_node_depth: return "Incompatible node depth."; case error::ssl_handshake_timeout: return "SSL handshake timeout.";
case error::resp3_hello: return "RESP3 handshake error (hello command)."; case error::sync_receive_push_failed:
default: BOOST_ASSERT(false); return "Boost.Redis error."; return "Can't receive server push synchronously without blocking.";
case error::incompatible_node_depth: return "Incompatible node depth.";
case error::resp3_hello: return "RESP3 handshake error (hello command).";
default: BOOST_ASSERT(false); return "Boost.Redis error.";
} }
} }
}; };
auto category() -> system::error_category const& auto category() -> system::error_category const&
{ {
static error_category_impl instance; static error_category_impl instance;
return instance; return instance;
} }
} // detail } // namespace detail
auto make_error_code(error e) -> system::error_code auto make_error_code(error e) -> system::error_code
{ {
return system::error_code{static_cast<int>(e), detail::category()}; return system::error_code{static_cast<int>(e), detail::category()};
} }
} // boost::redis::detail } // namespace boost::redis

View File

@@ -6,7 +6,6 @@
#include <boost/redis/ignore.hpp> #include <boost/redis/ignore.hpp>
namespace boost::redis namespace boost::redis {
{
ignore_t ignore; ignore_t ignore;
} }

View File

@@ -5,12 +5,13 @@
*/ */
#include <boost/redis/logger.hpp> #include <boost/redis/logger.hpp>
#include <boost/system/error_code.hpp> #include <boost/system/error_code.hpp>
#include <iostream> #include <iostream>
#include <iterator> #include <iterator>
namespace boost::redis namespace boost::redis {
{
void logger::write_prefix() void logger::write_prefix()
{ {
@@ -18,7 +19,9 @@ void logger::write_prefix()
std::clog << prefix_; std::clog << prefix_;
} }
void logger::on_resolve(system::error_code const& ec, asio::ip::tcp::resolver::results_type const& res) void logger::on_resolve(
system::error_code const& ec,
asio::ip::tcp::resolver::results_type const& res)
{ {
if (level_ < level::info) if (level_ < level::info)
return; return;
@@ -71,10 +74,7 @@ void logger::on_ssl_handshake(system::error_code const& ec)
std::clog << "SSL handshake: " << ec.message() << std::endl; std::clog << "SSL handshake: " << ec.message() << std::endl;
} }
void void logger::on_write(system::error_code const& ec, std::string_view payload)
logger::on_write(
system::error_code const& ec,
std::string_view payload)
{ {
if (level_ < level::info) if (level_ < level::info)
return; return;
@@ -104,10 +104,7 @@ void logger::on_read(system::error_code const& ec, std::size_t n)
std::clog << std::endl; std::clog << std::endl;
} }
void void logger::on_hello(system::error_code const& ec, generic_response const& resp)
logger::on_hello(
system::error_code const& ec,
generic_response const& resp)
{ {
if (level_ < level::info) if (level_ < level::info)
return; return;
@@ -145,4 +142,4 @@ void logger::trace(std::string_view op, system::error_code const& ec)
std::clog << op << ": " << ec.message() << std::endl; std::clog << op << ": " << ec.message() << std::endl;
} }
} // boost::redis } // namespace boost::redis

View File

@@ -9,8 +9,7 @@
#include <memory> #include <memory>
namespace boost::redis::detail namespace boost::redis::detail {
{
multiplexer::elem::elem(request const& req, pipeline_adapter_type adapter) multiplexer::elem::elem(request const& req, pipeline_adapter_type adapter)
: req_{&req} : req_{&req}
@@ -20,8 +19,7 @@ multiplexer::elem::elem(request const& req, pipeline_adapter_type adapter)
, ec_{{}} , ec_{{}}
, read_size_{0} , read_size_{0}
{ {
adapter_ = [this, adapter](resp3::node_view const& nd, system::error_code& ec) adapter_ = [this, adapter](resp3::node_view const& nd, system::error_code& ec) {
{
auto const i = req_->get_expected_responses() - remaining_responses_; auto const i = req_->get_expected_responses() - remaining_responses_;
adapter(i, nd, ec); adapter(i, nd, ec);
}; };
@@ -75,17 +73,15 @@ void multiplexer::add(std::shared_ptr<elem> const& info)
reqs_.push_back(info); reqs_.push_back(info);
if (info->get_request().has_hello_priority()) { if (info->get_request().has_hello_priority()) {
auto rend = auto rend = std::partition_point(std::rbegin(reqs_), std::rend(reqs_), [](auto const& e) {
std::partition_point(std::rbegin(reqs_), std::rend(reqs_), [](auto const& e) { return e->is_waiting();
return e->is_waiting();
}); });
std::rotate(std::rbegin(reqs_), std::rbegin(reqs_) + 1, rend); std::rotate(std::rbegin(reqs_), std::rbegin(reqs_) + 1, rend);
} }
} }
std::pair<tribool, std::size_t> std::pair<tribool, std::size_t> multiplexer::commit_read(system::error_code& ec)
multiplexer::commit_read(system::error_code& ec)
{ {
// We arrive here in two states: // We arrive here in two states:
// //
@@ -97,7 +93,7 @@ multiplexer::commit_read(system::error_code& ec)
// 2. On a new message, in which case we have to determine // 2. On a new message, in which case we have to determine
// whether the next messag is a push or a response. // whether the next messag is a push or a response.
// //
if (!on_push_) // Prepare for new message. if (!on_push_) // Prepare for new message.
on_push_ = is_next_push(); on_push_ = is_next_push();
if (on_push_) { if (on_push_) {
@@ -111,7 +107,9 @@ multiplexer::commit_read(system::error_code& ec)
return std::make_pair(std::make_optional(true), size); return std::make_pair(std::make_optional(true), size);
} }
BOOST_ASSERT_MSG(is_waiting_response(), "Not waiting for a response (using MONITOR command perhaps?)"); BOOST_ASSERT_MSG(
is_waiting_response(),
"Not waiting for a response (using MONITOR command perhaps?)");
BOOST_ASSERT(!reqs_.empty()); BOOST_ASSERT(!reqs_.empty());
BOOST_ASSERT(reqs_.front() != nullptr); BOOST_ASSERT(reqs_.front() != nullptr);
BOOST_ASSERT(reqs_.front()->get_remaining_responses() != 0); BOOST_ASSERT(reqs_.front()->get_remaining_responses() != 0);
@@ -148,10 +146,12 @@ std::size_t multiplexer::prepare_write()
{ {
// Coalesces the requests and marks them staged. After a // Coalesces the requests and marks them staged. After a
// successful write staged requests will be marked as written. // successful write staged requests will be marked as written.
auto const point = auto const point = std::partition_point(
std::partition_point(std::cbegin(reqs_), std::cend(reqs_), [](auto const& ri) { std::cbegin(reqs_),
std::cend(reqs_),
[](auto const& ri) {
return !ri->is_waiting(); return !ri->is_waiting();
}); });
std::for_each(point, std::cend(reqs_), [this](auto const& ri) { std::for_each(point, std::cend(reqs_), [this](auto const& ri) {
// Stage the request. // Stage the request.
@@ -166,11 +166,9 @@ std::size_t multiplexer::prepare_write()
return static_cast<std::size_t>(d); return static_cast<std::size_t>(d);
} }
std::size_t multiplexer::cancel_waiting() std::size_t multiplexer::cancel_waiting()
{ {
auto f = [](auto const& ptr) auto f = [](auto const& ptr) {
{
BOOST_ASSERT(ptr != nullptr); BOOST_ASSERT(ptr != nullptr);
return !ptr->is_waiting(); return !ptr->is_waiting();
}; };
@@ -196,8 +194,7 @@ auto multiplexer::cancel_on_conn_lost() -> std::size_t
} }
// Must return false if the request should be removed. // Must return false if the request should be removed.
auto cond = [](auto const& ptr) auto cond = [](auto const& ptr) {
{
BOOST_ASSERT(ptr != nullptr); BOOST_ASSERT(ptr != nullptr);
if (ptr->is_waiting()) { if (ptr->is_waiting()) {
@@ -281,7 +278,7 @@ bool multiplexer::is_next_push() const noexcept
std::size_t multiplexer::release_push_requests() std::size_t multiplexer::release_push_requests()
{ {
auto point = std::stable_partition(std::begin(reqs_), std::end(reqs_), [](auto const& ptr) { auto point = std::stable_partition(std::begin(reqs_), std::end(reqs_), [](auto const& ptr) {
return !(ptr->is_written() && ptr->get_request().get_expected_responses() == 0); return !(ptr->is_written() && ptr->get_request().get_expected_responses() == 0);
}); });
std::for_each(point, std::end(reqs_), [](auto const& ptr) { std::for_each(point, std::end(reqs_), [](auto const& ptr) {
@@ -305,17 +302,12 @@ bool multiplexer::is_waiting_response() const noexcept
return !reqs_.front()->is_waiting(); return !reqs_.front()->is_waiting();
} }
bool multiplexer::is_writing() const noexcept bool multiplexer::is_writing() const noexcept { return !write_buffer_.empty(); }
{
return !write_buffer_.empty();
}
auto auto make_elem(request const& req, multiplexer::pipeline_adapter_type adapter)
make_elem( -> std::shared_ptr<multiplexer::elem>
request const& req,
multiplexer::pipeline_adapter_type adapter) -> std::shared_ptr<multiplexer::elem>
{ {
return std::make_shared<multiplexer::elem>(req, std::move(adapter)); return std::make_shared<multiplexer::elem>(req, std::move(adapter));
} }
} } // namespace boost::redis::detail

View File

@@ -12,10 +12,13 @@ namespace boost::redis::detail {
auto has_response(std::string_view cmd) -> bool auto has_response(std::string_view cmd) -> bool
{ {
if (cmd == "SUBSCRIBE") return true; if (cmd == "SUBSCRIBE")
if (cmd == "PSUBSCRIBE") return true; return true;
if (cmd == "UNSUBSCRIBE") return true; if (cmd == "PSUBSCRIBE")
return true;
if (cmd == "UNSUBSCRIBE")
return true;
return false; return false;
} }
} // boost:redis::detail } // namespace boost::redis::detail

View File

@@ -6,8 +6,7 @@
#include <boost/redis/detail/resp3_handshaker.hpp> #include <boost/redis/detail/resp3_handshaker.hpp>
namespace boost::redis::detail namespace boost::redis::detail {
{
void push_hello(config const& cfg, request& req) void push_hello(config const& cfg, request& req)
{ {
@@ -24,4 +23,4 @@ void push_hello(config const& cfg, request& req)
req.push("SELECT", cfg.database_index.value()); req.push("SELECT", cfg.database_index.value());
} }
} // boost::redis::detail } // namespace boost::redis::detail

View File

@@ -4,20 +4,20 @@
* accompanying file LICENSE.txt) * accompanying file LICENSE.txt)
*/ */
#include <boost/redis/response.hpp>
#include <boost/redis/error.hpp> #include <boost/redis/error.hpp>
#include <boost/redis/response.hpp>
#include <boost/assert.hpp> #include <boost/assert.hpp>
namespace boost::redis namespace boost::redis {
{
void consume_one(generic_response& r, system::error_code& ec) void consume_one(generic_response& r, system::error_code& ec)
{ {
if (r.has_error()) if (r.has_error())
return; // Nothing to consume. return; // Nothing to consume.
if (std::empty(r.value())) if (std::empty(r.value()))
return; // Nothing to consume. return; // Nothing to consume.
auto const depth = r.value().front().depth; auto const depth = r.value().front().depth;
@@ -29,8 +29,9 @@ void consume_one(generic_response& r, system::error_code& ec)
return; return;
} }
auto f = [depth](auto const& e) auto f = [depth](auto const& e) {
{ return e.depth == depth; }; return e.depth == depth;
};
auto match = std::find_if(std::next(std::cbegin(r.value())), std::cend(r.value()), f); auto match = std::find_if(std::next(std::cbegin(r.value())), std::cend(r.value()), f);
@@ -45,4 +46,4 @@ void consume_one(generic_response& r)
throw system::system_error(ec); throw system::system_error(ec);
} }
} // boost::redis::resp3 } // namespace boost::redis

View File

@@ -8,10 +8,14 @@
#define BOOST_REDIS_LOGGER_HPP #define BOOST_REDIS_LOGGER_HPP
#include <boost/redis/response.hpp> #include <boost/redis/response.hpp>
#include <boost/asio/ip/tcp.hpp> #include <boost/asio/ip/tcp.hpp>
#include <string> #include <string>
namespace boost::system {class error_code;} namespace boost::system {
class error_code;
}
namespace boost::redis { namespace boost::redis {
@@ -66,7 +70,7 @@ public:
*/ */
logger(level l = level::debug) logger(level l = level::debug)
: level_{l} : level_{l}
{} { }
/** @brief Called when the resolve operation completes. /** @brief Called when the resolve operation completes.
* @ingroup high-level-api * @ingroup high-level-api
@@ -120,10 +124,7 @@ public:
* *
* @param prefix The prefix. * @param prefix The prefix.
*/ */
void set_prefix(std::string_view prefix) void set_prefix(std::string_view prefix) { prefix_ = prefix; }
{
prefix_ = prefix;
}
void trace(std::string_view message); void trace(std::string_view message);
void trace(std::string_view op, system::error_code const& ec); void trace(std::string_view op, system::error_code const& ec);
@@ -134,6 +135,6 @@ private:
std::string_view prefix_; std::string_view prefix_;
}; };
} // boost::redis } // namespace boost::redis
#endif // BOOST_REDIS_LOGGER_HPP #endif // BOOST_REDIS_LOGGER_HPP

View File

@@ -15,7 +15,8 @@ namespace boost::redis {
* The operations listed below can be passed to the * The operations listed below can be passed to the
* `boost::redis::connection::cancel` member function. * `boost::redis::connection::cancel` member function.
*/ */
enum class operation { enum class operation
{
/// Resolve operation. /// Resolve operation.
resolve, resolve,
/// Connect operation. /// Connect operation.
@@ -36,6 +37,6 @@ enum class operation {
all, all,
}; };
} // boost::redis } // namespace boost::redis
#endif // BOOST_REDIS_OPERATION_HPP #endif // BOOST_REDIS_OPERATION_HPP

View File

@@ -7,19 +7,19 @@
#ifndef BOOST_REDIS_REQUEST_HPP #ifndef BOOST_REDIS_REQUEST_HPP
#define BOOST_REDIS_REQUEST_HPP #define BOOST_REDIS_REQUEST_HPP
#include <boost/redis/resp3/type.hpp>
#include <boost/redis/resp3/serialization.hpp> #include <boost/redis/resp3/serialization.hpp>
#include <boost/redis/resp3/type.hpp>
#include <algorithm>
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <algorithm>
// NOTE: For some commands like hset it would be a good idea to assert // NOTE: For some commands like hset it would be a good idea to assert
// the value type is a pair. // the value type is a pair.
namespace boost::redis { namespace boost::redis {
namespace detail{ namespace detail {
auto has_response(std::string_view cmd) -> bool; auto has_response(std::string_view cmd) -> bool;
} }
@@ -80,23 +80,25 @@ public:
* *
* \param cfg Configuration options. * \param cfg Configuration options.
*/ */
explicit explicit request(config cfg = config{true, false, true, true})
request(config cfg = config{true, false, true, true}) : cfg_{cfg}
: cfg_{cfg} {} { }
//// Returns the number of responses expected for this request. //// Returns the number of responses expected for this request.
[[nodiscard]] auto get_expected_responses() const noexcept -> std::size_t [[nodiscard]] auto get_expected_responses() const noexcept -> std::size_t
{ return expected_responses_;}; {
return expected_responses_;
};
//// Returns the number of commands contained in this request. //// Returns the number of commands contained in this request.
[[nodiscard]] auto get_commands() const noexcept -> std::size_t [[nodiscard]] auto get_commands() const noexcept -> std::size_t { return commands_; };
{ return commands_;};
[[nodiscard]] auto payload() const noexcept -> std::string_view [[nodiscard]] auto payload() const noexcept -> std::string_view { return payload_; }
{ return payload_;}
[[nodiscard]] auto has_hello_priority() const noexcept -> auto const& [[nodiscard]] auto has_hello_priority() const noexcept -> auto const&
{ return has_hello_priority_;} {
return has_hello_priority_;
}
/// Clears the request preserving allocated memory. /// Clears the request preserving allocated memory.
void clear() void clear()
@@ -108,14 +110,13 @@ public:
} }
/// Calls std::string::reserve on the internal storage. /// Calls std::string::reserve on the internal storage.
void reserve(std::size_t new_cap = 0) void reserve(std::size_t new_cap = 0) { payload_.reserve(new_cap); }
{ payload_.reserve(new_cap); }
/// Returns a const reference to the config object. /// Returns a const reference to the config object.
[[nodiscard]] auto get_config() const noexcept -> auto const& {return cfg_; } [[nodiscard]] auto get_config() const noexcept -> auto const& { return cfg_; }
/// Returns a reference to the config object. /// Returns a reference to the config object.
[[nodiscard]] auto get_config() noexcept -> auto& {return cfg_; } [[nodiscard]] auto get_config() noexcept -> auto& { return cfg_; }
/** @brief Appends a new command to the end of the request. /** @brief Appends a new command to the end of the request.
* *
@@ -185,13 +186,12 @@ public:
* See cpp20_serialization.cpp * See cpp20_serialization.cpp
*/ */
template <class ForwardIterator> template <class ForwardIterator>
void void push_range(
push_range(
std::string_view const& cmd, std::string_view const& cmd,
std::string_view const& key, std::string_view const& key,
ForwardIterator begin, ForwardIterator begin,
ForwardIterator end, ForwardIterator end,
typename std::iterator_traits<ForwardIterator>::value_type * = nullptr) typename std::iterator_traits<ForwardIterator>::value_type* = nullptr)
{ {
using value_type = typename std::iterator_traits<ForwardIterator>::value_type; using value_type = typename std::iterator_traits<ForwardIterator>::value_type;
@@ -205,7 +205,7 @@ public:
resp3::add_bulk(payload_, key); resp3::add_bulk(payload_, key);
for (; begin != end; ++begin) for (; begin != end; ++begin)
resp3::add_bulk(payload_, *begin); resp3::add_bulk(payload_, *begin);
check_cmd(cmd); check_cmd(cmd);
} }
@@ -238,12 +238,11 @@ public:
* See cpp20_serialization.cpp * See cpp20_serialization.cpp
*/ */
template <class ForwardIterator> template <class ForwardIterator>
void void push_range(
push_range(
std::string_view const& cmd, std::string_view const& cmd,
ForwardIterator begin, ForwardIterator begin,
ForwardIterator end, ForwardIterator end,
typename std::iterator_traits<ForwardIterator>::value_type * = nullptr) typename std::iterator_traits<ForwardIterator>::value_type* = nullptr)
{ {
using value_type = typename std::iterator_traits<ForwardIterator>::value_type; using value_type = typename std::iterator_traits<ForwardIterator>::value_type;
@@ -256,7 +255,7 @@ public:
resp3::add_bulk(payload_, cmd); resp3::add_bulk(payload_, cmd);
for (; begin != end; ++begin) for (; begin != end; ++begin)
resp3::add_bulk(payload_, *begin); resp3::add_bulk(payload_, *begin);
check_cmd(cmd); check_cmd(cmd);
} }
@@ -272,12 +271,11 @@ public:
* \tparam A type that can be passed to `std::cbegin()` and `std::cend()`. * \tparam A type that can be passed to `std::cbegin()` and `std::cend()`.
*/ */
template <class Range> template <class Range>
void void push_range(
push_range(
std::string_view const& cmd, std::string_view const& cmd,
std::string_view const& key, std::string_view const& key,
Range const& range, Range const& range,
decltype(std::begin(range)) * = nullptr) decltype(std::begin(range))* = nullptr)
{ {
using std::begin; using std::begin;
using std::end; using std::end;
@@ -294,11 +292,10 @@ public:
* \tparam A type that can be passed to `std::cbegin()` and `std::cend()`. * \tparam A type that can be passed to `std::cbegin()` and `std::cend()`.
*/ */
template <class Range> template <class Range>
void void push_range(
push_range(
std::string_view cmd, std::string_view cmd,
Range const& range, Range const& range,
decltype(std::cbegin(range)) * = nullptr) decltype(std::cbegin(range))* = nullptr)
{ {
using std::cbegin; using std::cbegin;
using std::cend; using std::cend;
@@ -324,6 +321,6 @@ private:
bool has_hello_priority_ = false; bool has_hello_priority_ = false;
}; };
} // boost::redis::resp3 } // namespace boost::redis
#endif // BOOST_REDIS_REQUEST_HPP #endif // BOOST_REDIS_REQUEST_HPP

View File

@@ -4,8 +4,9 @@
* accompanying file LICENSE.txt) * accompanying file LICENSE.txt)
*/ */
#include <boost/redis/resp3/parser.hpp>
#include <boost/redis/error.hpp> #include <boost/redis/error.hpp>
#include <boost/redis/resp3/parser.hpp>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <charconv> #include <charconv>
@@ -20,10 +21,7 @@ void to_int(std::size_t& i, std::string_view sv, system::error_code& ec)
ec = error::not_a_number; ec = error::not_a_number;
} }
parser::parser() parser::parser() { reset(); }
{
reset();
}
void parser::reset() void parser::reset()
{ {
@@ -32,11 +30,10 @@ void parser::reset()
bulk_length_ = (std::numeric_limits<std::size_t>::max)(); bulk_length_ = (std::numeric_limits<std::size_t>::max)();
bulk_ = type::invalid; bulk_ = type::invalid;
consumed_ = 0; consumed_ = 0;
sizes_[0] = 2; // The sentinel must be more than 1. sizes_[0] = 2; // The sentinel must be more than 1.
} }
std::size_t std::size_t parser::get_suggested_buffer_growth(std::size_t hint) const noexcept
parser::get_suggested_buffer_growth(std::size_t hint) const noexcept
{ {
if (!bulk_expected()) if (!bulk_expected())
return hint; return hint;
@@ -47,20 +44,14 @@ parser::get_suggested_buffer_growth(std::size_t hint) const noexcept
return hint; return hint;
} }
std::size_t std::size_t parser::get_consumed() const noexcept { return consumed_; }
parser::get_consumed() const noexcept
{
return consumed_;
}
bool bool parser::done() const noexcept
parser::done() const noexcept
{ {
return depth_ == 0 && bulk_ == type::invalid && consumed_ != 0; return depth_ == 0 && bulk_ == type::invalid && consumed_ != 0;
} }
void void parser::commit_elem() noexcept
parser::commit_elem() noexcept
{ {
--sizes_[depth_]; --sizes_[depth_];
while (sizes_[depth_] == 0) { while (sizes_[depth_] == 0) {
@@ -69,15 +60,14 @@ parser::commit_elem() noexcept
} }
} }
auto auto parser::consume(std::string_view view, system::error_code& ec) noexcept -> parser::result
parser::consume(std::string_view view, system::error_code& ec) noexcept -> parser::result
{ {
switch (bulk_) { switch (bulk_) {
case type::invalid: case type::invalid:
{ {
auto const pos = view.find(sep, consumed_); auto const pos = view.find(sep, consumed_);
if (pos == std::string::npos) if (pos == std::string::npos)
return {}; // Needs more data to proceeed. return {}; // Needs more data to proceeed.
auto const t = to_type(view.at(consumed_)); auto const t = to_type(view.at(consumed_));
auto const content = view.substr(consumed_ + 1, pos - 1 - consumed_); auto const content = view.substr(consumed_ + 1, pos - 1 - consumed_);
@@ -88,14 +78,14 @@ parser::consume(std::string_view view, system::error_code& ec) noexcept -> parse
consumed_ = pos + 2; consumed_ = pos + 2;
if (!bulk_expected()) if (!bulk_expected())
return ret; return ret;
}
[[fallthrough]];
} [[fallthrough]]; default: // Handles bulk.
default: // Handles bulk.
{ {
auto const span = bulk_length_ + 2; auto const span = bulk_length_ + 2;
if ((std::size(view) - consumed_) < span) if ((std::size(view) - consumed_) < span)
return {}; // Needs more data to proceeed. return {}; // Needs more data to proceeed.
auto const bulk_view = view.substr(consumed_, bulk_length_); auto const bulk_view = view.substr(consumed_, bulk_length_);
node_type const ret = {bulk_, 1, depth_, bulk_view}; node_type const ret = {bulk_, 1, depth_, bulk_view};
@@ -108,11 +98,8 @@ parser::consume(std::string_view view, system::error_code& ec) noexcept -> parse
} }
} }
auto auto parser::consume_impl(type t, std::string_view elem, system::error_code& ec)
parser::consume_impl( -> parser::node_type
type t,
std::string_view elem,
system::error_code& ec) -> parser::node_type
{ {
BOOST_ASSERT(!bulk_expected()); BOOST_ASSERT(!bulk_expected());
@@ -120,13 +107,13 @@ parser::consume_impl(
switch (t) { switch (t) {
case type::streamed_string_part: case type::streamed_string_part:
{ {
to_int(bulk_length_ , elem, ec); to_int(bulk_length_, elem, ec);
if (ec) if (ec)
return {}; return {};
if (bulk_length_ == 0) { if (bulk_length_ == 0) {
ret = {type::streamed_string_part, 1, depth_, {}}; ret = {type::streamed_string_part, 1, depth_, {}};
sizes_[depth_] = 1; // We are done. sizes_[depth_] = 1; // We are done.
bulk_ = type::invalid; bulk_ = type::invalid;
commit_elem(); commit_elem();
} else { } else {
@@ -145,7 +132,7 @@ parser::consume_impl(
sizes_[++depth_] = (std::numeric_limits<std::size_t>::max)(); sizes_[++depth_] = (std::numeric_limits<std::size_t>::max)();
ret = {type::streamed_string, 0, depth_, {}}; ret = {type::streamed_string, 0, depth_, {}};
} else { } else {
to_int(bulk_length_ , elem , ec); to_int(bulk_length_, elem, ec);
if (ec) if (ec)
return {}; return {};
@@ -155,13 +142,13 @@ parser::consume_impl(
case type::boolean: case type::boolean:
{ {
if (std::empty(elem)) { if (std::empty(elem)) {
ec = error::empty_field; ec = error::empty_field;
return {}; return {};
} }
if (elem.at(0) != 'f' && elem.at(0) != 't') { if (elem.at(0) != 'f' && elem.at(0) != 't') {
ec = error::unexpected_bool_value; ec = error::unexpected_bool_value;
return {}; return {};
} }
ret = {t, 1, depth_, elem}; ret = {t, 1, depth_, elem};
@@ -172,10 +159,11 @@ parser::consume_impl(
case type::number: case type::number:
{ {
if (std::empty(elem)) { if (std::empty(elem)) {
ec = error::empty_field; ec = error::empty_field;
return {}; return {};
} }
} [[fallthrough]]; }
[[fallthrough]];
case type::simple_error: case type::simple_error:
case type::simple_string: case type::simple_string:
case type::null: case type::null:
@@ -217,4 +205,4 @@ parser::consume_impl(
return ret; return ret;
} }
} // boost::redis::resp3 } // namespace boost::redis::resp3

View File

@@ -4,8 +4,8 @@
* accompanying file LICENSE.txt) * accompanying file LICENSE.txt)
*/ */
#include <boost/redis/resp3/serialization.hpp>
#include <boost/redis/resp3/parser.hpp> #include <boost/redis/resp3/parser.hpp>
#include <boost/redis/resp3/serialization.hpp>
namespace boost::redis::resp3 { namespace boost::redis::resp3 {
@@ -35,8 +35,5 @@ void add_blob(std::string& payload, std::string_view blob)
payload += parser::sep; payload += parser::sep;
} }
void add_separator(std::string& payload) void add_separator(std::string& payload) { payload += parser::sep; }
{ } // namespace boost::redis::resp3
payload += parser::sep;
}
} // boost::redis::resp3

View File

@@ -5,6 +5,7 @@
*/ */
#include <boost/redis/resp3/type.hpp> #include <boost/redis/resp3/type.hpp>
#include <boost/assert.hpp> #include <boost/assert.hpp>
namespace boost::redis::resp3 { namespace boost::redis::resp3 {
@@ -12,24 +13,24 @@ namespace boost::redis::resp3 {
auto to_string(type t) noexcept -> char const* auto to_string(type t) noexcept -> char const*
{ {
switch (t) { switch (t) {
case type::array: return "array"; case type::array: return "array";
case type::push: return "push"; case type::push: return "push";
case type::set: return "set"; case type::set: return "set";
case type::map: return "map"; case type::map: return "map";
case type::attribute: return "attribute"; case type::attribute: return "attribute";
case type::simple_string: return "simple_string"; case type::simple_string: return "simple_string";
case type::simple_error: return "simple_error"; case type::simple_error: return "simple_error";
case type::number: return "number"; case type::number: return "number";
case type::doublean: return "doublean"; case type::doublean: return "doublean";
case type::boolean: return "boolean"; case type::boolean: return "boolean";
case type::big_number: return "big_number"; case type::big_number: return "big_number";
case type::null: return "null"; case type::null: return "null";
case type::blob_error: return "blob_error"; case type::blob_error: return "blob_error";
case type::verbatim_string: return "verbatim_string"; case type::verbatim_string: return "verbatim_string";
case type::blob_string: return "blob_string"; case type::blob_string: return "blob_string";
case type::streamed_string: return "streamed_string"; case type::streamed_string: return "streamed_string";
case type::streamed_string_part: return "streamed_string_part"; case type::streamed_string_part: return "streamed_string_part";
default: return "invalid"; default: return "invalid";
} }
} }
@@ -39,4 +40,4 @@ auto operator<<(std::ostream& os, type t) -> std::ostream&
return os; return os;
} }
} // boost::redis::resp3 } // namespace boost::redis::resp3

View File

@@ -48,10 +48,12 @@ struct basic_node {
template <class String> template <class String>
auto operator==(basic_node<String> const& a, basic_node<String> const& b) auto operator==(basic_node<String> const& a, basic_node<String> const& b)
{ {
// clang-format off
return a.aggregate_size == b.aggregate_size return a.aggregate_size == b.aggregate_size
&& a.depth == b.depth && a.depth == b.depth
&& a.data_type == b.data_type && a.data_type == b.data_type
&& a.value == b.value; && a.value == b.value;
// clang-format on
}; };
/** @brief A node in the response tree that owns its data /** @brief A node in the response tree that owns its data
@@ -64,6 +66,6 @@ using node = basic_node<std::string>;
*/ */
using node_view = basic_node<std::string_view>; using node_view = basic_node<std::string_view>;
} // boost::redis::resp3 } // namespace boost::redis::resp3
#endif // BOOST_REDIS_RESP3_NODE_HPP #endif // BOOST_REDIS_RESP3_NODE_HPP

View File

@@ -8,11 +8,13 @@
#define BOOST_REDIS_RESP3_PARSER_HPP #define BOOST_REDIS_RESP3_PARSER_HPP
#include <boost/redis/resp3/node.hpp> #include <boost/redis/resp3/node.hpp>
#include <boost/system/error_code.hpp> #include <boost/system/error_code.hpp>
#include <array> #include <array>
#include <string_view>
#include <cstdint> #include <cstdint>
#include <optional> #include <optional>
#include <string_view>
namespace boost::redis::resp3 { namespace boost::redis::resp3 {
@@ -54,7 +56,9 @@ private:
// returns type::invalid. // returns type::invalid.
[[nodiscard]] [[nodiscard]]
auto bulk_expected() const noexcept -> bool auto bulk_expected() const noexcept -> bool
{ return bulk_ != type::invalid; } {
return bulk_ != type::invalid;
}
public: public:
parser(); parser();
@@ -76,12 +80,7 @@ public:
// parser is either done or an error occured, that can be checked on // parser is either done or an error occured, that can be checked on
// ec. // ec.
template <class Adapter> template <class Adapter>
bool bool parse(resp3::parser& p, std::string_view const& msg, Adapter& adapter, system::error_code& ec)
parse(
resp3::parser& p,
std::string_view const& msg,
Adapter& adapter,
system::error_code& ec)
{ {
while (!p.done()) { while (!p.done()) {
auto const res = p.consume(msg, ec); auto const res = p.consume(msg, ec);
@@ -99,6 +98,6 @@ parse(
return true; return true;
} }
} // boost::redis::resp3 } // namespace boost::redis::resp3
#endif // BOOST_REDIS_RESP3_PARSER_HPP #endif // BOOST_REDIS_RESP3_PARSER_HPP

View File

@@ -7,10 +7,11 @@
#ifndef BOOST_REDIS_RESP3_SERIALIZATION_HPP #ifndef BOOST_REDIS_RESP3_SERIALIZATION_HPP
#define BOOST_REDIS_RESP3_SERIALIZATION_HPP #define BOOST_REDIS_RESP3_SERIALIZATION_HPP
#include <boost/redis/resp3/parser.hpp>
#include <boost/redis/resp3/type.hpp> #include <boost/redis/resp3/type.hpp>
#include <boost/system/system_error.hpp> #include <boost/system/system_error.hpp>
#include <boost/throw_exception.hpp> #include <boost/throw_exception.hpp>
#include <boost/redis/resp3/parser.hpp>
#include <string> #include <string>
#include <tuple> #include <tuple>
@@ -57,12 +58,11 @@ struct add_bulk_impl {
} }
}; };
template <class ...Ts> template <class... Ts>
struct add_bulk_impl<std::tuple<Ts...>> { struct add_bulk_impl<std::tuple<Ts...>> {
static void add(std::string& payload, std::tuple<Ts...> const& t) static void add(std::string& payload, std::tuple<Ts...> const& t)
{ {
auto f = [&](auto const&... vs) auto f = [&](auto const&... vs) {
{
using namespace boost::redis::resp3; using namespace boost::redis::resp3;
(boost_redis_to_bulk(payload, vs), ...); (boost_redis_to_bulk(payload, vs), ...);
}; };
@@ -94,19 +94,18 @@ struct bulk_counter;
template <class> template <class>
struct bulk_counter { struct bulk_counter {
static constexpr auto size = 1U; static constexpr auto size = 1U;
}; };
template <class T, class U> template <class T, class U>
struct bulk_counter<std::pair<T, U>> { struct bulk_counter<std::pair<T, U>> {
static constexpr auto size = 2U; static constexpr auto size = 2U;
}; };
void add_blob(std::string& payload, std::string_view blob); void add_blob(std::string& payload, std::string_view blob);
void add_separator(std::string& payload); void add_separator(std::string& payload);
namespace detail namespace detail {
{
template <class Adapter> template <class Adapter>
void deserialize(std::string_view const& data, Adapter adapter, system::error_code& ec) void deserialize(std::string_view const& data, Adapter adapter, system::error_code& ec)
@@ -134,11 +133,11 @@ void deserialize(std::string_view const& data, Adapter adapter)
deserialize(data, adapter, ec); deserialize(data, adapter, ec);
if (ec) if (ec)
BOOST_THROW_EXCEPTION(system::system_error{ec}); BOOST_THROW_EXCEPTION(system::system_error{ec});
} }
} } // namespace detail
} // boost::redis::resp3 } // namespace boost::redis::resp3
#endif // BOOST_REDIS_RESP3_SERIALIZATION_HPP #endif // BOOST_REDIS_RESP3_SERIALIZATION_HPP

View File

@@ -8,9 +8,10 @@
#define BOOST_REDIS_RESP3_TYPE_HPP #define BOOST_REDIS_RESP3_TYPE_HPP
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <ostream> #include <ostream>
#include <vector>
#include <string> #include <string>
#include <vector>
namespace boost::redis::resp3 { namespace boost::redis::resp3 {
@@ -20,42 +21,42 @@ namespace boost::redis::resp3 {
The RESP3 specification can be found at https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md. The RESP3 specification can be found at https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md.
*/ */
enum class type enum class type
{ /// Aggregate { /// Aggregate
array, array,
/// Aaggregate /// Aaggregate
push, push,
/// Aggregate /// Aggregate
set, set,
/// Aggregate /// Aggregate
map, map,
/// Aggregate /// Aggregate
attribute, attribute,
/// Simple /// Simple
simple_string, simple_string,
/// Simple /// Simple
simple_error, simple_error,
/// Simple /// Simple
number, number,
/// Simple /// Simple
doublean, doublean,
/// Simple /// Simple
boolean, boolean,
/// Simple /// Simple
big_number, big_number,
/// Simple /// Simple
null, null,
/// Simple /// Simple
blob_error, blob_error,
/// Simple /// Simple
verbatim_string, verbatim_string,
/// Simple /// Simple
blob_string, blob_string,
/// Simple /// Simple
streamed_string, streamed_string,
/// Simple /// Simple
streamed_string_part, streamed_string_part,
/// Invalid /// Invalid
invalid invalid
}; };
/** \brief Converts the data type to a string. /** \brief Converts the data type to a string.
@@ -81,7 +82,7 @@ constexpr auto is_aggregate(type t) noexcept -> bool
case type::set: case type::set:
case type::map: case type::map:
case type::attribute: return true; case type::attribute: return true;
default: return false; default: return false;
} }
} }
@@ -92,7 +93,7 @@ constexpr auto element_multiplicity(type t) noexcept -> std::size_t
switch (t) { switch (t) {
case type::map: case type::map:
case type::attribute: return 2ULL; case type::attribute: return 2ULL;
default: return 1ULL; default: return 1ULL;
} }
} }
@@ -141,10 +142,10 @@ constexpr auto to_type(char c) noexcept -> type
case '*': return type::array; case '*': return type::array;
case '|': return type::attribute; case '|': return type::attribute;
case '%': return type::map; case '%': return type::map;
default: return type::invalid; default: return type::invalid;
} }
} }
} // boost::redis::resp3 } // namespace boost::redis::resp3
#endif // BOOST_REDIS_RESP3_TYPE_HPP #endif // BOOST_REDIS_RESP3_TYPE_HPP

View File

@@ -7,16 +7,16 @@
#ifndef BOOST_REDIS_RESPONSE_HPP #ifndef BOOST_REDIS_RESPONSE_HPP
#define BOOST_REDIS_RESPONSE_HPP #define BOOST_REDIS_RESPONSE_HPP
#include <boost/redis/resp3/node.hpp>
#include <boost/redis/adapter/result.hpp> #include <boost/redis/adapter/result.hpp>
#include <boost/redis/resp3/node.hpp>
#include <boost/system.hpp> #include <boost/system.hpp>
#include <vector>
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <vector>
namespace boost::redis namespace boost::redis {
{
/** @brief Response with compile-time size. /** @brief Response with compile-time size.
* @ingroup high-level-api * @ingroup high-level-api
@@ -75,6 +75,6 @@ void consume_one(generic_response& r, system::error_code& ec);
/// Throwing overload of `consume_one`. /// Throwing overload of `consume_one`.
void consume_one(generic_response& r); void consume_one(generic_response& r);
} // boost::redis } // namespace boost::redis
#endif // BOOST_REDIS_RESPONSE_HPP #endif // BOOST_REDIS_RESPONSE_HPP

View File

@@ -4,14 +4,14 @@
* accompanying file LICENSE.txt) * accompanying file LICENSE.txt)
*/ */
#include <boost/redis/impl/error.ipp>
#include <boost/redis/impl/logger.ipp>
#include <boost/redis/impl/request.ipp>
#include <boost/redis/impl/ignore.ipp>
#include <boost/redis/impl/connection.ipp> #include <boost/redis/impl/connection.ipp>
#include <boost/redis/impl/response.ipp> #include <boost/redis/impl/error.ipp>
#include <boost/redis/impl/resp3_handshaker.ipp> #include <boost/redis/impl/ignore.ipp>
#include <boost/redis/impl/logger.ipp>
#include <boost/redis/impl/multiplexer.ipp> #include <boost/redis/impl/multiplexer.ipp>
#include <boost/redis/resp3/impl/type.ipp> #include <boost/redis/impl/request.ipp>
#include <boost/redis/impl/resp3_handshaker.ipp>
#include <boost/redis/impl/response.ipp>
#include <boost/redis/resp3/impl/parser.ipp> #include <boost/redis/resp3/impl/parser.ipp>
#include <boost/redis/resp3/impl/serialization.ipp> #include <boost/redis/resp3/impl/serialization.ipp>
#include <boost/redis/resp3/impl/type.ipp>

View File

@@ -7,8 +7,7 @@
#ifndef BOOST_REDIS_USAGE_HPP #ifndef BOOST_REDIS_USAGE_HPP
#define BOOST_REDIS_USAGE_HPP #define BOOST_REDIS_USAGE_HPP
namespace boost::redis namespace boost::redis {
{
/** @brief Connection usage information. /** @brief Connection usage information.
* @ingroup high-level-api * @ingroup high-level-api
@@ -38,6 +37,6 @@ struct usage {
std::size_t push_bytes_received = 0; std::size_t push_bytes_received = 0;
}; };
} // boost::redis } // namespace boost::redis
#endif // BOOST_REDIS_USAGE_HPP #endif // BOOST_REDIS_USAGE_HPP

View File

@@ -4,12 +4,11 @@
* accompanying file LICENSE.txt) * accompanying file LICENSE.txt)
*/ */
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/redis/src.hpp> #include <boost/redis/src.hpp>
int main() int main()
{ {
boost::redis::connection conn(boost::asio::system_executor{}); boost::redis::connection conn(boost::asio::system_executor{});
return static_cast<int>(!conn.will_reconnect()); return static_cast<int>(!conn.will_reconnect());
} }

View File

@@ -4,12 +4,11 @@
* accompanying file LICENSE.txt) * accompanying file LICENSE.txt)
*/ */
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/redis/src.hpp> #include <boost/redis/src.hpp>
int main() int main()
{ {
boost::redis::connection conn(boost::asio::system_executor{}); boost::redis::connection conn(boost::asio::system_executor{});
return static_cast<int>(!conn.will_reconnect()); return static_cast<int>(!conn.will_reconnect());
} }

View File

@@ -4,12 +4,11 @@
* accompanying file LICENSE.txt) * accompanying file LICENSE.txt)
*/ */
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/redis/src.hpp> #include <boost/redis/src.hpp>
int main() int main()
{ {
boost::redis::connection conn(boost::asio::system_executor{}); boost::redis::connection conn(boost::asio::system_executor{});
return static_cast<int>(!conn.will_reconnect()); return static_cast<int>(!conn.will_reconnect());
} }

View File

@@ -1,8 +1,10 @@
#include "common.hpp"
#include <iostream>
#include <cstdlib>
#include <boost/asio/consign.hpp>
#include <boost/asio/co_spawn.hpp> #include <boost/asio/co_spawn.hpp>
#include <boost/asio/consign.hpp>
#include "common.hpp"
#include <cstdlib>
#include <iostream>
namespace net = boost::asio; namespace net = boost::asio;
@@ -18,8 +20,7 @@ struct run_callback {
} }
}; };
void void run(
run(
std::shared_ptr<boost::redis::connection> conn, std::shared_ptr<boost::redis::connection> conn,
boost::redis::config cfg, boost::redis::config cfg,
boost::system::error_code ec, boost::system::error_code ec,
@@ -31,22 +32,19 @@ run(
static std::string safe_getenv(const char* name, const char* default_value) static std::string safe_getenv(const char* name, const char* default_value)
{ {
// MSVC doesn't like getenv // MSVC doesn't like getenv
#ifdef BOOST_MSVC #ifdef BOOST_MSVC
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4996) #pragma warning(disable : 4996)
#endif #endif
const char* res = std::getenv(name); const char* res = std::getenv(name);
#ifdef BOOST_MSVC #ifdef BOOST_MSVC
#pragma warning(pop) #pragma warning(pop)
#endif #endif
return res ? res : default_value; return res ? res : default_value;
} }
std::string get_server_hostname() std::string get_server_hostname() { return safe_getenv("BOOST_REDIS_TEST_SERVER", "localhost"); }
{
return safe_getenv("BOOST_REDIS_TEST_SERVER", "localhost");
}
boost::redis::config make_test_config() boost::redis::config make_test_config()
{ {
@@ -75,4 +73,4 @@ auto start(net::awaitable<void> op) -> int
return 1; return 1;
} }
#endif // BOOST_ASIO_HAS_CO_AWAIT #endif // BOOST_ASIO_HAS_CO_AWAIT

View File

@@ -1,28 +1,29 @@
#pragma once #pragma once
#include <boost/system/error_code.hpp>
#include <boost/asio/redirect_error.hpp>
#include <boost/asio/awaitable.hpp>
#include <boost/asio/use_awaitable.hpp>
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/redis/operation.hpp> #include <boost/redis/operation.hpp>
#include <boost/asio/awaitable.hpp>
#include <boost/asio/redirect_error.hpp>
#include <boost/asio/use_awaitable.hpp>
#include <boost/system/error_code.hpp>
#include <memory> #include <memory>
#ifdef BOOST_ASIO_HAS_CO_AWAIT #ifdef BOOST_ASIO_HAS_CO_AWAIT
inline inline auto redir(boost::system::error_code& ec)
auto redir(boost::system::error_code& ec) {
{ return boost::asio::redirect_error(boost::asio::use_awaitable, ec); } return boost::asio::redirect_error(boost::asio::use_awaitable, ec);
}
auto start(boost::asio::awaitable<void> op) -> int; auto start(boost::asio::awaitable<void> op) -> int;
#endif // BOOST_ASIO_HAS_CO_AWAIT #endif // BOOST_ASIO_HAS_CO_AWAIT
boost::redis::config make_test_config(); boost::redis::config make_test_config();
std::string get_server_hostname(); std::string get_server_hostname();
void void run(
run(
std::shared_ptr<boost::redis::connection> conn, std::shared_ptr<boost::redis::connection> conn,
boost::redis::config cfg = make_test_config(), boost::redis::config cfg = make_test_config(),
boost::system::error_code ec = boost::asio::error::operation_aborted, boost::system::error_code ec = boost::asio::error::operation_aborted,
boost::redis::operation op = boost::redis::operation::receive, boost::redis::operation op = boost::redis::operation::receive,
boost::redis::logger::level l = boost::redis::logger::level::debug); boost::redis::logger::level l = boost::redis::logger::level::debug);

View File

@@ -4,9 +4,10 @@
* accompanying file LICENSE.txt) * accompanying file LICENSE.txt)
*/ */
#include <boost/redis/adapter/any_adapter.hpp>
#include <boost/redis/ignore.hpp> #include <boost/redis/ignore.hpp>
#include <boost/redis/response.hpp> #include <boost/redis/response.hpp>
#include <boost/redis/adapter/any_adapter.hpp>
#include <string> #include <string>
#define BOOST_TEST_MODULE any_adapter #define BOOST_TEST_MODULE any_adapter
#include <boost/test/included/unit_test.hpp> #include <boost/test/included/unit_test.hpp>
@@ -33,17 +34,17 @@ BOOST_AUTO_TEST_CASE(any_adapter_copy_move)
{ {
// any_adapter can be copied/moved // any_adapter can be copied/moved
response<int, std::string> r; response<int, std::string> r;
any_adapter ad1 {r}; any_adapter ad1{r};
// copy constructor // copy constructor
any_adapter ad2 {ad1}; any_adapter ad2{ad1};
// move constructor // move constructor
any_adapter ad3 {std::move(ad2)}; any_adapter ad3{std::move(ad2)};
// copy assignment // copy assignment
BOOST_CHECK_NO_THROW(ad2 = ad1); BOOST_CHECK_NO_THROW(ad2 = ad1);
// move assignment // move assignment
BOOST_CHECK_NO_THROW(ad2 = std::move(ad1)); BOOST_CHECK_NO_THROW(ad2 = std::move(ad1));
} }

View File

@@ -6,12 +6,15 @@
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/redis/response.hpp> #include <boost/redis/response.hpp>
#include <boost/system/errc.hpp> #include <boost/system/errc.hpp>
#define BOOST_TEST_MODULE check-health #define BOOST_TEST_MODULE check_health
#include <boost/test/included/unit_test.hpp> #include <boost/test/included/unit_test.hpp>
#include "common.hpp"
#include <iostream> #include <iostream>
#include <thread> #include <thread>
#include "common.hpp"
namespace net = boost::asio; namespace net = boost::asio;
namespace redis = boost::redis; namespace redis = boost::redis;
@@ -23,7 +26,7 @@ using boost::redis::operation;
using boost::redis::generic_response; using boost::redis::generic_response;
using boost::redis::consume_one; using boost::redis::consume_one;
// TODO: Test cancel(health_check) // TODO: Test cancel(health_check)
struct push_callback { struct push_callback {
connection* conn1; connection* conn1;
@@ -35,7 +38,7 @@ struct push_callback {
void operator()(error_code ec = {}, std::size_t = 0) void operator()(error_code ec = {}, std::size_t = 0)
{ {
BOOST_ASIO_CORO_REENTER (coro) for (;;) BOOST_ASIO_CORO_REENTER(coro) for (;;)
{ {
BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD
conn2->async_receive(*this); conn2->async_receive(*this);
@@ -94,7 +97,7 @@ BOOST_AUTO_TEST_CASE(check_health)
auto cfg2 = make_test_config(); auto cfg2 = make_test_config();
cfg2.health_check_id = "conn2"; cfg2.health_check_id = "conn2";
error_code res2; error_code res2;
conn2.async_run(cfg2, {}, [&](auto ec){ conn2.async_run(cfg2, {}, [&](auto ec) {
std::cout << "async_run 2 completed: " << ec.message() << std::endl; std::cout << "async_run 2 completed: " << ec.message() << std::endl;
res2 = ec; res2 = ec;
}); });
@@ -110,8 +113,8 @@ BOOST_AUTO_TEST_CASE(check_health)
}); });
//-------------------------------- //--------------------------------
push_callback{&conn1, &conn2, &resp2, &req1}(); // Starts reading pushes. push_callback{&conn1, &conn2, &resp2, &req1}(); // Starts reading pushes.
ioc.run(); ioc.run();
@@ -122,4 +125,3 @@ BOOST_AUTO_TEST_CASE(check_health)
// to fail. // to fail.
std::this_thread::sleep_for(std::chrono::seconds{10}); std::this_thread::sleep_for(std::chrono::seconds{10});
} }

View File

@@ -5,15 +5,18 @@
*/ */
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/asio/co_spawn.hpp> #include <boost/asio/co_spawn.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/deferred.hpp> #include <boost/asio/deferred.hpp>
#include <boost/asio/detached.hpp>
#include <boost/system/errc.hpp> #include <boost/system/errc.hpp>
#define BOOST_TEST_MODULE echo-stress #define BOOST_TEST_MODULE echo_stress
#include <boost/test/included/unit_test.hpp> #include <boost/test/included/unit_test.hpp>
#include <iostream>
#include "common.hpp" #include "common.hpp"
#include <iostream>
#ifdef BOOST_ASIO_HAS_CO_AWAIT #ifdef BOOST_ASIO_HAS_CO_AWAIT
namespace net = boost::asio; namespace net = boost::asio;
@@ -30,8 +33,7 @@ using boost::redis::error;
std::ostream& operator<<(std::ostream& os, usage const& u) std::ostream& operator<<(std::ostream& os, usage const& u)
{ {
os os << "Commands sent: " << u.commands_sent << "\n"
<< "Commands sent: " << u.commands_sent << "\n"
<< "Bytes sent: " << u.bytes_sent << "\n" << "Bytes sent: " << u.bytes_sent << "\n"
<< "Responses received: " << u.responses_received << "\n" << "Responses received: " << u.responses_received << "\n"
<< "Pushes received: " << u.pushes_received << "\n" << "Pushes received: " << u.pushes_received << "\n"
@@ -65,11 +67,8 @@ auto push_consumer(std::shared_ptr<connection> conn, int expected) -> net::await
conn->cancel(); conn->cancel();
} }
auto auto echo_session(std::shared_ptr<connection> conn, std::shared_ptr<request> pubs, int n)
echo_session( -> net::awaitable<void>
std::shared_ptr<connection> conn,
std::shared_ptr<request> pubs,
int n) -> net::awaitable<void>
{ {
for (auto i = 0; i < n; ++i) for (auto i = 0; i < n; ++i)
co_await conn->async_exec(*pubs, ignore, net::deferred); co_await conn->async_exec(*pubs, ignore, net::deferred);
@@ -80,10 +79,12 @@ auto async_echo_stress(std::shared_ptr<connection> conn) -> net::awaitable<void>
auto ex = co_await net::this_coro::executor; auto ex = co_await net::this_coro::executor;
auto cfg = make_test_config(); auto cfg = make_test_config();
cfg.health_check_interval = std::chrono::seconds::zero(); cfg.health_check_interval = std::chrono::seconds::zero();
run(conn, cfg, run(
boost::asio::error::operation_aborted, conn,
boost::redis::operation::receive, cfg,
boost::redis::logger::level::crit); boost::asio::error::operation_aborted,
boost::redis::operation::receive,
boost::redis::logger::level::crit);
request req; request req;
req.push("SUBSCRIBE", "channel"); req.push("SUBSCRIBE", "channel");
@@ -112,7 +113,7 @@ auto async_echo_stress(std::shared_ptr<connection> conn) -> net::awaitable<void>
// pushes have been received. // pushes have been received.
net::co_spawn(ex, push_consumer(conn, total_pushes), net::detached); net::co_spawn(ex, push_consumer(conn, total_pushes), net::detached);
for (int i = 0; i < sessions; ++i) for (int i = 0; i < sessions; ++i)
net::co_spawn(ex, echo_session(conn, pubs, msgs), net::detached); net::co_spawn(ex, echo_session(conn, pubs, msgs), net::detached);
} }
@@ -123,15 +124,9 @@ BOOST_AUTO_TEST_CASE(echo_stress)
net::co_spawn(ioc, async_echo_stress(conn), net::detached); net::co_spawn(ioc, async_echo_stress(conn), net::detached);
ioc.run(); ioc.run();
std::cout std::cout << "-------------------\n" << conn->get_usage() << std::endl;
<< "-------------------\n"
<< conn->get_usage()
<< std::endl;
} }
#else #else
BOOST_AUTO_TEST_CASE(dummy) BOOST_AUTO_TEST_CASE(dummy) { BOOST_TEST(true); }
{
BOOST_TEST(true);
}
#endif #endif

View File

@@ -6,14 +6,18 @@
#include <boost/redis/adapter/any_adapter.hpp> #include <boost/redis/adapter/any_adapter.hpp>
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/system/errc.hpp>
#include <boost/asio/detached.hpp> #include <boost/asio/detached.hpp>
#include <boost/system/errc.hpp>
#include <string> #include <string>
#define BOOST_TEST_MODULE conn-exec #define BOOST_TEST_MODULE conn_exec
#include <boost/test/included/unit_test.hpp> #include <boost/test/included/unit_test.hpp>
#include <iostream>
#include "common.hpp" #include "common.hpp"
#include <iostream>
// TODO: Test whether HELLO won't be inserted passt commands that have // TODO: Test whether HELLO won't be inserted passt commands that have
// been already writen. // been already writen.
// TODO: Test async_exec with empty request e.g. hgetall with an empty // TODO: Test async_exec with empty request e.g. hgetall with an empty
@@ -53,7 +57,7 @@ BOOST_AUTO_TEST_CASE(hello_priority)
bool seen2 = false; bool seen2 = false;
bool seen3 = false; bool seen3 = false;
conn->async_exec(req1, ignore, [&](auto ec, auto){ conn->async_exec(req1, ignore, [&](auto ec, auto) {
// Second callback to the called. // Second callback to the called.
std::cout << "req1" << std::endl; std::cout << "req1" << std::endl;
BOOST_TEST(!ec); BOOST_TEST(!ec);
@@ -62,7 +66,7 @@ BOOST_AUTO_TEST_CASE(hello_priority)
seen1 = true; seen1 = true;
}); });
conn->async_exec(req2, ignore, [&](auto ec, auto){ conn->async_exec(req2, ignore, [&](auto ec, auto) {
// Last callback to the called. // Last callback to the called.
std::cout << "req2" << std::endl; std::cout << "req2" << std::endl;
BOOST_TEST(!ec); BOOST_TEST(!ec);
@@ -73,7 +77,7 @@ BOOST_AUTO_TEST_CASE(hello_priority)
conn->cancel(operation::reconnection); conn->cancel(operation::reconnection);
}); });
conn->async_exec(req3, ignore, [&](auto ec, auto){ conn->async_exec(req3, ignore, [&](auto ec, auto) {
// Callback that will be called first. // Callback that will be called first.
std::cout << "req3" << std::endl; std::cout << "req3" << std::endl;
BOOST_TEST(!ec); BOOST_TEST(!ec);
@@ -98,7 +102,7 @@ BOOST_AUTO_TEST_CASE(wrong_response_data_type)
auto conn = std::make_shared<connection>(ioc); auto conn = std::make_shared<connection>(ioc);
conn->async_exec(req, resp, [conn](auto ec, auto){ conn->async_exec(req, resp, [conn](auto ec, auto) {
BOOST_CHECK_EQUAL(ec, boost::redis::error::not_a_number); BOOST_CHECK_EQUAL(ec, boost::redis::error::not_a_number);
conn->cancel(operation::reconnection); conn->cancel(operation::reconnection);
}); });
@@ -115,7 +119,7 @@ BOOST_AUTO_TEST_CASE(cancel_request_if_not_connected)
net::io_context ioc; net::io_context ioc;
auto conn = std::make_shared<connection>(ioc); auto conn = std::make_shared<connection>(ioc);
conn->async_exec(req, ignore, [conn](auto ec, auto){ conn->async_exec(req, ignore, [conn](auto ec, auto) {
BOOST_CHECK_EQUAL(ec, boost::redis::error::not_connected); BOOST_CHECK_EQUAL(ec, boost::redis::error::not_connected);
conn->cancel(); conn->cancel();
}); });
@@ -137,14 +141,14 @@ BOOST_AUTO_TEST_CASE(correct_database)
generic_response resp; generic_response resp;
conn->async_exec(req, resp, [&](auto ec, auto n){ conn->async_exec(req, resp, [&](auto ec, auto n) {
BOOST_TEST(!ec); BOOST_TEST(!ec);
std::clog << "async_exec has completed: " << n << std::endl; std::clog << "async_exec has completed: " << n << std::endl;
conn->cancel(); conn->cancel();
}); });
conn->async_run(cfg, {}, [](auto){ conn->async_run(cfg, {}, [](auto) {
std::clog << "async_run has exited." << std::endl; std::clog << "async_run has exited." << std::endl;
}); });
ioc.run(); ioc.run();
@@ -156,7 +160,7 @@ BOOST_AUTO_TEST_CASE(correct_database)
auto const index = std::stoi(index_str); auto const index = std::stoi(index_str);
// This check might fail if more than one client is connected to // This check might fail if more than one client is connected to
// redis when the CLIENT LIST command is run. // redis when the CLIENT LIST command is run.
BOOST_CHECK_EQUAL(cfg.database_index.value(), index); BOOST_CHECK_EQUAL(cfg.database_index.value(), index);
} }
@@ -204,7 +208,7 @@ BOOST_AUTO_TEST_CASE(exec_any_adapter)
auto conn = std::make_shared<connection>(ioc); auto conn = std::make_shared<connection>(ioc);
conn->async_exec(req, boost::redis::any_adapter(res), [&](auto ec, auto){ conn->async_exec(req, boost::redis::any_adapter(res), [&](auto ec, auto) {
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->cancel(); conn->cancel();
}); });
@@ -214,4 +218,3 @@ BOOST_AUTO_TEST_CASE(exec_any_adapter)
BOOST_TEST(std::get<0>(res).value() == "PONG"); BOOST_TEST(std::get<0>(res).value() == "PONG");
} }

View File

@@ -5,11 +5,14 @@
*/ */
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/system/errc.hpp> #include <boost/system/errc.hpp>
#define BOOST_TEST_MODULE conn-exec-cancel #define BOOST_TEST_MODULE conn_exec_cancel
#include <boost/test/included/unit_test.hpp>
#include <boost/asio/detached.hpp> #include <boost/asio/detached.hpp>
#include <boost/test/included/unit_test.hpp>
#include "common.hpp" #include "common.hpp"
#include <iostream> #include <iostream>
#ifdef BOOST_ASIO_HAS_CO_AWAIT #ifdef BOOST_ASIO_HAS_CO_AWAIT
@@ -57,10 +60,7 @@ auto implicit_cancel_of_req_written() -> net::awaitable<void>
// Achieves implicit cancellation when the timer fires. // Achieves implicit cancellation when the timer fires.
boost::system::error_code ec1, ec2; boost::system::error_code ec1, ec2;
co_await ( co_await (conn->async_exec(req1, ignore, redir(ec1)) || st.async_wait(redir(ec2)));
conn->async_exec(req1, ignore, redir(ec1)) ||
st.async_wait(redir(ec2))
);
conn->cancel(); conn->cancel();
@@ -92,13 +92,11 @@ BOOST_AUTO_TEST_CASE(test_cancel_of_req_written_on_run_canceled)
req1.get_config().cancel_if_unresponded = true; req1.get_config().cancel_if_unresponded = true;
req1.push("BLPOP", "any", 0); req1.push("BLPOP", "any", 0);
auto c1 = [&](auto ec, auto) auto c1 = [&](auto ec, auto) {
{
BOOST_CHECK_EQUAL(ec, net::error::operation_aborted); BOOST_CHECK_EQUAL(ec, net::error::operation_aborted);
}; };
auto c0 = [&](auto ec, auto) auto c0 = [&](auto ec, auto) {
{
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->async_exec(req1, ignore, c1); conn->async_exec(req1, ignore, c1);
}; };
@@ -111,7 +109,7 @@ BOOST_AUTO_TEST_CASE(test_cancel_of_req_written_on_run_canceled)
net::steady_timer st{ioc}; net::steady_timer st{ioc};
st.expires_after(std::chrono::seconds{1}); st.expires_after(std::chrono::seconds{1});
st.async_wait([&](auto ec){ st.async_wait([&](auto ec) {
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->cancel(operation::run); conn->cancel(operation::run);
conn->cancel(operation::reconnection); conn->cancel(operation::reconnection);
@@ -121,8 +119,5 @@ BOOST_AUTO_TEST_CASE(test_cancel_of_req_written_on_run_canceled)
} }
#else #else
BOOST_AUTO_TEST_CASE(dummy) BOOST_AUTO_TEST_CASE(dummy) { BOOST_TEST(true); }
{
BOOST_TEST(true);
}
#endif #endif

View File

@@ -5,11 +5,14 @@
*/ */
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/system/errc.hpp> #include <boost/system/errc.hpp>
#define BOOST_TEST_MODULE conn-exec-cancel #define BOOST_TEST_MODULE conn_exec_cancel
#include <boost/test/included/unit_test.hpp>
#include <boost/asio/detached.hpp> #include <boost/asio/detached.hpp>
#include <boost/test/included/unit_test.hpp>
#include "common.hpp" #include "common.hpp"
#include <iostream> #include <iostream>
#ifdef BOOST_ASIO_HAS_CO_AWAIT #ifdef BOOST_ASIO_HAS_CO_AWAIT
@@ -55,7 +58,7 @@ auto async_ignore_explicit_cancel_of_req_written() -> net::awaitable<void>
req1.push("BLPOP", "any", 3); req1.push("BLPOP", "any", 3);
bool seen = false; bool seen = false;
conn->async_exec(req1, gresp, [&](auto ec, auto) mutable{ conn->async_exec(req1, gresp, [&](auto ec, auto) mutable {
// No error should occur since the cancelation should be // No error should occur since the cancelation should be
// ignored. // ignored.
std::cout << "async_exec (1): " << ec.message() << std::endl; std::cout << "async_exec (1): " << ec.message() << std::endl;
@@ -90,8 +93,5 @@ BOOST_AUTO_TEST_CASE(test_ignore_explicit_cancel_of_req_written)
} }
#else #else
BOOST_AUTO_TEST_CASE(dummy) BOOST_AUTO_TEST_CASE(dummy) { BOOST_TEST(true); }
{
BOOST_TEST(true);
}
#endif #endif

View File

@@ -6,10 +6,13 @@
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/redis/logger.hpp> #include <boost/redis/logger.hpp>
#include <boost/system/errc.hpp> #include <boost/system/errc.hpp>
#define BOOST_TEST_MODULE conn-exec-error #define BOOST_TEST_MODULE conn_exec_error
#include <boost/test/included/unit_test.hpp> #include <boost/test/included/unit_test.hpp>
#include "common.hpp" #include "common.hpp"
#include <iostream> #include <iostream>
namespace net = boost::asio; namespace net = boost::asio;
@@ -38,7 +41,7 @@ BOOST_AUTO_TEST_CASE(no_ignore_error)
auto conn = std::make_shared<connection>(ioc); auto conn = std::make_shared<connection>(ioc);
conn->async_exec(req, ignore, [&](auto ec, auto){ conn->async_exec(req, ignore, [&](auto ec, auto) {
BOOST_CHECK_EQUAL(ec, error::resp3_simple_error); BOOST_CHECK_EQUAL(ec, error::resp3_simple_error);
conn->cancel(operation::run); conn->cancel(operation::run);
conn->cancel(operation::reconnection); conn->cancel(operation::reconnection);
@@ -65,7 +68,7 @@ BOOST_AUTO_TEST_CASE(has_diagnostic)
auto conn = std::make_shared<connection>(ioc); auto conn = std::make_shared<connection>(ioc);
response<std::string, std::string> resp; response<std::string, std::string> resp;
conn->async_exec(req, resp, [&](auto ec, auto){ conn->async_exec(req, resp, [&](auto ec, auto) {
BOOST_TEST(!ec); BOOST_TEST(!ec);
// HELLO // HELLO
@@ -93,8 +96,8 @@ BOOST_AUTO_TEST_CASE(resp3_error_in_cmd_pipeline)
request req1; request req1;
req1.push("HELLO", "3"); req1.push("HELLO", "3");
req1.push("PING", "req1-msg1"); req1.push("PING", "req1-msg1");
req1.push("PING", "req1-msg2", "extra arg"); // Error. req1.push("PING", "req1-msg2", "extra arg"); // Error.
req1.push("PING", "req1-msg3"); // Should run ok. req1.push("PING", "req1-msg3"); // Should run ok.
response<ignore_t, std::string, std::string, std::string> resp1; response<ignore_t, std::string, std::string, std::string> resp1;
@@ -106,8 +109,7 @@ BOOST_AUTO_TEST_CASE(resp3_error_in_cmd_pipeline)
net::io_context ioc; net::io_context ioc;
auto conn = std::make_shared<connection>(ioc); auto conn = std::make_shared<connection>(ioc);
auto c2 = [&](auto ec, auto) auto c2 = [&](auto ec, auto) {
{
BOOST_TEST(!ec); BOOST_TEST(!ec);
BOOST_TEST(std::get<0>(resp2).has_value()); BOOST_TEST(std::get<0>(resp2).has_value());
BOOST_CHECK_EQUAL(std::get<0>(resp2).value(), "req2-msg1"); BOOST_CHECK_EQUAL(std::get<0>(resp2).value(), "req2-msg1");
@@ -115,8 +117,7 @@ BOOST_AUTO_TEST_CASE(resp3_error_in_cmd_pipeline)
conn->cancel(operation::reconnection); conn->cancel(operation::reconnection);
}; };
auto c1 = [&](auto ec, auto) auto c1 = [&](auto ec, auto) {
{
BOOST_TEST(!ec); BOOST_TEST(!ec);
BOOST_TEST(std::get<2>(resp1).has_error()); BOOST_TEST(std::get<2>(resp1).has_error());
BOOST_CHECK_EQUAL(std::get<2>(resp1).error().data_type, resp3::type::simple_error); BOOST_CHECK_EQUAL(std::get<2>(resp1).error().data_type, resp3::type::simple_error);
@@ -142,29 +143,29 @@ BOOST_AUTO_TEST_CASE(error_in_transaction)
req.push("HELLO", 3); req.push("HELLO", 3);
req.push("MULTI"); req.push("MULTI");
req.push("PING"); req.push("PING");
req.push("PING", "msg2", "error"); // Error. req.push("PING", "msg2", "error"); // Error.
req.push("PING"); req.push("PING");
req.push("EXEC"); req.push("EXEC");
req.push("PING"); req.push("PING");
response< response<
ignore_t, // hello ignore_t, // hello
ignore_t, // multi ignore_t, // multi
ignore_t, // ping ignore_t, // ping
ignore_t, // ping ignore_t, // ping
ignore_t, // ping ignore_t, // ping
response<std::string, std::string, std::string>, // exec response<std::string, std::string, std::string>, // exec
std::string // ping std::string // ping
> resp; >
resp;
net::io_context ioc; net::io_context ioc;
auto conn = std::make_shared<connection>(ioc); auto conn = std::make_shared<connection>(ioc);
conn->async_exec(req, resp, [&](auto ec, auto){ conn->async_exec(req, resp, [&](auto ec, auto) {
BOOST_TEST(!ec); BOOST_TEST(!ec);
BOOST_TEST(std::get<0>(resp).has_value()); BOOST_TEST(std::get<0>(resp).has_value());
BOOST_TEST(std::get<1>(resp).has_value()); BOOST_TEST(std::get<1>(resp).has_value());
BOOST_TEST(std::get<2>(resp).has_value()); BOOST_TEST(std::get<2>(resp).has_value());
@@ -178,7 +179,9 @@ BOOST_AUTO_TEST_CASE(error_in_transaction)
// The ping in the transaction that should be an error. // The ping in the transaction that should be an error.
BOOST_TEST(std::get<1>(std::get<5>(resp).value()).has_error()); BOOST_TEST(std::get<1>(std::get<5>(resp).value()).has_error());
BOOST_CHECK_EQUAL(std::get<1>(std::get<5>(resp).value()).error().data_type, resp3::type::simple_error); BOOST_CHECK_EQUAL(
std::get<1>(std::get<5>(resp).value()).error().data_type,
resp3::type::simple_error);
auto const diag = std::get<1>(std::get<5>(resp).value()).error().diagnostic; auto const diag = std::get<1>(std::get<5>(resp).value()).error().diagnostic;
BOOST_TEST(!std::empty(diag)); BOOST_TEST(!std::empty(diag));
@@ -220,19 +223,17 @@ BOOST_AUTO_TEST_CASE(subscriber_wrong_syntax)
req1.push("PING"); req1.push("PING");
request req2; request req2;
req2.push("SUBSCRIBE"); // Wrong command synthax. req2.push("SUBSCRIBE"); // Wrong command synthax.
net::io_context ioc; net::io_context ioc;
auto conn = std::make_shared<connection>(ioc); auto conn = std::make_shared<connection>(ioc);
auto c2 = [&](auto ec, auto) auto c2 = [&](auto ec, auto) {
{
std::cout << "async_exec: subscribe" << std::endl; std::cout << "async_exec: subscribe" << std::endl;
BOOST_TEST(!ec); BOOST_TEST(!ec);
}; };
auto c1 = [&](auto ec, auto) auto c1 = [&](auto ec, auto) {
{
std::cout << "async_exec: hello" << std::endl; std::cout << "async_exec: hello" << std::endl;
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->async_exec(req2, ignore, c2); conn->async_exec(req2, ignore, c2);
@@ -243,8 +244,7 @@ BOOST_AUTO_TEST_CASE(subscriber_wrong_syntax)
generic_response gresp; generic_response gresp;
conn->set_receive_response(gresp); conn->set_receive_response(gresp);
auto c3 = [&](auto ec, auto) auto c3 = [&](auto ec, auto) {
{
std::cout << "async_receive" << std::endl; std::cout << "async_receive" << std::endl;
BOOST_TEST(!ec); BOOST_TEST(!ec);
BOOST_TEST(gresp.has_error()); BOOST_TEST(gresp.has_error());
@@ -261,4 +261,3 @@ BOOST_AUTO_TEST_CASE(subscriber_wrong_syntax)
ioc.run(); ioc.run();
} }

View File

@@ -5,14 +5,17 @@
*/ */
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/asio/awaitable.hpp> #include <boost/asio/awaitable.hpp>
#include <boost/system/errc.hpp> #include <boost/system/errc.hpp>
#define BOOST_TEST_MODULE conn-exec-retry #define BOOST_TEST_MODULE conn_exec_retry
#include <boost/test/included/unit_test.hpp> #include <boost/test/included/unit_test.hpp>
#include <iostream>
#include "common.hpp" #include "common.hpp"
#include <iostream>
namespace net = boost::asio; namespace net = boost::asio;
using error_code = boost::system::error_code; using error_code = boost::system::error_code;
using connection = boost::redis::connection; using connection = boost::redis::connection;
@@ -44,7 +47,7 @@ BOOST_AUTO_TEST_CASE(request_retry_false)
net::steady_timer st{ioc}; net::steady_timer st{ioc};
st.expires_after(std::chrono::seconds{1}); st.expires_after(std::chrono::seconds{1});
st.async_wait([&](auto){ st.async_wait([&](auto) {
// Cancels the request before receiving the response. This // Cancels the request before receiving the response. This
// should cause the third request to complete with error // should cause the third request to complete with error
// although it has cancel_on_connection_lost = false. The reason // although it has cancel_on_connection_lost = false. The reason
@@ -55,17 +58,17 @@ BOOST_AUTO_TEST_CASE(request_retry_false)
std::cout << "async_wait" << std::endl; std::cout << "async_wait" << std::endl;
}); });
auto c2 = [&](auto ec, auto){ auto c2 = [&](auto ec, auto) {
std::cout << "c2" << std::endl; std::cout << "c2" << std::endl;
BOOST_CHECK_EQUAL(ec, boost::asio::error::operation_aborted); BOOST_CHECK_EQUAL(ec, boost::asio::error::operation_aborted);
}; };
auto c1 = [&](auto ec, auto){ auto c1 = [&](auto ec, auto) {
std::cout << "c1" << std::endl; std::cout << "c1" << std::endl;
BOOST_CHECK_EQUAL(ec, boost::asio::error::operation_aborted); BOOST_CHECK_EQUAL(ec, boost::asio::error::operation_aborted);
}; };
auto c0 = [&](auto ec, auto){ auto c0 = [&](auto ec, auto) {
std::cout << "c0" << std::endl; std::cout << "c0" << std::endl;
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->async_exec(req1, ignore, c1); conn->async_exec(req1, ignore, c1);
@@ -75,13 +78,13 @@ BOOST_AUTO_TEST_CASE(request_retry_false)
conn->async_exec(req0, ignore, c0); conn->async_exec(req0, ignore, c0);
auto cfg = make_test_config(); auto cfg = make_test_config();
conn->async_run(cfg, {boost::redis::logger::level::debug}, conn->async_run(
[&](boost::system::error_code const& ec) cfg,
{ {boost::redis::logger::level::debug},
[&](boost::system::error_code const& ec) {
std::cout << "async_run: " << ec.message() << std::endl; std::cout << "async_run: " << ec.message() << std::endl;
conn->cancel(); conn->cancel();
} });
);
ioc.run(); ioc.run();
} }
@@ -111,7 +114,7 @@ BOOST_AUTO_TEST_CASE(request_retry_true)
net::steady_timer st{ioc}; net::steady_timer st{ioc};
st.expires_after(std::chrono::seconds{1}); st.expires_after(std::chrono::seconds{1});
st.async_wait([&](auto){ st.async_wait([&](auto) {
// Cancels the request before receiving the response. This // Cancels the request before receiving the response. This
// should cause the third request to not complete with error // should cause the third request to not complete with error
// since it has cancel_if_unresponded = true and cancellation // since it has cancel_if_unresponded = true and cancellation
@@ -119,22 +122,22 @@ BOOST_AUTO_TEST_CASE(request_retry_true)
conn->cancel(operation::run); conn->cancel(operation::run);
}); });
auto c3 = [&](auto ec, auto){ auto c3 = [&](auto ec, auto) {
std::cout << "c3: " << ec.message() << std::endl; std::cout << "c3: " << ec.message() << std::endl;
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->cancel(); conn->cancel();
}; };
auto c2 = [&](auto ec, auto){ auto c2 = [&](auto ec, auto) {
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->async_exec(req3, ignore, c3); conn->async_exec(req3, ignore, c3);
}; };
auto c1 = [](auto ec, auto){ auto c1 = [](auto ec, auto) {
BOOST_CHECK_EQUAL(ec, boost::system::errc::errc_t::operation_canceled); BOOST_CHECK_EQUAL(ec, boost::system::errc::errc_t::operation_canceled);
}; };
auto c0 = [&](auto ec, auto){ auto c0 = [&](auto ec, auto) {
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->async_exec(req1, ignore, c1); conn->async_exec(req1, ignore, c1);
conn->async_exec(req2, ignore, c2); conn->async_exec(req2, ignore, c2);
@@ -144,7 +147,7 @@ BOOST_AUTO_TEST_CASE(request_retry_true)
auto cfg = make_test_config(); auto cfg = make_test_config();
cfg.health_check_interval = 5s; cfg.health_check_interval = 5s;
conn->async_run(cfg, {}, [&](auto ec){ conn->async_run(cfg, {}, [&](auto ec) {
std::cout << ec.message() << std::endl; std::cout << ec.message() << std::endl;
BOOST_TEST(!!ec); BOOST_TEST(!!ec);
}); });

View File

@@ -6,15 +6,18 @@
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/redis/logger.hpp> #include <boost/redis/logger.hpp>
#include <boost/system/errc.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/as_tuple.hpp> #include <boost/asio/as_tuple.hpp>
#define BOOST_TEST_MODULE conn-push #include <boost/asio/co_spawn.hpp>
#include <boost/asio/detached.hpp>
#include <boost/system/errc.hpp>
#define BOOST_TEST_MODULE conn - push
#include <boost/test/included/unit_test.hpp> #include <boost/test/included/unit_test.hpp>
#include <iostream>
#include "common.hpp" #include "common.hpp"
#include <iostream>
namespace net = boost::asio; namespace net = boost::asio;
namespace redis = boost::redis; namespace redis = boost::redis;
@@ -47,19 +50,16 @@ BOOST_AUTO_TEST_CASE(receives_push_waiting_resps)
auto conn = std::make_shared<connection>(ioc); auto conn = std::make_shared<connection>(ioc);
auto c3 =[](auto ec, auto...) auto c3 = [](auto ec, auto...) {
{
std::cout << "c3: " << ec.message() << std::endl; std::cout << "c3: " << ec.message() << std::endl;
}; };
auto c2 =[&, conn](auto ec, auto...) auto c2 = [&, conn](auto ec, auto...) {
{
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->async_exec(req3, ignore, c3); conn->async_exec(req3, ignore, c3);
}; };
auto c1 =[&, conn](auto ec, auto...) auto c1 = [&, conn](auto ec, auto...) {
{
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->async_exec(req2, ignore, c2); conn->async_exec(req2, ignore, c2);
}; };
@@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(receives_push_waiting_resps)
run(conn, make_test_config(), {}); run(conn, make_test_config(), {});
bool push_received = false; bool push_received = false;
conn->async_receive([&, conn](auto ec, auto){ conn->async_receive([&, conn](auto ec, auto) {
std::cout << "async_receive" << std::endl; std::cout << "async_receive" << std::endl;
BOOST_TEST(!ec); BOOST_TEST(!ec);
push_received = true; push_received = true;
@@ -94,13 +94,13 @@ BOOST_AUTO_TEST_CASE(push_received1)
req.push("SUBSCRIBE", "channel1"); req.push("SUBSCRIBE", "channel1");
req.push("SUBSCRIBE", "channel2"); req.push("SUBSCRIBE", "channel2");
conn->async_exec(req, ignore, [conn](auto ec, auto){ conn->async_exec(req, ignore, [conn](auto ec, auto) {
std::cout << "async_exec" << std::endl; std::cout << "async_exec" << std::endl;
BOOST_TEST(!ec); BOOST_TEST(!ec);
}); });
bool push_async_received = false; bool push_async_received = false;
conn->async_receive([&, conn](auto ec, auto){ conn->async_receive([&, conn](auto ec, auto) {
std::cout << "(1) async_receive" << std::endl; std::cout << "(1) async_receive" << std::endl;
BOOST_TEST(!ec); BOOST_TEST(!ec);
@@ -116,7 +116,9 @@ BOOST_AUTO_TEST_CASE(push_received1)
// Tries to receive a third push synchronously. // Tries to receive a third push synchronously.
ec2 = {}; ec2 = {};
res = conn->receive(ec2); res = conn->receive(ec2);
BOOST_CHECK_EQUAL(ec2, boost::redis::make_error_code(boost::redis::error::sync_receive_push_failed)); BOOST_CHECK_EQUAL(
ec2,
boost::redis::make_error_code(boost::redis::error::sync_receive_push_failed));
conn->cancel(); conn->cancel();
}); });
@@ -139,11 +141,11 @@ BOOST_AUTO_TEST_CASE(push_filtered_out)
req.push("QUIT"); req.push("QUIT");
response<ignore_t, std::string, std::string> resp; response<ignore_t, std::string, std::string> resp;
conn->async_exec(req, resp, [conn](auto ec, auto){ conn->async_exec(req, resp, [conn](auto ec, auto) {
BOOST_TEST(!ec); BOOST_TEST(!ec);
}); });
conn->async_receive([&, conn](auto ec, auto){ conn->async_receive([&, conn](auto ec, auto) {
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->cancel(operation::reconnection); conn->cancel(operation::reconnection);
}); });
@@ -157,8 +159,7 @@ BOOST_AUTO_TEST_CASE(push_filtered_out)
} }
#ifdef BOOST_ASIO_HAS_CO_AWAIT #ifdef BOOST_ASIO_HAS_CO_AWAIT
net::awaitable<void> net::awaitable<void> push_consumer1(std::shared_ptr<connection> conn, bool& push_received)
push_consumer1(std::shared_ptr<connection> conn, bool& push_received)
{ {
{ {
auto [ec, ev] = co_await conn->async_receive(as_tuple(net::use_awaitable)); auto [ec, ev] = co_await conn->async_receive(as_tuple(net::use_awaitable));
@@ -173,26 +174,26 @@ push_consumer1(std::shared_ptr<connection> conn, bool& push_received)
push_received = true; push_received = true;
} }
struct response_error_tag{}; struct response_error_tag { };
response_error_tag error_tag_obj; response_error_tag error_tag_obj;
struct response_error_adapter { struct response_error_adapter {
void void operator()(
operator()( std::size_t,
std::size_t, boost::redis::resp3::basic_node<std::string_view> const&, boost::system::error_code& ec) boost::redis::resp3::basic_node<std::string_view> const&,
boost::system::error_code& ec)
{ {
ec = boost::redis::error::incompatible_size; ec = boost::redis::error::incompatible_size;
} }
[[nodiscard]] [[nodiscard]]
auto get_supported_response_size() const noexcept auto get_supported_response_size() const noexcept
{ return static_cast<std::size_t>(-1);} {
return static_cast<std::size_t>(-1);
}
}; };
auto boost_redis_adapt(response_error_tag&) auto boost_redis_adapt(response_error_tag&) { return response_error_adapter{}; }
{
return response_error_adapter{};
}
BOOST_AUTO_TEST_CASE(test_push_adapter) BOOST_AUTO_TEST_CASE(test_push_adapter)
{ {
@@ -212,12 +213,12 @@ BOOST_AUTO_TEST_CASE(test_push_adapter)
conn->cancel(operation::reconnection); conn->cancel(operation::reconnection);
}); });
conn->async_exec(req, ignore, [](auto ec, auto){ conn->async_exec(req, ignore, [](auto ec, auto) {
BOOST_CHECK_EQUAL(ec, boost::system::errc::errc_t::operation_canceled); BOOST_CHECK_EQUAL(ec, boost::system::errc::errc_t::operation_canceled);
}); });
auto cfg = make_test_config(); auto cfg = make_test_config();
conn->async_run(cfg, {}, [](auto ec){ conn->async_run(cfg, {}, [](auto ec) {
BOOST_CHECK_EQUAL(ec, redis::error::incompatible_size); BOOST_CHECK_EQUAL(ec, redis::error::incompatible_size);
}); });
@@ -255,68 +256,56 @@ BOOST_AUTO_TEST_CASE(many_subscribers)
net::io_context ioc; net::io_context ioc;
auto conn = std::make_shared<connection>(ioc); auto conn = std::make_shared<connection>(ioc);
auto c11 =[&](auto ec, auto...) auto c11 = [&](auto ec, auto...) {
{
std::cout << "quit sent: " << ec.message() << std::endl; std::cout << "quit sent: " << ec.message() << std::endl;
conn->cancel(operation::reconnection); conn->cancel(operation::reconnection);
}; };
auto c10 =[&](auto ec, auto...) auto c10 = [&](auto ec, auto...) {
{
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->async_exec(req3, ignore, c11); conn->async_exec(req3, ignore, c11);
}; };
auto c9 =[&](auto ec, auto...) auto c9 = [&](auto ec, auto...) {
{
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->async_exec(req2, ignore, c10); conn->async_exec(req2, ignore, c10);
}; };
auto c8 =[&](auto ec, auto...) auto c8 = [&](auto ec, auto...) {
{
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->async_exec(req1, ignore, c9); conn->async_exec(req1, ignore, c9);
}; };
auto c7 =[&](auto ec, auto...) auto c7 = [&](auto ec, auto...) {
{
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->async_exec(req2, ignore, c8); conn->async_exec(req2, ignore, c8);
}; };
auto c6 =[&](auto ec, auto...) auto c6 = [&](auto ec, auto...) {
{
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->async_exec(req2, ignore, c7); conn->async_exec(req2, ignore, c7);
}; };
auto c5 =[&](auto ec, auto...) auto c5 = [&](auto ec, auto...) {
{
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->async_exec(req1, ignore, c6); conn->async_exec(req1, ignore, c6);
}; };
auto c4 =[&](auto ec, auto...) auto c4 = [&](auto ec, auto...) {
{
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->async_exec(req2, ignore, c5); conn->async_exec(req2, ignore, c5);
}; };
auto c3 =[&](auto ec, auto...) auto c3 = [&](auto ec, auto...) {
{
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->async_exec(req1, ignore, c4); conn->async_exec(req1, ignore, c4);
}; };
auto c2 =[&](auto ec, auto...) auto c2 = [&](auto ec, auto...) {
{
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->async_exec(req2, ignore, c3); conn->async_exec(req2, ignore, c3);
}; };
auto c1 =[&](auto ec, auto...) auto c1 = [&](auto ec, auto...) {
{
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->async_exec(req2, ignore, c2); conn->async_exec(req2, ignore, c2);
}; };
auto c0 =[&](auto ec, auto...) auto c0 = [&](auto ec, auto...) {
{
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->async_exec(req1, ignore, c1); conn->async_exec(req1, ignore, c1);
}; };
conn->async_exec(req0, ignore, c0); conn->async_exec(req0, ignore, c0);
run(conn, make_test_config(), {}); run(conn, make_test_config(), {});

View File

@@ -5,12 +5,15 @@
*/ */
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/system/errc.hpp> #include <boost/system/errc.hpp>
#define BOOST_TEST_MODULE conn-quit #define BOOST_TEST_MODULE conn_quit
#include <boost/test/included/unit_test.hpp> #include <boost/test/included/unit_test.hpp>
#include <iostream>
#include "common.hpp" #include "common.hpp"
#include <iostream>
namespace net = boost::asio; namespace net = boost::asio;
using boost::redis::connection; using boost::redis::connection;
using boost::system::error_code; using boost::system::error_code;
@@ -40,21 +43,18 @@ BOOST_AUTO_TEST_CASE(test_async_run_exits)
req3.get_config().cancel_if_not_connected = true; req3.get_config().cancel_if_not_connected = true;
req3.push("PING"); req3.push("PING");
auto c3 = [](auto ec, auto) auto c3 = [](auto ec, auto) {
{
std::clog << "c3: " << ec.message() << std::endl; std::clog << "c3: " << ec.message() << std::endl;
BOOST_CHECK_EQUAL(ec, boost::asio::error::operation_aborted); BOOST_CHECK_EQUAL(ec, boost::asio::error::operation_aborted);
}; };
auto c2 = [&](auto ec, auto) auto c2 = [&](auto ec, auto) {
{
std::clog << "c2: " << ec.message() << std::endl; std::clog << "c2: " << ec.message() << std::endl;
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->async_exec(req3, ignore, c3); conn->async_exec(req3, ignore, c3);
}; };
auto c1 = [&](auto ec, auto) auto c1 = [&](auto ec, auto) {
{
std::cout << "c1: " << ec.message() << std::endl; std::cout << "c1: " << ec.message() << std::endl;
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->async_exec(req2, ignore, c2); conn->async_exec(req2, ignore, c2);
@@ -71,4 +71,3 @@ BOOST_AUTO_TEST_CASE(test_async_run_exits)
ioc.run(); ioc.run();
} }

View File

@@ -5,12 +5,15 @@
*/ */
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/asio/detached.hpp> #include <boost/asio/detached.hpp>
#define BOOST_TEST_MODULE conn-reconnect #define BOOST_TEST_MODULE conn_reconnect
#include <boost/test/included/unit_test.hpp> #include <boost/test/included/unit_test.hpp>
#include <iostream>
#include "common.hpp" #include "common.hpp"
#include <iostream>
#ifdef BOOST_ASIO_HAS_CO_AWAIT #ifdef BOOST_ASIO_HAS_CO_AWAIT
#include <boost/asio/experimental/awaitable_operators.hpp> #include <boost/asio/experimental/awaitable_operators.hpp>
@@ -43,7 +46,8 @@ net::awaitable<void> test_reconnect_impl()
logger l; logger l;
co_await conn->async_exec(req, ignore, net::redirect_error(net::use_awaitable, ec1)); co_await conn->async_exec(req, ignore, net::redirect_error(net::use_awaitable, ec1));
//BOOST_TEST(!ec); //BOOST_TEST(!ec);
std::cout << "test_reconnect: " << i << " " << ec2.message() << " " << ec1.message() << std::endl; std::cout << "test_reconnect: " << i << " " << ec2.message() << " " << ec1.message()
<< std::endl;
} }
conn->cancel(); conn->cancel();
@@ -76,10 +80,7 @@ auto async_test_reconnect_timeout() -> net::awaitable<void>
st.expires_after(std::chrono::seconds{1}); st.expires_after(std::chrono::seconds{1});
auto cfg = make_test_config(); auto cfg = make_test_config();
co_await ( co_await (conn->async_exec(req1, ignore, redir(ec1)) || st.async_wait(redir(ec3)));
conn->async_exec(req1, ignore, redir(ec1)) ||
st.async_wait(redir(ec3))
);
//BOOST_TEST(!ec1); //BOOST_TEST(!ec1);
//BOOST_TEST(!ec3); //BOOST_TEST(!ec3);
@@ -87,14 +88,13 @@ auto async_test_reconnect_timeout() -> net::awaitable<void>
request req2; request req2;
req2.get_config().cancel_if_not_connected = false; req2.get_config().cancel_if_not_connected = false;
req2.get_config().cancel_on_connection_lost = true; req2.get_config().cancel_on_connection_lost = true;
req2.get_config().cancel_if_unresponded= true; req2.get_config().cancel_if_unresponded = true;
req2.push("QUIT"); req2.push("QUIT");
st.expires_after(std::chrono::seconds{1}); st.expires_after(std::chrono::seconds{1});
co_await ( co_await (
conn->async_exec(req1, ignore, net::redirect_error(net::use_awaitable, ec1)) || conn->async_exec(req1, ignore, net::redirect_error(net::use_awaitable, ec1)) ||
st.async_wait(net::redirect_error(net::use_awaitable, ec3)) st.async_wait(net::redirect_error(net::use_awaitable, ec3)));
);
conn->cancel(); conn->cancel();
std::cout << "ccc" << std::endl; std::cout << "ccc" << std::endl;
@@ -109,8 +109,5 @@ BOOST_AUTO_TEST_CASE(test_reconnect_and_idle)
ioc.run(); ioc.run();
} }
#else #else
BOOST_AUTO_TEST_CASE(dummy) BOOST_AUTO_TEST_CASE(dummy) { BOOST_TEST(true); }
{
BOOST_TEST(true);
}
#endif #endif

View File

@@ -4,11 +4,13 @@
* accompanying file LICENSE.txt) * accompanying file LICENSE.txt)
*/ */
#include <boost/redis/connection.hpp>
#include <boost/asio/ssl/host_name_verification.hpp> #include <boost/asio/ssl/host_name_verification.hpp>
#include <boost/system/error_code.hpp> #include <boost/system/error_code.hpp>
#include <boost/redis/connection.hpp> #define BOOST_TEST_MODULE conn_tls
#define BOOST_TEST_MODULE conn-tls
#include <boost/test/included/unit_test.hpp> #include <boost/test/included/unit_test.hpp>
#include "common.hpp" #include "common.hpp"
namespace net = boost::asio; namespace net = boost::asio;

View File

@@ -8,6 +8,7 @@
#include "boost/system/detail/error_code.hpp" #include "boost/system/detail/error_code.hpp"
#define BOOST_TEST_MODULE conversions #define BOOST_TEST_MODULE conversions
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/test/included/unit_test.hpp> #include <boost/test/included/unit_test.hpp>
#include "common.hpp" #include "common.hpp"
@@ -21,103 +22,103 @@ using boost::system::error_code;
BOOST_AUTO_TEST_CASE(ints) BOOST_AUTO_TEST_CASE(ints)
{ {
// Setup // Setup
net::io_context ioc; net::io_context ioc;
auto conn = std::make_shared<connection>(ioc); auto conn = std::make_shared<connection>(ioc);
run(conn); run(conn);
// Get an integer key as all possible C++ integral types // Get an integer key as all possible C++ integral types
request req; request req;
req.push("SET", "key", 42); req.push("SET", "key", 42);
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i)
req.push("GET", "key"); req.push("GET", "key");
response< response<
ignore_t, ignore_t,
signed char, signed char,
unsigned char, unsigned char,
short, short,
unsigned short, unsigned short,
int, int,
unsigned int, unsigned int,
long, long,
unsigned long, unsigned long,
long long, long long,
unsigned long long unsigned long long>
> resp; resp;
conn->async_exec(req, resp, [conn](error_code ec, std::size_t) { conn->async_exec(req, resp, [conn](error_code ec, std::size_t) {
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->cancel(); conn->cancel();
}); });
// Run the operations // Run the operations
ioc.run(); ioc.run();
// Check // Check
BOOST_TEST(std::get<1>(resp).value() == 42); BOOST_TEST(std::get<1>(resp).value() == 42);
BOOST_TEST(std::get<2>(resp).value() == 42); BOOST_TEST(std::get<2>(resp).value() == 42);
BOOST_TEST(std::get<3>(resp).value() == 42); BOOST_TEST(std::get<3>(resp).value() == 42);
BOOST_TEST(std::get<4>(resp).value() == 42); BOOST_TEST(std::get<4>(resp).value() == 42);
BOOST_TEST(std::get<5>(resp).value() == 42); BOOST_TEST(std::get<5>(resp).value() == 42);
BOOST_TEST(std::get<6>(resp).value() == 42); BOOST_TEST(std::get<6>(resp).value() == 42);
BOOST_TEST(std::get<7>(resp).value() == 42); BOOST_TEST(std::get<7>(resp).value() == 42);
BOOST_TEST(std::get<8>(resp).value() == 42); BOOST_TEST(std::get<8>(resp).value() == 42);
BOOST_TEST(std::get<9>(resp).value() == 42); BOOST_TEST(std::get<9>(resp).value() == 42);
BOOST_TEST(std::get<10>(resp).value() == 42); BOOST_TEST(std::get<10>(resp).value() == 42);
} }
BOOST_AUTO_TEST_CASE(bools) BOOST_AUTO_TEST_CASE(bools)
{ {
// Setup // Setup
net::io_context ioc; net::io_context ioc;
auto conn = std::make_shared<connection>(ioc); auto conn = std::make_shared<connection>(ioc);
run(conn); run(conn);
// Get a boolean // Get a boolean
request req; request req;
req.push("SET", "key_true", "t"); req.push("SET", "key_true", "t");
req.push("SET", "key_false", "f"); req.push("SET", "key_false", "f");
req.push("GET", "key_true"); req.push("GET", "key_true");
req.push("GET", "key_false"); req.push("GET", "key_false");
response<ignore_t, ignore_t, bool, bool> resp; response<ignore_t, ignore_t, bool, bool> resp;
conn->async_exec(req, resp, [conn](error_code ec, std::size_t) { conn->async_exec(req, resp, [conn](error_code ec, std::size_t) {
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->cancel(); conn->cancel();
}); });
// Run the operations // Run the operations
ioc.run(); ioc.run();
// Check // Check
BOOST_TEST(std::get<2>(resp).value() == true); BOOST_TEST(std::get<2>(resp).value() == true);
BOOST_TEST(std::get<3>(resp).value() == false); BOOST_TEST(std::get<3>(resp).value() == false);
} }
BOOST_AUTO_TEST_CASE(floating_points) BOOST_AUTO_TEST_CASE(floating_points)
{ {
// Setup // Setup
net::io_context ioc; net::io_context ioc;
auto conn = std::make_shared<connection>(ioc); auto conn = std::make_shared<connection>(ioc);
run(conn); run(conn);
// Get a boolean // Get a boolean
request req; request req;
req.push("SET", "key", "4.12"); req.push("SET", "key", "4.12");
req.push("GET", "key"); req.push("GET", "key");
response<ignore_t, double> resp; response<ignore_t, double> resp;
conn->async_exec(req, resp, [conn](error_code ec, std::size_t) { conn->async_exec(req, resp, [conn](error_code ec, std::size_t) {
BOOST_TEST(!ec); BOOST_TEST(!ec);
conn->cancel(); conn->cancel();
}); });
// Run the operations // Run the operations
ioc.run(); ioc.run();
// Check // Check
BOOST_TEST(std::get<1>(resp).value() == 4.12); BOOST_TEST(std::get<1>(resp).value() == 4.12);
} }

View File

@@ -6,16 +6,19 @@
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/redis/logger.hpp> #include <boost/redis/logger.hpp>
#include <boost/asio/awaitable.hpp> #include <boost/asio/awaitable.hpp>
#include <boost/asio/use_awaitable.hpp> #include <boost/asio/use_awaitable.hpp>
#define BOOST_TEST_MODULE conn-quit #define BOOST_TEST_MODULE conn_quit
#include <boost/test/included/unit_test.hpp> #include <boost/test/included/unit_test.hpp>
#include "common.hpp"
#include <chrono> #include <chrono>
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <string> #include <string>
#include "common.hpp"
namespace net = boost::asio; namespace net = boost::asio;
using boost::redis::request; using boost::redis::request;
@@ -40,7 +43,7 @@ BOOST_AUTO_TEST_CASE(issue_181)
net::steady_timer timer{ioc}; net::steady_timer timer{ioc};
timer.expires_after(std::chrono::seconds{1}); timer.expires_after(std::chrono::seconds{1});
auto run_cont = [&](auto ec){ auto run_cont = [&](auto ec) {
std::cout << "async_run1: " << ec.message() << std::endl; std::cout << "async_run1: " << ec.message() << std::endl;
}; };
@@ -51,7 +54,7 @@ BOOST_AUTO_TEST_CASE(issue_181)
BOOST_TEST(!conn.run_is_canceled()); BOOST_TEST(!conn.run_is_canceled());
// Uses a timer to wait some time until run has been called. // Uses a timer to wait some time until run has been called.
auto timer_cont = [&](auto ec){ auto timer_cont = [&](auto ec) {
std::cout << "timer_cont: " << ec.message() << std::endl; std::cout << "timer_cont: " << ec.message() << std::endl;
BOOST_TEST(!conn.run_is_canceled()); BOOST_TEST(!conn.run_is_canceled());
conn.cancel(operation::run); conn.cancel(operation::run);

View File

@@ -8,19 +8,22 @@
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#include <boost/redis/logger.hpp> #include <boost/redis/logger.hpp>
#include <boost/asio/as_tuple.hpp> #include <boost/asio/as_tuple.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/consign.hpp>
#include <boost/asio/redirect_error.hpp>
#include <boost/asio/awaitable.hpp> #include <boost/asio/awaitable.hpp>
#include <boost/asio/use_awaitable.hpp>
#include <boost/asio/co_spawn.hpp> #include <boost/asio/co_spawn.hpp>
#define BOOST_TEST_MODULE conn-quit #include <boost/asio/consign.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/redirect_error.hpp>
#include <boost/asio/use_awaitable.hpp>
#define BOOST_TEST_MODULE conn - quit
#include <boost/test/included/unit_test.hpp> #include <boost/test/included/unit_test.hpp>
#include <tuple>
#include <iostream>
#include "common.hpp" #include "common.hpp"
#include <iostream>
#include <tuple>
#if defined(BOOST_ASIO_HAS_CO_AWAIT) #if defined(BOOST_ASIO_HAS_CO_AWAIT)
namespace net = boost::asio; namespace net = boost::asio;
@@ -38,8 +41,7 @@ using boost::asio::redirect_error;
using namespace std::chrono_literals; using namespace std::chrono_literals;
// Push consumer // Push consumer
auto auto receiver(std::shared_ptr<connection> conn) -> net::awaitable<void>
receiver(std::shared_ptr<connection> conn) -> net::awaitable<void>
{ {
std::cout << "uuu" << std::endl; std::cout << "uuu" << std::endl;
while (conn->will_reconnect()) { while (conn->will_reconnect()) {
@@ -59,32 +61,31 @@ receiver(std::shared_ptr<connection> conn) -> net::awaitable<void>
std::cout << "Exiting the receiver." << std::endl; std::cout << "Exiting the receiver." << std::endl;
} }
auto auto periodic_task(std::shared_ptr<connection> conn) -> net::awaitable<void>
periodic_task(std::shared_ptr<connection> conn) -> net::awaitable<void>
{ {
net::steady_timer timer{co_await net::this_coro::executor}; net::steady_timer timer{co_await net::this_coro::executor};
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
std::cout << "In the loop: " << i << std::endl; std::cout << "In the loop: " << i << std::endl;
timer.expires_after(std::chrono::milliseconds(50)); timer.expires_after(std::chrono::milliseconds(50));
co_await timer.async_wait(net::use_awaitable); co_await timer.async_wait(net::use_awaitable);
// Key is not set so it will cause an error since we are passing // Key is not set so it will cause an error since we are passing
// an adapter that does not accept null, this will cause an error // an adapter that does not accept null, this will cause an error
// that result in the connection being closed. // that result in the connection being closed.
request req; request req;
req.push("GET", "mykey"); req.push("GET", "mykey");
auto [ec, u] = co_await conn->async_exec(req, ignore, net::as_tuple(net::use_awaitable)); auto [ec, u] = co_await conn->async_exec(req, ignore, net::as_tuple(net::use_awaitable));
if (ec) { if (ec) {
std::cout << "(1)Error: " << ec << std::endl; std::cout << "(1)Error: " << ec << std::endl;
} else { } else {
std::cout << "no error: " << std::endl; std::cout << "no error: " << std::endl;
} }
} }
std::cout << "Periodic task done!" << std::endl; std::cout << "Periodic task done!" << std::endl;
conn->cancel(operation::run); conn->cancel(operation::run);
conn->cancel(operation::receive); conn->cancel(operation::receive);
conn->cancel(operation::reconnection); conn->cancel(operation::reconnection);
} }
auto co_main(config) -> net::awaitable<void> auto co_main(config) -> net::awaitable<void>
@@ -105,10 +106,8 @@ BOOST_AUTO_TEST_CASE(issue_50)
ioc.run(); ioc.run();
} }
#else // defined(BOOST_ASIO_HAS_CO_AWAIT) #else // defined(BOOST_ASIO_HAS_CO_AWAIT)
BOOST_AUTO_TEST_CASE(issue_50) BOOST_AUTO_TEST_CASE(issue_50) { }
{
}
#endif // defined(BOOST_ASIO_HAS_CO_AWAIT) #endif // defined(BOOST_ASIO_HAS_CO_AWAIT)

View File

@@ -4,17 +4,18 @@
* accompanying file LICENSE.txt) * accompanying file LICENSE.txt)
*/ */
#include <boost/redis/detail/resp3_handshaker.hpp>
#include <boost/redis/detail/multiplexer.hpp>
#include <boost/redis/resp3/serialization.hpp>
#include <boost/redis/resp3/node.hpp>
#include <boost/redis/resp3/type.hpp>
#include <boost/redis/adapter/adapt.hpp> #include <boost/redis/adapter/adapt.hpp>
#include <boost/redis/adapter/any_adapter.hpp> #include <boost/redis/adapter/any_adapter.hpp>
#define BOOST_TEST_MODULE conn-quit #include <boost/redis/detail/multiplexer.hpp>
#include <boost/redis/detail/resp3_handshaker.hpp>
#include <boost/redis/resp3/node.hpp>
#include <boost/redis/resp3/serialization.hpp>
#include <boost/redis/resp3/type.hpp>
#define BOOST_TEST_MODULE conn_quit
#include <boost/test/included/unit_test.hpp> #include <boost/test/included/unit_test.hpp>
#include <string>
#include <iostream> #include <iostream>
#include <string>
using boost::redis::request; using boost::redis::request;
using boost::redis::config; using boost::redis::config;
@@ -38,7 +39,7 @@ BOOST_AUTO_TEST_CASE(low_level_sync_sans_io)
char const* wire = "~6\r\n+orange\r\n+apple\r\n+one\r\n+two\r\n+three\r\n+orange\r\n"; char const* wire = "~6\r\n+orange\r\n+apple\r\n+one\r\n+two\r\n+three\r\n+orange\r\n";
deserialize(wire, adapt2(resp)); deserialize(wire, adapt2(resp));
for (auto const& e: resp.value()) for (auto const& e : resp.value())
std::cout << e << std::endl; std::cout << e << std::endl;
} catch (std::exception const& e) { } catch (std::exception const& e) {
@@ -82,7 +83,8 @@ BOOST_AUTO_TEST_CASE(config_to_hello_cmd_clientname)
push_hello(cfg, req); push_hello(cfg, req);
std::string_view const expected = "*4\r\n$5\r\nHELLO\r\n$1\r\n3\r\n$7\r\nSETNAME\r\n$11\r\nBoost.Redis\r\n"; std::string_view const
expected = "*4\r\n$5\r\nHELLO\r\n$1\r\n3\r\n$7\r\nSETNAME\r\n$11\r\nBoost.Redis\r\n";
BOOST_CHECK_EQUAL(req.payload(), expected); BOOST_CHECK_EQUAL(req.payload(), expected);
} }
@@ -96,21 +98,20 @@ BOOST_AUTO_TEST_CASE(config_to_hello_cmd_auth)
push_hello(cfg, req); push_hello(cfg, req);
std::string_view const expected = "*5\r\n$5\r\nHELLO\r\n$1\r\n3\r\n$4\r\nAUTH\r\n$3\r\nfoo\r\n$3\r\nbar\r\n"; std::string_view const
expected = "*5\r\n$5\r\nHELLO\r\n$1\r\n3\r\n$4\r\nAUTH\r\n$3\r\nfoo\r\n$3\r\nbar\r\n";
BOOST_CHECK_EQUAL(req.payload(), expected); BOOST_CHECK_EQUAL(req.payload(), expected);
} }
BOOST_AUTO_TEST_CASE(issue_210_empty_set) BOOST_AUTO_TEST_CASE(issue_210_empty_set)
{ {
try { try {
result< result<std::tuple<
std::tuple< result<int>,
result<int>, result<std::vector<std::string>>,
result<std::vector<std::string>>, result<std::string>,
result<std::string>, result<int>>>
result<int> resp;
>
> resp;
char const* wire = "*4\r\n:1\r\n~0\r\n$25\r\nthis_should_not_be_in_set\r\n:2\r\n"; char const* wire = "*4\r\n:1\r\n~0\r\n$25\r\nthis_should_not_be_in_set\r\n:2\r\n";
@@ -130,16 +131,15 @@ BOOST_AUTO_TEST_CASE(issue_210_empty_set)
BOOST_AUTO_TEST_CASE(issue_210_non_empty_set_size_one) BOOST_AUTO_TEST_CASE(issue_210_non_empty_set_size_one)
{ {
try { try {
result< result<std::tuple<
std::tuple< result<int>,
result<int>, result<std::vector<std::string>>,
result<std::vector<std::string>>, result<std::string>,
result<std::string>, result<int>>>
result<int> resp;
>
> resp;
char const* wire = "*4\r\n:1\r\n~1\r\n$3\r\nfoo\r\n$25\r\nthis_should_not_be_in_set\r\n:2\r\n"; char const*
wire = "*4\r\n:1\r\n~1\r\n$3\r\nfoo\r\n$25\r\nthis_should_not_be_in_set\r\n:2\r\n";
deserialize(wire, adapt2(resp)); deserialize(wire, adapt2(resp));
@@ -158,16 +158,15 @@ BOOST_AUTO_TEST_CASE(issue_210_non_empty_set_size_one)
BOOST_AUTO_TEST_CASE(issue_210_non_empty_set_size_two) BOOST_AUTO_TEST_CASE(issue_210_non_empty_set_size_two)
{ {
try { try {
result< result<std::tuple<
std::tuple< result<int>,
result<int>, result<std::vector<std::string>>,
result<std::vector<std::string>>, result<std::string>,
result<std::string>, result<int>>>
result<int> resp;
>
> resp;
char const* wire = "*4\r\n:1\r\n~2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n$25\r\nthis_should_not_be_in_set\r\n:2\r\n"; char const* wire =
"*4\r\n:1\r\n~2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n$25\r\nthis_should_not_be_in_set\r\n:2\r\n";
deserialize(wire, adapt2(resp)); deserialize(wire, adapt2(resp));
@@ -185,16 +184,11 @@ BOOST_AUTO_TEST_CASE(issue_210_non_empty_set_size_two)
BOOST_AUTO_TEST_CASE(issue_210_no_nested) BOOST_AUTO_TEST_CASE(issue_210_no_nested)
{ {
try { try {
result< result<std::tuple<result<int>, result<std::string>, result<std::string>, result<std::string>>>
std::tuple< resp;
result<int>,
result<std::string>,
result<std::string>,
result<std::string>
>
> resp;
char const* wire = "*4\r\n:1\r\n$3\r\nfoo\r\n$3\r\nbar\r\n$25\r\nthis_should_not_be_in_set\r\n"; char const*
wire = "*4\r\n:1\r\n$3\r\nfoo\r\n$3\r\nbar\r\n$25\r\nthis_should_not_be_in_set\r\n";
deserialize(wire, adapt2(resp)); deserialize(wire, adapt2(resp));
@@ -278,7 +272,7 @@ BOOST_AUTO_TEST_CASE(multiplexer_push)
BOOST_CHECK_EQUAL(resp.value().at(1).value, "one"); BOOST_CHECK_EQUAL(resp.value().at(1).value, "one");
BOOST_CHECK_EQUAL(resp.value().at(2).value, "two"); BOOST_CHECK_EQUAL(resp.value().at(2).value, "two");
for (auto const& e: resp.value()) for (auto const& e : resp.value())
std::cout << e << std::endl; std::cout << e << std::endl;
} }
@@ -348,7 +342,7 @@ BOOST_AUTO_TEST_CASE(multiplexer_pipeline)
BOOST_TEST(item3.elem_ptr->is_waiting()); BOOST_TEST(item3.elem_ptr->is_waiting());
// There are three requests to coalesce, a second call should do // There are three requests to coalesce, a second call should do
// nothing. // nothing.
BOOST_CHECK_EQUAL(mpx.prepare_write(), 3); BOOST_CHECK_EQUAL(mpx.prepare_write(), 3);
BOOST_CHECK_EQUAL(mpx.prepare_write(), 0); BOOST_CHECK_EQUAL(mpx.prepare_write(), 0);
@@ -381,7 +375,7 @@ BOOST_AUTO_TEST_CASE(multiplexer_pipeline)
// The done status should still be unchanged on requests that // The done status should still be unchanged on requests that
// expect a response. // expect a response.
BOOST_TEST(!item1.done); BOOST_TEST(!item1.done);
BOOST_TEST( item2.done); BOOST_TEST(item2.done);
BOOST_TEST(!item3.done); BOOST_TEST(!item3.done);
// Simulates a socket read by putting some data in the read buffer. // Simulates a socket read by putting some data in the read buffer.
@@ -399,8 +393,8 @@ BOOST_AUTO_TEST_CASE(multiplexer_pipeline)
BOOST_TEST(mpx.get_read_buffer().empty()); BOOST_TEST(mpx.get_read_buffer().empty());
// The last request still did not get a response. // The last request still did not get a response.
BOOST_TEST( item1.done); BOOST_TEST(item1.done);
BOOST_TEST( item2.done); BOOST_TEST(item2.done);
BOOST_TEST(!item3.done); BOOST_TEST(!item3.done);
// TODO: Check the first request was removed from the queue. // TODO: Check the first request was removed from the queue.

View File

@@ -7,10 +7,10 @@
#include <iostream> #include <iostream>
#define BOOST_TEST_MODULE request #define BOOST_TEST_MODULE request
#include <boost/test/included/unit_test.hpp>
#include <boost/redis/request.hpp> #include <boost/redis/request.hpp>
#include <boost/test/included/unit_test.hpp>
using boost::redis::request; using boost::redis::request;
// TODO: Serialization. // TODO: Serialization.
@@ -39,9 +39,14 @@ BOOST_AUTO_TEST_CASE(multiple_args)
BOOST_AUTO_TEST_CASE(container_and_range) BOOST_AUTO_TEST_CASE(container_and_range)
{ {
std::map<std::string, std::string> in{{"key1", "value1"}, {"key2", "value2"}}; std::map<std::string, std::string> in{
{"key1", "value1"},
{"key2", "value2"}
};
char const* res = "*6\r\n$4\r\nHSET\r\n$3\r\nkey\r\n$4\r\nkey1\r\n$6\r\nvalue1\r\n$4\r\nkey2\r\n$6\r\nvalue2\r\n"; char const* res =
"*6\r\n$4\r\nHSET\r\n$3\r\nkey\r\n$4\r\nkey1\r\n$6\r\nvalue1\r\n$4\r\nkey2\r\n$"
"6\r\nvalue2\r\n";
request req1; request req1;
req1.push_range("HSET", "key", in); req1.push_range("HSET", "key", in);

View File

@@ -7,9 +7,11 @@
#include <boost/redis/connection.hpp> #include <boost/redis/connection.hpp>
#define BOOST_TEST_MODULE run #define BOOST_TEST_MODULE run
#include <boost/test/included/unit_test.hpp> #include <boost/test/included/unit_test.hpp>
#include <iostream>
#include "common.hpp" #include "common.hpp"
#include <iostream>
namespace net = boost::asio; namespace net = boost::asio;
namespace redis = boost::redis; namespace redis = boost::redis;
@@ -22,8 +24,10 @@ using namespace std::chrono_literals;
bool is_host_not_found(error_code ec) bool is_host_not_found(error_code ec)
{ {
if (ec == net::error::netdb_errors::host_not_found) return true; if (ec == net::error::netdb_errors::host_not_found)
if (ec == net::error::netdb_errors::host_not_found_try_again) return true; return true;
if (ec == net::error::netdb_errors::host_not_found_try_again)
return true;
return false; return false;
} }
@@ -40,7 +44,7 @@ BOOST_AUTO_TEST_CASE(resolve_bad_host)
cfg.reconnect_wait_interval = 0s; cfg.reconnect_wait_interval = 0s;
auto conn = std::make_shared<connection>(ioc); auto conn = std::make_shared<connection>(ioc);
conn->async_run(cfg, {}, [](auto ec){ conn->async_run(cfg, {}, [](auto ec) {
BOOST_TEST(is_host_not_found(ec)); BOOST_TEST(is_host_not_found(ec));
}); });
@@ -97,4 +101,3 @@ BOOST_AUTO_TEST_CASE(connect_bad_port)
// run(conn, cfg, boost::redis::error::connect_timeout); // run(conn, cfg, boost::redis::error::connect_timeout);
// ioc.run(); // ioc.run();
//} //}