Skip to content

Commit 93a32d3

Browse files
committed
Uses class specialization instead of function overload. [skip-ci]
1 parent 31ceed9 commit 93a32d3

File tree

5 files changed

+126
-45
lines changed

5 files changed

+126
-45
lines changed

example/cpp20_json.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <boost/redis/resp3/serialization.hpp>
2222

2323
namespace asio = boost::asio;
24+
namespace resp3 = boost::redis::resp3;
2425
using namespace boost::describe;
2526
using boost::redis::request;
2627
using boost::redis::response;
@@ -42,8 +43,14 @@ BOOST_DESCRIBE_STRUCT(user, (), (name, age, country))
4243
void boost_redis_to_bulk(std::string& to, user const& u)
4344
{ boost::redis::resp3::boost_redis_to_bulk(to, boost::json::serialize(boost::json::value_from(u))); }
4445

45-
void boost_redis_from_bulk(user& u, std::string_view sv, boost::system::error_code&)
46-
{ u = boost::json::value_to<user>(boost::json::parse(sv)); }
46+
void
47+
boost_redis_from_bulk(
48+
user& u,
49+
resp3::node_view const& node,
50+
boost::system::error_code&)
51+
{
52+
u = boost::json::value_to<user>(boost::json::parse(node.value));
53+
}
4754

4855
auto co_main(config cfg) -> asio::awaitable<void>
4956
{

example/cpp20_protobuf.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#if defined(BOOST_ASIO_HAS_CO_AWAIT)
2020

2121
namespace asio = boost::asio;
22+
namespace resp3 = boost::redis::resp3;
2223
using boost::redis::request;
2324
using boost::redis::response;
2425
using boost::redis::operation;
@@ -45,9 +46,13 @@ void boost_redis_to_bulk(std::string& to, person const& u)
4546
boost::redis::resp3::boost_redis_to_bulk(to, tmp);
4647
}
4748

48-
void boost_redis_from_bulk(person& u, std::string_view sv, boost::system::error_code& ec)
49+
void
50+
boost_redis_from_bulk(
51+
person& u,
52+
resp3::node_view const& node,
53+
boost::system::error_code& ec)
4954
{
50-
std::string const tmp {sv};
55+
std::string const tmp {node.value};
5156
if (!u.ParseFromString(tmp))
5257
ec = boost::redis::error::invalid_data_type;
5358
}

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

Lines changed: 83 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -37,49 +37,91 @@
3737
namespace boost::redis::adapter::detail
3838
{
3939

40-
// Serialization.
40+
template <class> struct is_integral : std::false_type {};
4141

42-
template <class T>
43-
auto boost_redis_from_bulk(T& i, std::string_view sv, system::error_code& ec) -> typename std::enable_if<std::is_integral<T>::value, void>::type
44-
{
45-
auto const res = std::from_chars(sv.data(), sv.data() + std::size(sv), i);
46-
if (res.ec != std::errc())
47-
ec = redis::error::not_a_number;
48-
}
42+
template <> struct is_integral<long long int > : std::true_type {};
43+
template <> struct is_integral<unsigned long long int> : std::true_type {};
44+
template <> struct is_integral<int > : std::true_type {};
4945

50-
inline
51-
void boost_redis_from_bulk(bool& t, std::string_view sv, system::error_code&)
52-
{
53-
t = *sv.data() == 't';
54-
}
46+
template<class T, bool = is_integral<T>::value>
47+
struct converter_impl;
5548

56-
inline
57-
void boost_redis_from_bulk(double& d, std::string_view sv, system::error_code& ec)
58-
{
49+
template<class T>
50+
struct converter_impl<T, true> {
51+
template <class String>
52+
static void
53+
apply(
54+
T& i,
55+
resp3::basic_node<String> const& node,
56+
system::error_code& ec)
57+
{
58+
auto const res =
59+
std::from_chars(node.value.data(), node.value.data() + node.value.size(), i);
60+
if (res.ec != std::errc())
61+
ec = redis::error::not_a_number;
62+
}
63+
};
64+
65+
template<>
66+
struct converter_impl<bool, false> {
67+
template <class String>
68+
static void
69+
apply(
70+
bool& t,
71+
resp3::basic_node<String> const& node,
72+
system::error_code& ec)
73+
{
74+
t = *node.value.data() == 't';
75+
}
76+
};
77+
78+
template<>
79+
struct converter_impl<double, false> {
80+
template <class String>
81+
static void
82+
apply(
83+
double& d,
84+
resp3::basic_node<String> const& node,
85+
system::error_code& ec)
86+
{
5987
#ifdef _LIBCPP_VERSION
60-
// The string in sv is not null terminated and we also don't know
61-
// if there is enough space at the end for a null char. The easiest
62-
// thing to do is to create a temporary.
63-
std::string const tmp{sv.data(), sv.data() + std::size(sv)};
64-
char* end{};
65-
d = std::strtod(tmp.data(), &end);
66-
if (d == HUGE_VAL || d == 0)
67-
ec = redis::error::not_a_double;
88+
// The string in node.value is not null terminated and we also
89+
// don't know if there is enough space at the end for a null
90+
// char. The easiest thing to do is to create a temporary.
91+
std::string const tmp{node.value.data(), node.value.data() + node.value.size()};
92+
char* end{};
93+
d = std::strtod(tmp.data(), &end);
94+
if (d == HUGE_VAL || d == 0)
95+
ec = redis::error::not_a_double;
6896
#else
69-
auto const res = std::from_chars(sv.data(), sv.data() + std::size(sv), d);
70-
if (res.ec != std::errc())
71-
ec = redis::error::not_a_double;
97+
auto const res = std::from_chars(node.value.data(), node.value.data() + node.value.size(), d);
98+
if (res.ec != std::errc())
99+
ec = redis::error::not_a_double;
72100
#endif // _LIBCPP_VERSION
73-
}
101+
}
102+
};
74103

75104
template <class CharT, class Traits, class Allocator>
105+
struct converter_impl<std::basic_string<CharT, Traits, Allocator>, false> {
106+
template <class String>
107+
static void
108+
apply(
109+
std::basic_string<CharT, Traits, Allocator>& s,
110+
resp3::basic_node<String> const& node,
111+
system::error_code&)
112+
{
113+
s.append(node.value.data(), node.value.size());
114+
}
115+
};
116+
117+
template <class T, class String>
76118
void
77119
boost_redis_from_bulk(
78-
std::basic_string<CharT, Traits, Allocator>& s,
79-
std::string_view sv,
80-
system::error_code&)
120+
T& t,
121+
resp3::basic_node<String> const& node,
122+
system::error_code& ec)
81123
{
82-
s.append(sv.data(), sv.size());
124+
converter_impl<T>::apply(t, node, ec);
83125
}
84126

