diff --git a/README.md b/README.md index 3ca1d448..93af26a8 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,12 @@ below req.quit(); } - struct receiver : public receiver_base { - std::shared_ptr conn_; // Optional + class receiver : public receiver_base { + private: + std::shared_ptr conn_; + + public: + receiver(std::shared_ptr conn) : conn_{conn} { } void on_hello(resp::array_type& v) noexcept override { conn_->send(f); } @@ -32,7 +36,6 @@ below void on_quit(resp::simple_string_type& s) noexcept override { std::cout << "QUIT: " << s << std::endl; } }; - ``` In general for each redis command you have to override a member @@ -57,5 +60,5 @@ This library is header only. To use it include the following header in one of your source files e.g. `aedis.cpp` ```cpp -#include +#include ``` diff --git a/examples/async_basic.cpp b/examples/async_basic.cpp index 9f9d7736..255ee126 100644 --- a/examples/async_basic.cpp +++ b/examples/async_basic.cpp @@ -6,7 +6,7 @@ */ #include -#include +#include using namespace aedis; diff --git a/examples/async_low_level.cpp b/examples/async_low_level.cpp index f0b336cd..37b73fd6 100644 --- a/examples/async_low_level.cpp +++ b/examples/async_low_level.cpp @@ -6,7 +6,7 @@ */ #include -#include +#include using namespace aedis; diff --git a/examples/sync_basic.cpp b/examples/sync_basic.cpp index d6048f32..42771a47 100644 --- a/examples/sync_basic.cpp +++ b/examples/sync_basic.cpp @@ -6,7 +6,7 @@ */ #include -#include +#include using namespace aedis; diff --git a/include/aedis/aedis.hpp b/include/aedis/aedis.hpp index 344f5630..98c62e58 100644 --- a/include/aedis/aedis.hpp +++ b/include/aedis/aedis.hpp @@ -9,9 +9,7 @@ #include #include -#include #include #include #include #include -#include diff --git a/include/aedis/connection.hpp b/include/aedis/connection.hpp index 84849ed5..8841ea54 100644 --- a/include/aedis/connection.hpp +++ b/include/aedis/connection.hpp @@ -10,11 +10,12 @@ #include #include +#include + #include "config.hpp" #include "type.hpp" #include "request.hpp" #include "read.hpp" -#include "response_buffers.hpp" namespace aedis { diff --git a/include/aedis/command.hpp b/include/aedis/detail/command.hpp similarity index 94% rename from include/aedis/command.hpp rename to include/aedis/detail/command.hpp index 93236218..34c78413 100644 --- a/include/aedis/command.hpp +++ b/include/aedis/detail/command.hpp @@ -8,7 +8,6 @@ #pragma once #include -#include namespace aedis { @@ -73,7 +72,7 @@ enum class command , none }; -char const* to_string(command c); +std::string to_string(command c); std::ostream& operator<<(std::ostream& os, command c); } // aedis diff --git a/include/aedis/command.ipp b/include/aedis/detail/impl/command.ipp similarity index 96% rename from include/aedis/command.ipp rename to include/aedis/detail/impl/command.ipp index 6328e51a..1c0ab78e 100644 --- a/include/aedis/command.ipp +++ b/include/aedis/detail/impl/command.ipp @@ -5,7 +5,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -#include "command.hpp" +#include #include @@ -13,7 +13,7 @@ namespace aedis { #define EXPAND_COMMAND_CASE(x) case command::x: return #x -char const* to_string(command c) +std::string to_string(command c) { switch (c) { EXPAND_COMMAND_CASE(append); diff --git a/include/aedis/parser.ipp b/include/aedis/detail/impl/parser.ipp similarity index 95% rename from include/aedis/parser.ipp rename to include/aedis/detail/impl/parser.ipp index 045b45f5..666d4639 100644 --- a/include/aedis/parser.ipp +++ b/include/aedis/detail/impl/parser.ipp @@ -5,14 +5,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -#include "parser.hpp" - -//#include -//#include -//#include -//#include -//#include -//#include +#include namespace aedis { namespace resp { diff --git a/include/aedis/response_buffers.ipp b/include/aedis/detail/impl/response_buffers.ipp similarity index 99% rename from include/aedis/response_buffers.ipp rename to include/aedis/detail/impl/response_buffers.ipp index 63bd41eb..a68f023c 100644 --- a/include/aedis/response_buffers.ipp +++ b/include/aedis/detail/impl/response_buffers.ipp @@ -5,10 +5,10 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -#include "response_buffers.hpp" - #include +#include + namespace aedis { namespace resp { void response_buffers::forward_transaction( diff --git a/include/aedis/parser.hpp b/include/aedis/detail/parser.hpp similarity index 100% rename from include/aedis/parser.hpp rename to include/aedis/detail/parser.hpp diff --git a/include/aedis/detail/response_base.hpp b/include/aedis/detail/response_base.hpp new file mode 100644 index 00000000..9c615e92 --- /dev/null +++ b/include/aedis/detail/response_base.hpp @@ -0,0 +1,40 @@ +/* Copyright (c) 2019 - 2021 Marcelo Zimbres Silva (mzimbres at gmail dot com) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include +#include + +#include + +namespace aedis { namespace resp { + +struct response_base { + virtual void pop() {} + virtual void on_simple_string(std::string_view s) { throw std::runtime_error("on_simple_string: Has not been overridden."); } + virtual void on_simple_error(std::string_view s) { throw std::runtime_error("on_simple_error: Has not been overridden."); } + virtual void on_number(std::string_view s) { throw std::runtime_error("on_number: Has not been overridden."); } + virtual void on_double(std::string_view s) { throw std::runtime_error("on_double: Has not been overridden."); } + virtual void on_null() { throw std::runtime_error("on_null: Has not been overridden."); } + virtual void on_bool(std::string_view s) { throw std::runtime_error("on_bool: Has not been overridden."); } + virtual void on_big_number(std::string_view s) { throw std::runtime_error("on_big_number: Has not been overridden."); } + virtual void on_verbatim_string(std::string_view s = {}) { throw std::runtime_error("on_verbatim_string: Has not been overridden."); } + virtual void on_blob_string(std::string_view s = {}) { throw std::runtime_error("on_blob_string: Has not been overridden."); } + virtual void on_blob_error(std::string_view s = {}) { throw std::runtime_error("on_blob_error: Has not been overridden."); } + virtual void on_streamed_string_part(std::string_view s = {}) { throw std::runtime_error("on_streamed_string_part: Has not been overridden."); } + virtual void select_array(int n) { throw std::runtime_error("select_array: Has not been overridden."); } + virtual void select_set(int n) { throw std::runtime_error("select_set: Has not been overridden."); } + virtual void select_map(int n) { throw std::runtime_error("select_map: Has not been overridden."); } + virtual void select_push(int n) { throw std::runtime_error("select_push: Has not been overridden."); } + virtual void select_attribute(int n) { throw std::runtime_error("select_attribute: Has not been overridden."); } + virtual ~response_base() {} +}; + +} // resp +} // aedis + diff --git a/include/aedis/response_buffers.hpp b/include/aedis/detail/response_buffers.hpp similarity index 95% rename from include/aedis/response_buffers.hpp rename to include/aedis/detail/response_buffers.hpp index 6f8d91fc..95b1106a 100644 --- a/include/aedis/response_buffers.hpp +++ b/include/aedis/detail/response_buffers.hpp @@ -7,9 +7,10 @@ #pragma once -#include "type.hpp" +#include +#include + #include "command.hpp" -#include "receiver_base.hpp" #include "response_types.hpp" namespace aedis { namespace resp { diff --git a/include/aedis/response_types.hpp b/include/aedis/detail/response_types.hpp similarity index 100% rename from include/aedis/response_types.hpp rename to include/aedis/detail/response_types.hpp diff --git a/include/aedis/detail/responses.hpp b/include/aedis/detail/responses.hpp new file mode 100644 index 00000000..48cd2a6c --- /dev/null +++ b/include/aedis/detail/responses.hpp @@ -0,0 +1,380 @@ +/* Copyright (c) 2019 - 2021 Marcelo Zimbres Silva (mzimbres at gmail dot com) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "response_base.hpp" + +#include + +namespace aedis { namespace resp { + +template +std::enable_if::value, void>::type +from_string_view(std::string_view s, T& n) +{ + auto r = std::from_chars(s.data(), s.data() + s.size(), n); + if (r.ec == std::errc::invalid_argument) + throw std::runtime_error("from_chars: Unable to convert"); +} + +inline +void from_string_view(std::string_view s, std::string& r) + { r = s; } + +struct response_ignore : response_base { + void on_simple_string(std::string_view s) override {} + void on_simple_error(std::string_view s) override {} + void on_number(std::string_view s) override {} + void on_double(std::string_view s) override {} + void on_null() override {} + void on_bool(std::string_view s) override {} + void on_big_number(std::string_view s) override {} + void on_verbatim_string(std::string_view s = {}) override {} + void on_blob_string(std::string_view s = {}) override {} + void on_blob_error(std::string_view s = {}) override {} + void on_streamed_string_part(std::string_view s = {}) override {} + void select_array(int n) override {} + void select_set(int n) override {} + void select_map(int n) override {} + void select_push(int n) override {} + void select_attribute(int n) override {} +}; + +// This response type is able to deal with recursive redis responses +// as in a transaction for example. +class response_tree: public response_base { +public: + struct elem { + int depth; + type t; + int expected_size = -1; + std::vector value; + }; + + std::vector result; + +private: + int depth_ = 0; + + void add_aggregate(int n, type t) + { + if (depth_ == 0) { + result.reserve(n); + ++depth_; + return; + } + + result.emplace_back(depth_, t, n); + result.back().value.reserve(n); + ++depth_; + } + + void add(std::string_view s, type t) + { + if (std::empty(result)) { + result.emplace_back(depth_, t, 1, std::vector{std::string{s}}); + } else if (std::ssize(result.back().value) == result.back().expected_size) { + result.emplace_back(depth_, t, 1, std::vector{std::string{s}}); + } else { + result.back().value.push_back(std::string{s}); + } + } + +public: + void select_array(int n) override {add_aggregate(n, type::array);} + void select_push(int n) override {add_aggregate(n, type::push);} + void select_set(int n) override {add_aggregate(n, type::set);} + void select_map(int n) override {add_aggregate(n, type::map);} + void select_attribute(int n) override {add_aggregate(n, type::attribute);} + + void on_simple_string(std::string_view s) override { add(s, type::simple_string); } + void on_simple_error(std::string_view s) override { add(s, type::simple_error); } + void on_number(std::string_view s) override {add(s, type::number);} + void on_double(std::string_view s) override {add(s, type::double_type);} + void on_bool(std::string_view s) override {add(s, type::boolean);} + void on_big_number(std::string_view s) override {add(s, type::big_number);} + void on_null() override {add({}, type::null);} + void on_blob_error(std::string_view s = {}) override {add(s, type::blob_error);} + void on_verbatim_string(std::string_view s = {}) override {add(s, type::verbatim_string);} + void on_blob_string(std::string_view s = {}) override {add(s, type::blob_string);} + void on_streamed_string_part(std::string_view s = {}) override {add(s, type::streamed_string_part);} + void clear() { result.clear(); depth_ = 0;} + auto size() const { return result.size(); } + void pop() override { --depth_; } +}; + +struct response_number : public response_base { + void on_number(std::string_view s) override + { from_string_view(s, result); } + + number_type result; +}; + +template< + class CharT, + class Traits = std::char_traits, + class Allocator = std::allocator> +struct response_basic_blob_string : public response_base { + void on_blob_string(std::string_view s) override + { from_string_view(s, result); } + + basic_blob_string result; +}; + +template< + class CharT = char, + class Traits = std::char_traits, + class Allocator = std::allocator> +struct response_basic_blob_error : public response_base { + void on_blob_error(std::string_view s) override + { from_string_view(s, result); } + + basic_blob_error result; +}; + +template< + class CharT = char, + class Traits = std::char_traits, + class Allocator = std::allocator + > +struct response_basic_simple_string : public response_base { + void on_simple_string(std::string_view s) override + { from_string_view(s, result); } + + basic_simple_string result; +}; + +template< + class CharT = char, + class Traits = std::char_traits, + class Allocator = std::allocator + > +struct response_basic_simple_error : public response_base { + void on_simple_error(std::string_view s) override + { from_string_view(s, result); } + + basic_simple_error result; +}; + +// Big number uses strings at the moment as the underlying storage. +template < + class CharT = char, + class Traits = std::char_traits, + class Allocator = std::allocator + > +struct response_basic_big_number : public response_base { + void on_big_number(std::string_view s) override + { from_string_view(s, result); } + + basic_big_number result; +}; + +struct response_double : public response_base { + void on_double(std::string_view s) override + { + result = s; + } + + double_type result; +}; + +template< + class CharT = char, + class Traits = std::char_traits, + class Allocator = std::allocator + > +struct response_basic_verbatim_string : public response_base { + void on_verbatim_string(std::string_view s) override + { from_string_view(s, result); } +public: + basic_verbatim_string result; +}; + +template< + class CharT = char, + class Traits = std::char_traits, + class Allocator = std::allocator + > +struct response_basic_streamed_string_part : public response_base { + void on_streamed_string_part(std::string_view s) override + { result += s; } + + basic_streamed_string_part result; +}; + +struct response_bool : public response_base { + void on_bool(std::string_view s) override + { + assert(std::ssize(s) == 1); + result = s[0] == 't'; + } + + bool_type result; +}; + +template< + class Key, + class Compare = std::less, + class Allocator = std::allocator + > +struct response_unordered_set : response_base { + void on_blob_string(std::string_view s) override + { + Key r; + from_string_view(s, r); + result.insert(std::end(result), std::move(r)); + } + + void select_array(int n) override { } + void select_set(int n) override { } + + std::set result; +}; + +template < + class T, + class Allocator = std::allocator + > +struct response_basic_array : response_base { + void add(std::string_view s = {}) + { + T r; + from_string_view(s, r); + result.emplace_back(std::move(r)); + } + + // TODO: Call vector reserver. + void on_simple_string(std::string_view s) override { add(s); } + void on_number(std::string_view s) override { add(s); } + void on_double(std::string_view s) override { add(s); } + void on_bool(std::string_view s) override { add(s); } + void on_big_number(std::string_view s) override { add(s); } + void on_verbatim_string(std::string_view s = {}) override { add(s); } + void on_blob_string(std::string_view s = {}) override { add(s); } + void select_array(int n) override { } + void select_set(int n) override { } + void select_map(int n) override { } + void select_push(int n) override { } + void on_streamed_string_part(std::string_view s = {}) override { add(s); } + + basic_array_type result; +}; + +template < + class T, + class Allocator = std::allocator + > +struct response_basic_map : response_base { + void add(std::string_view s = {}) + { + T r; + from_string_view(s, r); + result.emplace_back(std::move(r)); + } + + void select_map(int n) override { } + + // We also have to enable arrays, the hello command for example + // returns a map that has an embeded array. + void select_array(int n) override { } + + void on_simple_string(std::string_view s) override { add(s); } + void on_number(std::string_view s) override { add(s); } + void on_double(std::string_view s) override { add(s); } + void on_bool(std::string_view s) override { add(s); } + void on_big_number(std::string_view s) override { add(s); } + void on_verbatim_string(std::string_view s = {}) override { add(s); } + void on_blob_string(std::string_view s = {}) override { add(s); } + + basic_map_type result; +}; + +template < + class T, + class Allocator = std::allocator + > +struct response_basic_set : response_base { + void add(std::string_view s = {}) + { + T r; + from_string_view(s, r); + result.emplace_back(std::move(r)); + } + + void select_set(int n) override { } + + void on_simple_string(std::string_view s) override { add(s); } + void on_number(std::string_view s) override { add(s); } + void on_double(std::string_view s) override { add(s); } + void on_bool(std::string_view s) override { add(s); } + void on_big_number(std::string_view s) override { add(s); } + void on_verbatim_string(std::string_view s = {}) override { add(s); } + void on_blob_string(std::string_view s = {}) override { add(s); } + + basic_set_type result; +}; + +template +struct response_static_array : response_base { + int i_ = 0; + void on_blob_string(std::string_view s) override + { from_string_view(s, result[i_++]); } + void select_array(int n) override { } + + std::array result; +}; + +template +struct response_static_string : response_base { + void add(std::string_view s) + { result.assign(std::cbegin(s), std::cend(s));}; + void on_blob_string(std::string_view s) override + { add(s); } + void on_simple_string(std::string_view s) override + { add(s); } + + boost::static_string result; +}; + +template < + class T, + std::size_t N + > +struct response_basic_static_map : response_base { + int i_ = 0; + + void add(std::string_view s = {}) + { from_string_view(s, result.at(i_++)); } + void on_blob_string(std::string_view s) override + { add(s); } + void on_number(std::string_view s) override + { add(s); } + + void select_push(int n) override { } + + std::array result; +}; + +} // resp +} // aedis + diff --git a/include/aedis/utils.hpp b/include/aedis/detail/utils.hpp similarity index 100% rename from include/aedis/utils.hpp rename to include/aedis/detail/utils.hpp diff --git a/include/aedis/connection.ipp b/include/aedis/impl/connection.ipp similarity index 96% rename from include/aedis/connection.ipp rename to include/aedis/impl/connection.ipp index 5f9aae19..fca72427 100644 --- a/include/aedis/connection.ipp +++ b/include/aedis/impl/connection.ipp @@ -5,9 +5,8 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -#include "connection.hpp" - -#include "write.hpp" +#include +#include namespace aedis { diff --git a/include/aedis/read.ipp b/include/aedis/impl/read.ipp similarity index 95% rename from include/aedis/read.ipp rename to include/aedis/impl/read.ipp index 7d66c05e..0fd9c64b 100644 --- a/include/aedis/read.ipp +++ b/include/aedis/impl/read.ipp @@ -5,7 +5,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -#include "read.hpp" +#include namespace aedis { diff --git a/include/aedis/src.hpp b/include/aedis/impl/src.hpp similarity index 56% rename from include/aedis/src.hpp rename to include/aedis/impl/src.hpp index bf67d5d3..759b073c 100644 --- a/include/aedis/src.hpp +++ b/include/aedis/impl/src.hpp @@ -7,9 +7,10 @@ #pragma once -#include -#include -#include -#include -#include -#include +#include +#include +#include + +#include +#include +#include diff --git a/include/aedis/type.ipp b/include/aedis/impl/type.ipp similarity index 97% rename from include/aedis/type.ipp rename to include/aedis/impl/type.ipp index 312e6627..09c54bc0 100644 --- a/include/aedis/type.ipp +++ b/include/aedis/impl/type.ipp @@ -5,7 +5,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -#include "type.hpp" +#include #include @@ -13,7 +13,7 @@ namespace aedis { namespace resp { #define EXPAND_TYPE_CASE(x) case type::x: return #x -auto to_string(type t) +std::string to_string(type t) { switch (t) { EXPAND_TYPE_CASE(array); diff --git a/include/aedis/read.hpp b/include/aedis/read.hpp index 1891253d..f80a5afa 100644 --- a/include/aedis/read.hpp +++ b/include/aedis/read.hpp @@ -21,12 +21,13 @@ #include #include +#include +#include +#include + #include "config.hpp" #include "type.hpp" -#include "parser.hpp" #include "request.hpp" -#include "response_base.hpp" -#include "response_buffers.hpp" namespace aedis { namespace resp { diff --git a/include/aedis/receiver_base.hpp b/include/aedis/receiver_base.hpp index 35e4139a..47805df2 100644 --- a/include/aedis/receiver_base.hpp +++ b/include/aedis/receiver_base.hpp @@ -11,8 +11,6 @@ #include #include "type.hpp" -#include "utils.hpp" -#include "responses.hpp" #include "request.hpp" namespace aedis { diff --git a/include/aedis/request.hpp b/include/aedis/request.hpp index be1f0b5d..50915e48 100644 --- a/include/aedis/request.hpp +++ b/include/aedis/request.hpp @@ -16,8 +16,9 @@ #include #include +#include + #include "config.hpp" -#include "command.hpp" namespace aedis { namespace resp { diff --git a/include/aedis/resp_types.hpp b/include/aedis/resp_types.hpp index fa237273..79f5b915 100644 --- a/include/aedis/resp_types.hpp +++ b/include/aedis/resp_types.hpp @@ -69,7 +69,7 @@ using set_type = basic_set_type; using number_type = long long int; using bool_type = bool; -using double_type = double; +using double_type = std::string; using blob_string_type = basic_blob_string; using blob_error_type = basic_blob_error; using simple_string_type = basic_simple_string; diff --git a/include/aedis/response_base.hpp b/include/aedis/response_base.hpp deleted file mode 100644 index 509dcf1d..00000000 --- a/include/aedis/response_base.hpp +++ /dev/null @@ -1,57 +0,0 @@ -/* Copyright (c) 2019 - 2021 Marcelo Zimbres Silva (mzimbres at gmail dot com) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#pragma once - -#include -#include - -namespace aedis { namespace resp { - -class response_base { -protected: - virtual void on_simple_string_impl(std::string_view s) { throw std::runtime_error("on_simple_string_impl: Has not been overridden."); } - virtual void on_simple_error_impl(std::string_view s) { throw std::runtime_error("on_simple_error_impl: Has not been overridden."); } - virtual void on_number_impl(std::string_view s) { throw std::runtime_error("on_number_impl: Has not been overridden."); } - virtual void on_double_impl(std::string_view s) { throw std::runtime_error("on_double_impl: Has not been overridden."); } - virtual void on_null_impl() { throw std::runtime_error("on_null_impl: Has not been overridden."); } - virtual void on_bool_impl(std::string_view s) { throw std::runtime_error("on_bool_impl: Has not been overridden."); } - virtual void on_big_number_impl(std::string_view s) { throw std::runtime_error("on_big_number_impl: Has not been overridden."); } - virtual void on_verbatim_string_impl(std::string_view s = {}) { throw std::runtime_error("on_verbatim_string_impl: Has not been overridden."); } - virtual void on_blob_string_impl(std::string_view s = {}) { throw std::runtime_error("on_blob_string_impl: Has not been overridden."); } - virtual void on_blob_error_impl(std::string_view s = {}) { throw std::runtime_error("on_blob_error_impl: Has not been overridden."); } - virtual void on_streamed_string_part_impl(std::string_view s = {}) { throw std::runtime_error("on_streamed_string_part: Has not been overridden."); } - virtual void select_array_impl(int n) { throw std::runtime_error("select_array_impl: Has not been overridden."); } - virtual void select_set_impl(int n) { throw std::runtime_error("select_set_impl: Has not been overridden."); } - virtual void select_map_impl(int n) { throw std::runtime_error("select_map_impl: Has not been overridden."); } - virtual void select_push_impl(int n) { throw std::runtime_error("select_push_impl: Has not been overridden."); } - virtual void select_attribute_impl(int n) { throw std::runtime_error("select_attribute_impl: Has not been overridden."); } - -public: - virtual void pop() {} - void select_attribute(int n) { select_attribute_impl(n);} - void select_push(int n) { select_push_impl(n);} - void select_array(int n) { select_array_impl(n);} - void select_set(int n) { select_set_impl(n);} - void select_map(int n) { select_map_impl(n);} - void on_simple_error(std::string_view s) { on_simple_error_impl(s); } - void on_blob_error(std::string_view s = {}) { on_blob_error_impl(s); } - void on_null() { on_null_impl(); } - void on_simple_string(std::string_view s) { on_simple_string_impl(s); } - void on_number(std::string_view s) { on_number_impl(s); } - void on_double(std::string_view s) { on_double_impl(s); } - void on_bool(std::string_view s) { on_bool_impl(s); } - void on_big_number(std::string_view s) { on_big_number_impl(s); } - void on_verbatim_string(std::string_view s = {}) { on_verbatim_string_impl(s); } - void on_blob_string(std::string_view s = {}) { on_blob_string_impl(s); } - void on_streamed_string_part(std::string_view s = {}) { on_streamed_string_part_impl(s); } - virtual ~response_base() {} -}; - -} // resp -} // aedis - diff --git a/include/aedis/responses.hpp b/include/aedis/responses.hpp deleted file mode 100644 index 4f4aa54a..00000000 --- a/include/aedis/responses.hpp +++ /dev/null @@ -1,411 +0,0 @@ -/* Copyright (c) 2019 - 2021 Marcelo Zimbres Silva (mzimbres at gmail dot com) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.hpp" -#include "type.hpp" -#include "command.hpp" -#include "resp_types.hpp" -#include "response_base.hpp" - -#include - -namespace aedis { namespace resp { - -template -std::enable_if::value, void>::type -from_string_view(std::string_view s, T& n) -{ - auto r = std::from_chars(s.data(), s.data() + s.size(), n); - if (r.ec == std::errc::invalid_argument) - throw std::runtime_error("from_chars: Unable to convert"); -} - -inline -void from_string_view(std::string_view s, std::string& r) - { r = s; } - -class response_ignore : public response_base { -private: - void on_simple_string_impl(std::string_view s) override {} - void on_simple_error_impl(std::string_view s) override {} - void on_number_impl(std::string_view s) override {} - void on_double_impl(std::string_view s) override {} - void on_null_impl() override {} - void on_bool_impl(std::string_view s) override {} - void on_big_number_impl(std::string_view s) override {} - void on_verbatim_string_impl(std::string_view s = {}) override {} - void on_blob_string_impl(std::string_view s = {}) override {} - void on_blob_error_impl(std::string_view s = {}) override {} - void on_streamed_string_part_impl(std::string_view s = {}) override {} - void select_array_impl(int n) override {} - void select_set_impl(int n) override {} - void select_map_impl(int n) override {} - void select_push_impl(int n) override {} - void select_attribute_impl(int n) override {} -}; - -// This response type is able to deal with recursive redis responses -// as in a transaction for example. -class response_tree: public response_base { -public: - struct elem { - int depth; - type t; - int expected_size = -1; - std::vector value; - }; - - std::vector result; - -private: - int depth_ = 0; - - void add_aggregate(int n, type t) - { - if (depth_ == 0) { - result.reserve(n); - ++depth_; - return; - } - - result.emplace_back(depth_, t, n); - result.back().value.reserve(n); - ++depth_; - } - - void add(std::string_view s, type t) - { - if (std::empty(result)) { - result.emplace_back(depth_, t, 1, std::vector{std::string{s}}); - } else if (std::ssize(result.back().value) == result.back().expected_size) { - result.emplace_back(depth_, t, 1, std::vector{std::string{s}}); - } else { - result.back().value.push_back(std::string{s}); - } - } - - void select_array_impl(int n) override {add_aggregate(n, type::array);} - void select_push_impl(int n) override {add_aggregate(n, type::push);} - void select_set_impl(int n) override {add_aggregate(n, type::set);} - void select_map_impl(int n) override {add_aggregate(n, type::map);} - void select_attribute_impl(int n) override {add_aggregate(n, type::attribute);} - - void on_simple_string_impl(std::string_view s) override { add(s, type::simple_string); } - void on_simple_error_impl(std::string_view s) override { add(s, type::simple_error); } - void on_number_impl(std::string_view s) override {add(s, type::number);} - void on_double_impl(std::string_view s) override {add(s, type::double_type);} - void on_bool_impl(std::string_view s) override {add(s, type::boolean);} - void on_big_number_impl(std::string_view s) override {add(s, type::big_number);} - void on_null_impl() override {add({}, type::null);} - void on_blob_error_impl(std::string_view s = {}) override {add(s, type::blob_error);} - void on_verbatim_string_impl(std::string_view s = {}) override {add(s, type::verbatim_string);} - void on_blob_string_impl(std::string_view s = {}) override {add(s, type::blob_string);} - void on_streamed_string_part_impl(std::string_view s = {}) override {add(s, type::streamed_string_part);} - -public: - void clear() { result.clear(); depth_ = 0;} - auto size() const { return result.size(); } - void pop() override { --depth_; } -}; - -class response_number : public response_base { -private: - void on_number_impl(std::string_view s) override - { from_string_view(s, result); } - -public: - number_type result; -}; - -template< - class CharT, - class Traits = std::char_traits, - class Allocator = std::allocator> -class response_basic_blob_string : public response_base { -private: - void on_blob_string_impl(std::string_view s) override - { from_string_view(s, result); } -public: - basic_blob_string result; -}; - -template< - class CharT = char, - class Traits = std::char_traits, - class Allocator = std::allocator> -class response_basic_blob_error : public response_base { -private: - void on_blob_error_impl(std::string_view s) override - { from_string_view(s, result); } -public: - basic_blob_error result; -}; - -template< - class CharT = char, - class Traits = std::char_traits, - class Allocator = std::allocator - > -class response_basic_simple_string : public response_base { -private: - void on_simple_string_impl(std::string_view s) override - { from_string_view(s, result); } -public: - basic_simple_string result; -}; - -template< - class CharT = char, - class Traits = std::char_traits, - class Allocator = std::allocator - > -class response_basic_simple_error : public response_base { -private: - void on_simple_error_impl(std::string_view s) override - { from_string_view(s, result); } - -public: - basic_simple_error result; -}; - -// Big number uses strings at the moment as the underlying storage. -template < - class CharT = char, - class Traits = std::char_traits, - class Allocator = std::allocator - > -class response_basic_big_number : public response_base { -private: - void on_big_number_impl(std::string_view s) override - { from_string_view(s, result); } - -public: - basic_big_number result; -}; - -class response_double : public response_base { -private: - void on_double_impl(std::string_view s) override - { - std::string tmp {s}; - result = std::stod(tmp); - } - -public: - double_type result; -}; - -template< - class CharT = char, - class Traits = std::char_traits, - class Allocator = std::allocator - > -class response_basic_verbatim_string : public response_base { -private: - void on_verbatim_string_impl(std::string_view s) override - { from_string_view(s, result); } -public: - basic_verbatim_string result; -}; - -template< - class CharT = char, - class Traits = std::char_traits, - class Allocator = std::allocator - > -class response_basic_streamed_string_part : public response_base { -private: - void on_streamed_string_part_impl(std::string_view s) override - { result += s; } -public: - basic_streamed_string_part result; -}; - -class response_bool : public response_base { -private: - void on_bool_impl(std::string_view s) override - { - assert(std::ssize(s) == 1); - result = s[0] == 't'; - } - -public: - bool_type result; -}; - -template< - class Key, - class Compare = std::less, - class Allocator = std::allocator - > -class response_unordered_set : public response_base { -private: - void on_blob_string_impl(std::string_view s) override - { - Key r; - from_string_view(s, r); - result.insert(std::end(result), std::move(r)); - } - - void select_array_impl(int n) override { } - void select_set_impl(int n) override { } - -public: - std::set result; -}; - -template < - class T, - class Allocator = std::allocator - > -class response_basic_array : public response_base { -private: - void add(std::string_view s = {}) - { - T r; - from_string_view(s, r); - result.emplace_back(std::move(r)); - } - - // TODO: Call vector reserver. - void on_simple_string_impl(std::string_view s) override { add(s); } - void on_number_impl(std::string_view s) override { add(s); } - void on_double_impl(std::string_view s) override { add(s); } - void on_bool_impl(std::string_view s) override { add(s); } - void on_big_number_impl(std::string_view s) override { add(s); } - void on_verbatim_string_impl(std::string_view s = {}) override { add(s); } - void on_blob_string_impl(std::string_view s = {}) override { add(s); } - void select_array_impl(int n) override { } - void select_set_impl(int n) override { } - void select_map_impl(int n) override { } - void select_push_impl(int n) override { } - void on_streamed_string_part_impl(std::string_view s = {}) override { add(s); } - -public: - basic_array_type result; -}; - -template < - class T, - class Allocator = std::allocator - > -class response_basic_map : public response_base { -private: - void add(std::string_view s = {}) - { - T r; - from_string_view(s, r); - result.emplace_back(std::move(r)); - } - - void select_map_impl(int n) override { } - - // We also have to enable arrays, the hello command for example - // returns a map that has an embeded array. - void select_array_impl(int n) override { } - - void on_simple_string_impl(std::string_view s) override { add(s); } - void on_number_impl(std::string_view s) override { add(s); } - void on_double_impl(std::string_view s) override { add(s); } - void on_bool_impl(std::string_view s) override { add(s); } - void on_big_number_impl(std::string_view s) override { add(s); } - void on_verbatim_string_impl(std::string_view s = {}) override { add(s); } - void on_blob_string_impl(std::string_view s = {}) override { add(s); } - -public: - basic_map_type result; -}; - -template < - class T, - class Allocator = std::allocator - > -class response_basic_set : public response_base { -private: - void add(std::string_view s = {}) - { - T r; - from_string_view(s, r); - result.emplace_back(std::move(r)); - } - - void select_set_impl(int n) override { } - - void on_simple_string_impl(std::string_view s) override { add(s); } - void on_number_impl(std::string_view s) override { add(s); } - void on_double_impl(std::string_view s) override { add(s); } - void on_bool_impl(std::string_view s) override { add(s); } - void on_big_number_impl(std::string_view s) override { add(s); } - void on_verbatim_string_impl(std::string_view s = {}) override { add(s); } - void on_blob_string_impl(std::string_view s = {}) override { add(s); } - -public: - basic_set_type result; -}; - -template -class response_static_array : public response_base { -private: - int i_ = 0; - void on_blob_string_impl(std::string_view s) override - { from_string_view(s, result[i_++]); } - void select_array_impl(int n) override { } - -public: - std::array result; -}; - -template -class response_static_string : public response_base { -private: - void add(std::string_view s) - { result.assign(std::cbegin(s), std::cend(s));}; - void on_blob_string_impl(std::string_view s) override - { add(s); } - void on_simple_string_impl(std::string_view s) override - { add(s); } - -public: - boost::static_string result; -}; - -template < - class T, - std::size_t N - > -class response_basic_static_map : public response_base { -private: - int i_ = 0; - - void add(std::string_view s = {}) - { from_string_view(s, result.at(i_++)); } - void on_blob_string_impl(std::string_view s) override - { add(s); } - void on_number_impl(std::string_view s) override - { add(s); } - - void select_push_impl(int n) override { } - -public: - std::array result; -}; - -} // resp -} // aedis - diff --git a/include/aedis/version.hpp b/include/aedis/version.hpp index a0854981..e2cc8645 100644 --- a/include/aedis/version.hpp +++ b/include/aedis/version.hpp @@ -1,10 +1,10 @@ -/* Copyright (c) 2019 - 2020 Marcelo Zimbres Silva (mzimbres at gmail dot com) +/* Copyright (c) 2019 - 2021 Marcelo Zimbres Silva (mzimbres at gmail dot com) * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -#define AEDIS_VERSION 2 +#define AEDIS_VERSION 3 diff --git a/src/aedis.cpp b/src/aedis.cpp index 88ef7672..844bc01f 100644 --- a/src/aedis.cpp +++ b/src/aedis.cpp @@ -1 +1 @@ -#include +#include diff --git a/tests/general.cpp b/tests/general.cpp index 6888ec16..1d1c9300 100644 --- a/tests/general.cpp +++ b/tests/general.cpp @@ -480,25 +480,24 @@ net::awaitable floating_point() test_tcp_socket ts {cmd}; resp::response_double res; co_await resp::async_read(ts, buffer, res); - check_equal(res.result, 1.23, "double"); + check_equal(res.result, {"1.23"}, "double"); } - // TODO: Support INF. - //{ - // std::string cmd {",inf\r\n"}; - // test_tcp_socket ts {cmd}; - // resp::response_double res; - // co_await resp::async_read(ts, buffer, res); - // check_equal(res.result, {"inf"}, "double (inf)"); - //} + { + std::string cmd {",inf\r\n"}; + test_tcp_socket ts {cmd}; + resp::response_double res; + co_await resp::async_read(ts, buffer, res); + check_equal(res.result, {"inf"}, "double (inf)"); + } - //{ - // std::string cmd {",-inf\r\n"}; - // test_tcp_socket ts {cmd}; - // resp::response_double res; - // co_await resp::async_read(ts, buffer, res); - // check_equal(res.result, {"-inf"}, "double (-inf)"); - //} + { + std::string cmd {",-inf\r\n"}; + test_tcp_socket ts {cmd}; + resp::response_double res; + co_await resp::async_read(ts, buffer, res); + check_equal(res.result, {"-inf"}, "double (-inf)"); + } } @@ -676,7 +675,6 @@ int main(int argc, char* argv[]) co_spawn(ioc, set(), net::detached); co_spawn(ioc, map(), net::detached); - co_spawn(ioc, test_list(results), net::detached); co_spawn(ioc, test_set(results), net::detached);