37
37
namespace boost ::redis::adapter::detail
38
38
{
39
39
40
- // Serialization.
40
+ template < class > struct is_integral : std::false_type {};
41
41
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 {};
49
45
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 ;
55
48
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 <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 <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 <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
+ {
59
87
#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;
68
96
#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;
72
100
#endif // _LIBCPP_VERSION
73
- }
101
+ }
102
+ };
74
103
75
104
template <class CharT , class Traits , class Allocator >
105
+ struct converter <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 >
118
+ struct from_bulk_impl {
119
+ template <class String >
120
+ static void
121
+ apply (
122
+ T& t,
123
+ resp3::basic_node<String> const & node,
124
+ system::error_code& ec)
125
+ {
126
+ converter<T>::apply (t, node, ec);
127
+ }
128
+ };
129
+
130
+ template <class T >
131
+ struct from_bulk_impl <std::optional<T>> {
132
+ template <class String >
133
+ static void
134
+ apply (
135
+ std::optional<T>& op,
136
+ resp3::basic_node<String> const & node,
137
+ system::error_code& ec)
138
+ {
139
+ if (node.data_type != resp3::type::null) {
140
+ op.emplace (T{});
141
+ converter<T>::apply (op.value (), node, ec);
142
+ }
143
+ }
144
+ };
145
+
146
+ template <class T , class String >
76
147
void
77
148
boost_redis_from_bulk (
78
- std::basic_string<CharT, Traits, Allocator>& s ,
79
- std::string_view sv ,
80
- system::error_code&)
149
+ T& t ,
150
+ resp3::basic_node<String> const & node ,
151
+ system::error_code& ec )
81
152
{
82
- s. append (sv. data (), sv. size () );
153
+ from_bulk_impl<T>:: apply (t, node, ec );
83
154
}
84
155
85
156
// ================================================
@@ -138,14 +209,14 @@ class simple_impl {
138
209
void on_value_available (Result&) {}
139
210
140
211
template <class String >
141
- void operator ()(Result& result, resp3::basic_node<String> const & n , system::error_code& ec)
212
+ void operator ()(Result& result, resp3::basic_node<String> const & node , system::error_code& ec)
142
213
{
143
- if (is_aggregate (n .data_type )) {
214
+ if (is_aggregate (node .data_type )) {
144
215
ec = redis::error::expects_resp3_simple_type;
145
216
return ;
146
217
}
147
218
148
- boost_redis_from_bulk (result, n. value , ec);
219
+ boost_redis_from_bulk (result, node , ec);
149
220
}
150
221
};
151
222
@@ -175,7 +246,7 @@ class set_impl {
175
246
}
176
247
177
248
typename Result::key_type obj;
178
- boost_redis_from_bulk (obj, nd. value , ec);
249
+ boost_redis_from_bulk (obj, nd, ec);
179
250
hint_ = result.insert (hint_, std::move (obj));
180
251
}
181
252
};
@@ -208,11 +279,11 @@ class map_impl {
208
279
209
280
if (on_key_) {
210
281
typename Result::key_type obj;
211
- boost_redis_from_bulk (obj, nd. value , ec);
282
+ boost_redis_from_bulk (obj, nd, ec);
212
283
current_ = result.insert (current_, {std::move (obj), {}});
213
284
} else {
214
285
typename Result::mapped_type obj;
215
- boost_redis_from_bulk (obj, nd. value , ec);
286
+ boost_redis_from_bulk (obj, nd, ec);
216
287
current_->second = std::move (obj);
217
288
}
218
289
@@ -233,7 +304,7 @@ class vector_impl {
233
304
result.reserve (result.size () + m * nd.aggregate_size );
234
305
} else {
235
306
result.push_back ({});
236
- boost_redis_from_bulk (result.back (), nd. value , ec);
307
+ boost_redis_from_bulk (result.back (), nd, ec);
237
308
}
238
309
}
239
310
};
@@ -266,7 +337,7 @@ class array_impl {
266
337
}
267
338
268
339
BOOST_ASSERT (nd.aggregate_size == 1 );
269
- boost_redis_from_bulk (result.at (i_), nd. value , ec);
340
+ boost_redis_from_bulk (result.at (i_), nd, ec);
270
341
}
271
342
272
343
++i_;
@@ -289,7 +360,7 @@ struct list_impl {
289
360
}
290
361
291
362
result.push_back ({});
292
- boost_redis_from_bulk (result.back (), nd. value , ec);
363
+ boost_redis_from_bulk (result.back (), nd, ec);
293
364
}
294
365
}
295
366
};
@@ -340,13 +411,14 @@ struct impl_map<std::deque<T, Allocator>> { using type = list_impl<std::deque<T,
340
411
template <class >
341
412
class wrapper ;
342
413
343
- template <class Result >
344
- class wrapper <result<Result >> {
414
+ template <class T >
415
+ class wrapper <result<T >> {
345
416
public:
346
- using response_type = result<Result >;
417
+ using response_type = result<T >;
347
418
private:
348
419
response_type* result_;
349
- typename impl_map<Result>::type impl_;
420
+ typename impl_map<T>::type impl_;
421
+ bool called_once_ = false ;
350
422
351
423
template <class String >
352
424
bool set_if_resp3_error (resp3::basic_node<String> const & nd) noexcept
@@ -366,7 +438,7 @@ class wrapper<result<Result>> {
366
438
explicit wrapper (response_type* t = nullptr ) : result_(t)
367
439
{
368
440
if (result_) {
369
- result_->value () = Result {};
441
+ result_->value () = T {};
370
442
impl_.on_value_available (result_->value ());
371
443
}
372
444
}
@@ -379,7 +451,7 @@ class wrapper<result<Result>> {
379
451
if (result_->has_error ())
380
452
return ;
381
453
382
- if (set_if_resp3_error (nd))
454
+ if (! std::exchange (called_once_, true ) && set_if_resp3_error (nd))
383
455
return ;
384
456
385
457
BOOST_ASSERT (result_);
@@ -395,6 +467,7 @@ class wrapper<result<std::optional<T>>> {
395
467
private:
396
468
response_type* result_;
397
469
typename impl_map<T>::type impl_{};
470
+ bool called_once_ = false ;
398
471
399
472
template <class String >
400
473
bool set_if_resp3_error (resp3::basic_node<String> const & nd) noexcept
@@ -426,7 +499,7 @@ class wrapper<result<std::optional<T>>> {
426
499
if (set_if_resp3_error (nd))
427
500
return ;
428
501
429
- if (nd.data_type == resp3::type::null)
502
+ if (! std::exchange (called_once_, true ) && nd.data_type == resp3::type::null)
430
503
return ;
431
504
432
505
if (!result_->value ().has_value ()) {
0 commit comments