Skip to content

Commit b365b96

Browse files
committed
Fixup Adds generic_flat_response typedef
1 parent 2c1f1c4 commit b365b96

7 files changed

Lines changed: 131 additions & 15 deletions

File tree

example/cpp20_chat_room.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2018-2022 Marcelo Zimbres Silva (mzimbres@gmail.com)
1+
/* Copyright (c) 2018-2025 Marcelo Zimbres Silva (mzimbres@gmail.com)
22
*
33
* Distributed under the Boost Software License, Version 1.0. (See
44
* accompanying file LICENSE.txt)
@@ -32,7 +32,7 @@ using boost::asio::dynamic_buffer;
3232
using boost::asio::redirect_error;
3333
using boost::redis::config;
3434
using boost::redis::connection;
35-
using boost::redis::resp3::flat_tree;
35+
using boost::redis::generic_flat_response;
3636
using boost::redis::request;
3737
using boost::system::error_code;
3838
using namespace std::chrono_literals;
@@ -45,7 +45,7 @@ auto receiver(std::shared_ptr<connection> conn) -> awaitable<void>
4545
request req;
4646
req.push("SUBSCRIBE", "channel");
4747

48-
flat_tree resp;
48+
generic_flat_response resp;
4949
conn->set_receive_response(resp);
5050

5151
while (conn->will_reconnect()) {
@@ -58,12 +58,12 @@ auto receiver(std::shared_ptr<connection> conn) -> awaitable<void>
5858
if (ec)
5959
break; // Connection lost, break so we can reconnect to channels.
6060

61-
for (auto const& elem: resp.get_view())
61+
for (auto const& elem: resp.value().get_view())
6262
std::cout << elem.value << "\n";
6363

6464
std::cout << std::endl;
6565

66-
resp.clear();
66+
resp.value().clear();
6767
}
6868
}
6969
}

example/cpp20_subscriber.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
namespace asio = boost::asio;
2222
using namespace std::chrono_literals;
2323
using boost::redis::request;
24-
using boost::redis::resp3::flat_tree;
24+
using boost::redis::generic_flat_response;
2525
using boost::redis::config;
2626
using boost::system::error_code;
2727
using boost::redis::connection;
@@ -49,7 +49,7 @@ auto receiver(std::shared_ptr<connection> conn) -> asio::awaitable<void>
4949
request req;
5050
req.push("SUBSCRIBE", "channel");
5151

52-
flat_tree resp;
52+
generic_flat_response resp;
5353
conn->set_receive_response(resp);
5454

5555
// Loop while reconnection is enabled
@@ -66,12 +66,12 @@ auto receiver(std::shared_ptr<connection> conn) -> asio::awaitable<void>
6666

6767
// The response must be consumed without suspending the
6868
// coroutine i.e. without the use of async operations.
69-
for (auto const& elem: resp.get_view())
69+
for (auto const& elem: resp.value().get_view())
7070
std::cout << elem.value << "\n";
7171

7272
std::cout << std::endl;
7373

74-
resp.clear();
74+
resp.value().clear();
7575
}
7676
}
7777
}

include/boost/redis/adapter/detail/adapters.hpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <boost/redis/resp3/serialization.hpp>
1414
#include <boost/redis/resp3/type.hpp>
1515
#include <boost/redis/resp3/flat_tree.hpp>
16+
#include <boost/redis/response.hpp>
1617

1718
#include <boost/assert.hpp>
1819

@@ -205,6 +206,45 @@ class general_aggregate<resp3::tree> {
205206
}
206207
};
207208

209+
template <>
210+
class general_aggregate<generic_flat_response> {
211+
private:
212+
generic_flat_response* tree_ = nullptr;
213+
214+
public:
215+
explicit general_aggregate(generic_flat_response* c = nullptr)
216+
: tree_(c)
217+
{ }
218+
219+
void on_init() { }
220+
void on_done()
221+
{
222+
BOOST_ASSERT_MSG(!!tree_, "Unexpected null pointer");
223+
if (tree_->has_value()) {
224+
tree_->value().notify_done();
225+
}
226+
}
227+
228+
template <class String>
229+
void on_node(resp3::basic_node<String> const& nd, system::error_code&)
230+
{
231+
BOOST_ASSERT_MSG(!!tree_, "Unexpected null pointer");
232+
switch (nd.data_type) {
233+
case resp3::type::blob_error:
234+
case resp3::type::simple_error:
235+
*tree_ = error{
236+
nd.data_type,
237+
std::string{std::cbegin(nd.value), std::cend(nd.value)}
238+
};
239+
break;
240+
default:
241+
if (tree_->has_value()) {
242+
(**tree_).push(nd);
243+
}
244+
}
245+
}
246+
};
247+
208248
template <>
209249
class general_aggregate<resp3::flat_tree> {
210250
private:

include/boost/redis/adapter/detail/response_traits.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,14 @@ struct response_traits<resp3::flat_tree> {
115115
static auto adapt(response_type& v) noexcept { return adapter_type{&v}; }
116116
};
117117

118+
template <>
119+
struct response_traits<generic_flat_response> {
120+
using response_type = generic_flat_response;
121+
using adapter_type = general_aggregate<response_type>;
122+
123+
static auto adapt(response_type& v) noexcept { return adapter_type{&v}; }
124+
};
125+
118126
template <class... Ts>
119127
struct response_traits<response<Ts...>> {
120128
using response_type = response<Ts...>;

include/boost/redis/adapter/detail/result_traits.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@ struct result_traits<resp3::basic_tree<String>> {
7171
static auto adapt(response_type& v) noexcept { return adapter_type{&v}; }
7272
};
7373

74+
template <>
75+
struct result_traits<generic_flat_response> {
76+
using response_type = generic_flat_response;
77+
using adapter_type = general_aggregate<response_type>;
78+
static auto adapt(response_type& v) noexcept { return adapter_type{&v}; }
79+
};
80+
7481
template <>
7582
struct result_traits<resp3::flat_tree> {
7683
using response_type = resp3::flat_tree;

include/boost/redis/response.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <boost/redis/adapter/result.hpp>
1111
#include <boost/redis/resp3/node.hpp>
1212
#include <boost/redis/resp3/tree.hpp>
13+
#include <boost/redis/resp3/flat_tree.hpp>
1314

1415
#include <boost/system/error_code.hpp>
1516

@@ -32,6 +33,9 @@ using response = std::tuple<adapter::result<Ts>...>;
3233
*/
3334
using generic_response = adapter::result<resp3::tree>;
3435