85127
//================================================
@@ -138,14 +180,14 @@ class simple_impl {
138180
void on_value_available(Result&) {}
139181

140182
template <class String>
141-
void operator()(Result& result, resp3::basic_node<String> const& n, system::error_code& ec)
183+
void operator()(Result& result, resp3::basic_node<String> const& node, system::error_code& ec)
142184
{
143-
if (is_aggregate(n.data_type)) {
185+
if (is_aggregate(node.data_type)) {
144186
ec = redis::error::expects_resp3_simple_type;
145187
return;
146188
}
147189

148-
boost_redis_from_bulk(result, n.value, ec);
190+
boost_redis_from_bulk(result, node, ec);
149191
}
150192
};
151193

@@ -175,7 +217,7 @@ class set_impl {
175217
}
176218

177219
typename Result::key_type obj;
178-
boost_redis_from_bulk(obj, nd.value, ec);
220+
boost_redis_from_bulk(obj, nd, ec);
179221
hint_ = result.insert(hint_, std::move(obj));
180222
}
181223
};
@@ -208,11 +250,11 @@ class map_impl {
208250

209251
if (on_key_) {
210252
typename Result::key_type obj;
211-
boost_redis_from_bulk(obj, nd.value, ec);
253+
boost_redis_from_bulk(obj, nd, ec);
212254
current_ = result.insert(current_, {std::move(obj), {}});
213255
} else {
214256
typename Result::mapped_type obj;
215-
boost_redis_from_bulk(obj, nd.value, ec);
257+
boost_redis_from_bulk(obj, nd, ec);
216258
current_->second = std::move(obj);
217259
}
218260

@@ -233,7 +275,7 @@ class vector_impl {
233275
result.reserve(result.size() + m * nd.aggregate_size);
234276
} else {
235277
result.push_back({});
236-
boost_redis_from_bulk(result.back(), nd.value, ec);
278+
boost_redis_from_bulk(result.back(), nd, ec);
237279
}
238280
}
239281
};
@@ -266,7 +308,7 @@ class array_impl {
266308
}
267309

268310
BOOST_ASSERT(nd.aggregate_size == 1);
269-
boost_redis_from_bulk(result.at(i_), nd.value, ec);
311+
boost_redis_from_bulk(result.at(i_), nd, ec);
270312
}
271313

272314
++i_;
@@ -289,7 +331,7 @@ struct list_impl {
289331
}
290332

291333
result.push_back({});
292-
boost_redis_from_bulk(result.back(), nd.value, ec);
334+
boost_redis_from_bulk(result.back(), nd, ec);
293335
}
294336
}
295337
};

include/boost/redis/resp3/node.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ auto operator==(basic_node<String> const& a, basic_node<String> const& b)
5959
*/
6060
using node = basic_node<std::string>;
6161

62+
using node_view = basic_node<std::string_view>;
63+
6264
} // boost::redis::resp3
6365

6466
#endif // BOOST_REDIS_RESP3_NODE_HPP

test/test_low_level_sync_sans_io.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,4 +199,29 @@ BOOST_AUTO_TEST_CASE(issue_210_no_nested)
199199
exit(EXIT_FAILURE);
200200
}
201201
}
202+
// char const* wire = "*6\r\n+orange\r\n+apple\r\n_\r\n+two\r\n+three\r\n+orange\r\n";
203+
// $ ./test/boost_redis_test_low_level_sync_sans_io --run_test=issue_233_array_with_nil
204+
// Running 1 test case...
205+
// : Got RESP3 null. [boost.redis:15]
206+
//
207+
BOOST_AUTO_TEST_CASE(issue_233_array_with_nil)
208+
{
209+
try {
210+
result<std::vector<std::optional<std::string>>> resp;
211+
212+
char const* wire = "*6\r\n+orange\r\n+apple\r\n_\r\n+two\r\n+three\r\n+orange\r\n";
213+
deserialize(wire, adapt2(resp));
214+
215+
for (auto const& e: resp.value()) {
216+
if (e)
217+
std::cout << e.value() << std::endl;
218+
else
219+
std::cout << "null" << std::endl;
220+
}
221+
222+
} catch (std::exception const& e) {
223+
std::cerr << e.what() << std::endl;
224+
exit(EXIT_FAILURE);
225+
}
226+
}
202227

0 commit comments

Comments
 (0)