36+
/// Similar to @ref boost::redis::generic_response but stores data contiguously.
37+
using generic_flat_response = adapter::result<resp3::flat_tree>;
38+
3539
/** @brief (Deprecated) Consume on response from a generic response
3640
*
3741
* This function rotates the elements so that the start of the next

test/test_low_level_sync_sans_io.cpp

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ using boost::redis::adapter::adapt2;
2424
using boost::redis::adapter::result;
2525
using boost::redis::resp3::tree;
2626
using boost::redis::resp3::flat_tree;
27+
using boost::redis::generic_flat_response;
2728
using boost::redis::ignore_t;
2829
using boost::redis::resp3::detail::deserialize;
2930
using boost::redis::resp3::node;
@@ -375,25 +376,45 @@ tree from_flat(flat_tree const& resp)
375376
return ret;
376377
}
377378

379+
tree from_flat(generic_flat_response const& resp)
380+
{
381+
tree ret;
382+
for (auto const& e: resp.value().get_view())
383+
ret.push_back(from_node_view(e));
384+
385+
return ret;
386+
}
387+
388+
378389
// Parses the same data into a tree and a
379390
// flat_tree, they should be equal to each other.
380391
BOOST_AUTO_TEST_CASE(flat_tree_views_are_set)
381392
{
382393
tree resp1;
383-
flat_tree fresp;
394+
flat_tree resp2;
395+
generic_flat_response resp3;
384396

385397
error_code ec;
386398
deserialize(resp3_set, adapt2(resp1), ec);
387399
BOOST_CHECK_EQUAL(ec, error_code{});
388400

389-
deserialize(resp3_set, adapt2(fresp), ec);
401+
deserialize(resp3_set, adapt2(resp2), ec);
390402
BOOST_CHECK_EQUAL(ec, error_code{});
391403

392-
BOOST_CHECK_EQUAL(fresp.get_reallocs(), 1u);
393-
BOOST_CHECK_EQUAL(fresp.get_total_msgs(), 1u);
404+
deserialize(resp3_set, adapt2(resp3), ec);
405+
BOOST_CHECK_EQUAL(ec, error_code{});
406+
407+
BOOST_CHECK_EQUAL(resp2.get_reallocs(), 1u);
408+
BOOST_CHECK_EQUAL(resp2.get_total_msgs(), 1u);
409+
410+
BOOST_CHECK_EQUAL(resp3.value().get_reallocs(), 1u);
411+
BOOST_CHECK_EQUAL(resp3.value().get_total_msgs(), 1u);
412+
413+
auto const tmp2 = from_flat(resp2);
414+
BOOST_CHECK_EQUAL(resp1, tmp2);
394415

395-
auto const resp2 = from_flat(fresp);
396-
BOOST_CHECK_EQUAL(resp1, resp2);
416+
auto const tmp3 = from_flat(resp3);
417+
BOOST_CHECK_EQUAL(resp1, tmp3);
397418
}
398419

399420
// The response should be reusable.
@@ -446,3 +467,39 @@ BOOST_AUTO_TEST_CASE(flat_tree_copy_assign)
446467
BOOST_TEST((copy2 == resp));
447468
BOOST_TEST((copy3 == resp));
448469
}
470+
471+
BOOST_AUTO_TEST_CASE(generic_flat_response_simple_error)
472+
{
473+
generic_flat_response resp;
474+
475+
char const* wire = "-Error\r\n";
476+
477+
error_code ec;
478+
deserialize(wire, adapt2(resp), ec);
479+
BOOST_CHECK_EQUAL(ec, error_code{});
480+
481+
BOOST_TEST(!resp.has_value());
482+
BOOST_TEST(resp.has_error());
483+
auto const error = resp.error();
484+
485+
BOOST_CHECK_EQUAL(error.data_type, boost::redis::resp3::type::simple_error);
486+
BOOST_CHECK_EQUAL(error.diagnostic, std::string{"Error"});
487+
}
488+
489+
BOOST_AUTO_TEST_CASE(generic_flat_response_blob_error)
490+
{
491+
generic_flat_response resp;
492+
493+
char const* wire = "!5\r\nError\r\n";
494+
495+
error_code ec;
496+
deserialize(wire, adapt2(resp), ec);
497+
BOOST_CHECK_EQUAL(ec, error_code{});
498+
499+
BOOST_TEST(!resp.has_value());
500+
BOOST_TEST(resp.has_error());
501+
auto const error = resp.error();
502+
503+
BOOST_CHECK_EQUAL(error.data_type, boost::redis::resp3::type::blob_error);
504+
BOOST_CHECK_EQUAL(error.diagnostic, std::string{"Error"});
505+
}

0 commit comments

Comments
 (0)