GCC Code Coverage Report


Directory: libs/json/include/boost/json/
File: detail/value_to.hpp
Date: 2025-12-23 17:35:06
Exec Total Coverage
Lines: 157 157 100.0%
Functions: 362 372 97.3%
Branches: 80 82 97.6%

Line Branch Exec Source
1 //
2 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
4 // Copyright (c) 2021 Dmitry Arkhipov (grisumbras@gmail.com)
5 //
6 // Distributed under the Boost Software License, Version 1.0. (See accompanying
7 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 //
9 // Official repository: https://github.com/boostorg/json
10 //
11
12 #ifndef BOOST_JSON_DETAIL_VALUE_TO_HPP
13 #define BOOST_JSON_DETAIL_VALUE_TO_HPP
14
15 #ifndef BOOST_JSON_INTRUSIVE_INDEX_INC
16 #define BOOST_JSON_INTRUSIVE_INDEX_INC ((void)0);
17 #endif
18
19 #ifndef BOOST_JSON_INTRUSIVE_PATH_PUSH
20 #define BOOST_JSON_INTRUSIVE_PATH_PUSH(x) ((void)0);
21 #endif
22
23 #ifndef BOOST_JSON_INTRUSIVE_PATH_POP
24 #define BOOST_JSON_INTRUSIVE_PATH_POP ((void)0);
25 #endif
26
27 #ifndef BOOST_JSON_INTRUSIVE_MESSAGE
28 #define BOOST_JSON_INTRUSIVE_MESSAGE(x) ((void)0);
29 #endif
30
31
32 #include <boost/json/value.hpp>
33 #include <boost/json/conversion.hpp>
34 #include <boost/json/result_for.hpp>
35 #include <boost/describe/enum_from_string.hpp>
36
37 #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
38 # include <optional>
39 #endif
40
41 namespace boost {
42 namespace json {
43
44 namespace detail {
45
46 template<class T>
47 using has_reserve_member_helper = decltype(std::declval<T&>().reserve(0));
48 template<class T>
49 using has_reserve_member = mp11::mp_valid<has_reserve_member_helper, T>;
50 template<class T>
51 using reserve_implementation = mp11::mp_cond<
52 is_tuple_like<T>, mp11::mp_int<2>,
53 has_reserve_member<T>, mp11::mp_int<1>,
54 mp11::mp_true, mp11::mp_int<0>>;
55
56 template<class T>
57 error
58 78 try_reserve(
59 T&,
60 std::size_t size,
61 mp11::mp_int<2>)
62 {
63 78 constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
64
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 11 times.
78 if ( N != size )
65 60 return error::size_mismatch;
66 18 return error();
67 }
68
69 template<typename T>
70 error
71 147 try_reserve(
72 T& cont,
73 std::size_t size,
74 mp11::mp_int<1>)
75 {
76 147 cont.reserve(size);
77 147 return error();
78 }
79
80 template<typename T>
81 error
82 114 try_reserve(
83 T&,
84 std::size_t,
85 mp11::mp_int<0>)
86 {
87 114 return error();
88 }
89
90
91 // identity conversion
92 template< class Ctx >
93 system::result<value>
94 value_to_impl(
95 value_conversion_tag,
96 try_value_to_tag<value>,
97 value const& jv,
98 Ctx const& )
99 {
100 return jv;
101 }
102
103 template< class Ctx >
104 value
105 value_to_impl(
106 value_conversion_tag, value_to_tag<value>, value const& jv, Ctx const& )
107 {
108 return jv;
109 }
110
111 // object
112 template< class Ctx >
113 system::result<object>
114 24 value_to_impl(
115 object_conversion_tag,
116 try_value_to_tag<object>,
117 value const& jv,
118 Ctx const& )
119 {
120 24 object const* obj = jv.if_object();
121
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
24 if( obj )
122
1/1
✓ Branch 1 taken 6 times.
12 return *obj;
123 12 system::error_code ec;
124 12 BOOST_JSON_FAIL(ec, error::not_object);
125 12 return ec;
126 }
127
128 // array
129 template< class Ctx >
130 system::result<array>
131 24 value_to_impl(
132 array_conversion_tag,
133 try_value_to_tag<array>,
134 value const& jv,
135 Ctx const& )
136 {
137 24 array const* arr = jv.if_array();
138
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
24 if( arr )
139
1/1
✓ Branch 1 taken 6 times.
12 return *arr;
140 12 system::error_code ec;
141 12 BOOST_JSON_FAIL(ec, error::not_array);
142 12 return ec;
143 }
144
145 // string
146 template< class Ctx >
147 system::result<string>
148 24 value_to_impl(
149 string_conversion_tag,
150 try_value_to_tag<string>,
151 value const& jv,
152 Ctx const& )
153 {
154 24 string const* str = jv.if_string();
155
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
24 if( str )
156
1/1
✓ Branch 1 taken 6 times.
12 return *str;
157 12 system::error_code ec;
158 12 BOOST_JSON_FAIL(ec, error::not_string);
159 12 return ec;
160 }
161
162 // bool
163 template< class Ctx >
164 system::result<bool>
165 91 value_to_impl(
166 bool_conversion_tag, try_value_to_tag<bool>, value const& jv, Ctx const& )
167 {
168 91 auto b = jv.if_bool();
169
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 7 times.
91 if( b )
170 78 return *b;
171 13 system::error_code ec;
172 13 BOOST_JSON_FAIL(ec, error::not_bool);
173 13 return {boost::system::in_place_error, ec};
174 }
175
176 // integral and floating point
177 template< class T, class Ctx >
178 system::result<T>
179 6788 value_to_impl(
180 number_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
181 {
182 6788 system::error_code ec;
183 6788 auto const n = jv.to_number<T>(ec);
184
2/2
✓ Branch 1 taken 55 times.
✓ Branch 2 taken 3341 times.
6788 if( ec.failed() )
185 110 return {boost::system::in_place_error, ec};
186 6678 return {boost::system::in_place_value, n};
187 }
188
189 // null-like conversion
190 template< class T, class Ctx >
191 system::result<T>
192 112 value_to_impl(
193 null_like_conversion_tag,
194 try_value_to_tag<T>,
195 value const& jv,
196 Ctx const& )
197 {
198
2/2
✓ Branch 1 taken 35 times.
✓ Branch 2 taken 21 times.
112 if( jv.is_null() )
199 70 return {boost::system::in_place_value, T{}};
200 42 system::error_code ec;
201 42 BOOST_JSON_FAIL(ec, error::not_null);
202 42 return {boost::system::in_place_error, ec};
203 }
204
205 // string-like types
206 template< class T, class Ctx >
207 system::result<T>
208 145 value_to_impl(
209 string_like_conversion_tag,
210 try_value_to_tag<T>,
211 value const& jv,
212 Ctx const& )
213 {
214 145 auto str = jv.if_string();
215
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 12 times.
145 if( str )
216
1/1
✓ Branch 2 taken 67 times.
121 return {boost::system::in_place_value, T(str->subview())};
217 24 system::error_code ec;
218 24 BOOST_JSON_FAIL(ec, error::not_string);
219 24 return {boost::system::in_place_error, ec};
220 }
221
222 // map-like containers
223 template< class T, class Ctx >
224 system::result<T>
225 148 value_to_impl(
226 map_like_conversion_tag,
227 try_value_to_tag<T>,
228 value const& jv,
229 Ctx const& ctx )
230 {
231 148 object const* obj = jv.if_object();
232
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 62 times.
148 if( !obj )
233 {
234 24 system::error_code ec;
235 24 BOOST_JSON_FAIL(ec, error::not_object);
236 24 return {boost::system::in_place_error, ec};
237 }
238
239
1/1
✓ Branch 1 taken 12 times.
124 T res;
240
1/1
✓ Branch 2 taken 6 times.
124 error const e = detail::try_reserve(
241 res, obj->size(), reserve_implementation<T>());
242
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 50 times.
124 if( e != error() )
243 {
244 24 system::error_code ec;
245 24 BOOST_JSON_FAIL( ec, e );
246 24 return {boost::system::in_place_error, ec};
247 }
248
249
1/1
✓ Branch 1 taken 50 times.
100 auto ins = detail::inserter(res, inserter_implementation<T>());
250
4/5
✓ Branch 2 taken 98 times.
✓ Branch 3 taken 36 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 7 times.
294 for( key_value_pair const& kv: *obj )
251 {
252
1/1
✓ Branch 2 taken 43 times.
208 auto elem_res = try_value_to<mapped_type<T>>( kv.value(), ctx );
253
2/2
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 91 times.
208 if( elem_res.has_error() )
254 26 return {boost::system::in_place_error, elem_res.error()};
255
2/2
✓ Branch 1 taken 91 times.
✓ Branch 6 taken 91 times.
182 *ins++ = value_type<T>{
256
1/1
✓ Branch 2 taken 91 times.
364 key_type<T>(kv.key()),
257 182 std::move(*elem_res)};
258 }
259 74 return res;
260 124 }
261
262 // all other containers
263 template< class T, class Ctx >
264 system::result<T>
265 237 value_to_impl(
266 sequence_conversion_tag,
267 try_value_to_tag<T>,
268 value const& jv,
269 Ctx const& ctx )
270 {
271 237 array const* arr = jv.if_array();
272
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 107 times.
237 if( !arr )
273 {
274 24 system::error_code ec;
275 24 BOOST_JSON_FAIL(ec, error::not_array);
276 24 return {boost::system::in_place_error, ec};
277 }
278
279 157 T result;
280
1/1
✓ Branch 2 taken 67 times.
213 error const e = detail::try_reserve(
281 result, arr->size(), reserve_implementation<T>());
282
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 89 times.
213 if( e != error() )
283 {
284 36 system::error_code ec;
285 36 BOOST_JSON_FAIL( ec, e );
286 36 return {boost::system::in_place_error, ec};
287 }
288
289
1/1
✓ Branch 1 taken 79 times.
177 auto ins = detail::inserter(result, inserter_implementation<T>());
290
291 BOOST_JSON_INTRUSIVE_PATH_PUSH(-1)
292
293
4/5
✓ Branch 2 taken 3190 times.
✓ Branch 3 taken 100 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 39 times.
✓ Branch 6 taken 15 times.
6683 for( value const& val: *arr )
294 {
295 BOOST_JSON_INTRUSIVE_INDEX_INC
296
297
1/1
✓ Branch 1 taken 110 times.
6454 auto elem_res = try_value_to<value_type<T>>( val, ctx );
298
2/2
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 3216 times.
6454 if( elem_res.has_error() )
299 26 return {boost::system::in_place_error, elem_res.error()};
300
1/1
✓ Branch 5 taken 200 times.
6428 *ins++ = std::move(*elem_res);
301 }
302
303 BOOST_JSON_INTRUSIVE_PATH_POP
304
305 151 return result;
306 157 }
307
308 // tuple-like types
309 template< class T, class Ctx >
310 system::result<T>
311 456 try_make_tuple_elem(value const& jv, Ctx const& ctx, system::error_code& ec)
312 {
313
2/2
✓ Branch 1 taken 38 times.
✓ Branch 2 taken 192 times.
456 if( ec.failed() )
314 76 return {boost::system::in_place_error, ec};
315
316
1/1
✓ Branch 1 taken 73 times.
380 auto result = try_value_to<T>( jv, ctx );
317 380 ec = result.error();
318 380 return result;
319 114 }
320
321 template <class T, class Ctx, std::size_t... Is>
322 system::result<T>
323 181 try_make_tuple_like(
324 array const& arr, Ctx const& ctx, boost::mp11::index_sequence<Is...>)
325 {
326 181 system::error_code ec;
327
3/3
✓ Branch 1 taken 37 times.
✓ Branch 9 taken 10 times.
✓ Branch 5 taken 44 times.
217 auto items = std::make_tuple(
328 try_make_tuple_elem<
329
4/4
✓ Branch 2 taken 13 times.
✓ Branch 6 taken 13 times.
✓ Branch 10 taken 1 times.
✓ Branch 14 taken 1 times.
221 typename std::decay<tuple_element_t<Is, T>>::type >(
330 arr[Is], ctx, ec)
331 ...);
332 #if defined(BOOST_GCC)
333 # pragma GCC diagnostic push
334 # pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
335 #endif
336
2/2
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 78 times.
181 if( ec.failed() )
337 26 return {boost::system::in_place_error, ec};
338 #if defined(BOOST_GCC)
339 # pragma GCC diagnostic pop
340 #endif
341
342 return {
343
1/1
✓ Branch 8 taken 18 times.
155 boost::system::in_place_value, T(std::move(*std::get<Is>(items))...)};
344 108 }
345
346 template< class T, class Ctx >
347 system::result<T>
348 229 value_to_impl(
349 tuple_conversion_tag,
350 try_value_to_tag<T>,
351 value const& jv,
352 Ctx const& ctx )
353 {
354 229 system::error_code ec;
355
356 229 array const* arr = jv.if_array();
357
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 103 times.
229 if( !arr )
358 {
359 24 BOOST_JSON_FAIL(ec, error::not_array);
360 24 return {boost::system::in_place_error, ec};
361 }
362
363 205 constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
364
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 91 times.
205 if( N != arr->size() )
365 {
366 24 BOOST_JSON_FAIL(ec, error::size_mismatch);
367 24 return {boost::system::in_place_error, ec};
368 }
369
370
1/1
✓ Branch 1 taken 31 times.
61 return try_make_tuple_like<T>(
371
1/1
✓ Branch 1 taken 60 times.
181 *arr, ctx, boost::mp11::make_index_sequence<N>());
372 }
373
374 template< class Ctx, class T >
375 struct to_described_member
376 {
377 using Ds = described_members<T>;
378
379 system::result<T>& res;
380 object const& obj;
381 Ctx const& ctx;
382
383 template< class I >
384 void
385 operator()(I)
386 {
387 if( !res )
388 return;
389
390 using D = mp11::mp_at<Ds, I>;
391 using M = described_member_t<T, D>;
392
393 auto const found = obj.find(D::name);
394 if( found == obj.end() )
395 {
396 BOOST_IF_CONSTEXPR( !is_optional_like<M>::value )
397 {
398 system::error_code ec;
399 BOOST_JSON_FAIL(ec, error::size_mismatch);
400 res = {boost::system::in_place_error, ec};
401
402 BOOST_JSON_INTRUSIVE_MESSAGE(std::format("the key >> {} << is non optional and missing in path {}", D::name, BOOST_JSON_INTRUSIVE::composePath()));
403 }
404 return;
405 }
406
407 BOOST_JSON_INTRUSIVE_PATH_PUSH(D::name)
408
409 #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
410 # pragma GCC diagnostic push
411 # pragma GCC diagnostic ignored "-Wunused"
412 # pragma GCC diagnostic ignored "-Wunused-variable"
413 #endif
414 auto member_res = try_value_to<M>( found->value(), ctx );
415 #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
416 # pragma GCC diagnostic pop
417 #endif
418 if( member_res ){
419 (*res).* D::pointer = std::move(*member_res);
420 BOOST_JSON_INTRUSIVE_PATH_POP
421 }
422 else
423 res = {boost::system::in_place_error, member_res.error()};
424 }
425 };
426
427 // described classes
428 template< class T, class Ctx >
429 system::result<T>
430 value_to_impl(
431 described_class_conversion_tag,
432 try_value_to_tag<T>,
433 value const& jv,
434 Ctx const& ctx )
435 {
436 BOOST_STATIC_ASSERT( std::is_default_constructible<T>::value );
437 system::result<T> res;
438
439 auto* obj = jv.if_object();
440 if( !obj )
441 {
442 system::error_code ec;
443 BOOST_JSON_FAIL(ec, error::not_object);
444 res = {boost::system::in_place_error, ec};
445 return res;
446 }
447
448 to_described_member<Ctx, T> member_converter{res, *obj, ctx};
449
450 using Ds = typename decltype(member_converter)::Ds;
451 constexpr std::size_t N = mp11::mp_size<Ds>::value;
452 mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
453
454 if( !res )
455 return res;
456
457 return res;
458 }
459
460 // described enums
461 template< class T, class Ctx >
462 system::result<T>
463 value_to_impl(
464 described_enum_conversion_tag,
465 try_value_to_tag<T>,
466 value const& jv,
467 Ctx const& )
468 {
469 T val = {};
470 (void)jv;
471 #ifdef BOOST_DESCRIBE_CXX14
472 system::error_code ec;
473
474 auto str = jv.if_string();
475 if( !str )
476 {
477 BOOST_JSON_FAIL(ec, error::not_string);
478 return {system::in_place_error, ec};
479 }
480
481 if( !describe::enum_from_string(str->data(), val) )
482 {
483 BOOST_JSON_FAIL(ec, error::unknown_name);
484 return {system::in_place_error, ec};
485 }
486 #endif
487
488 return {system::in_place_value, val};
489 }
490
491 // optionals
492 template< class T, class Ctx >
493 system::result<T>
494 value_to_impl(
495 optional_conversion_tag,
496 try_value_to_tag<T>,
497 value const& jv,
498 Ctx const& ctx)
499 {
500 using Inner = value_result_type<T>;
501 if( jv.is_null() )
502 return {};
503 else
504 return try_value_to<Inner>(jv, ctx);
505 }
506
507 // variants
508 template< class T, class V, class I >
509 using variant_construction_category = mp11::mp_cond<
510 std::is_constructible< T, variant2::in_place_index_t<I::value>, V >,
511 mp11::mp_int<2>,
512 #ifndef BOOST_NO_CXX17_HDR_VARIANT
513 std::is_constructible< T, std::in_place_index_t<I::value>, V >,
514 mp11::mp_int<1>,
515 #endif // BOOST_NO_CXX17_HDR_VARIANT
516 mp11::mp_true,
517 mp11::mp_int<0> >;
518
519 template< class T, class I, class V >
520 T
521 initialize_variant( V&& v, mp11::mp_int<0> )
522 {
523 T t;
524 t.template emplace<I::value>( std::move(v) );
525 return t;
526 }
527
528 template< class T, class I, class V >
529 T
530 initialize_variant( V&& v, mp11::mp_int<2> )
531 {
532 return T( variant2::in_place_index_t<I::value>(), std::move(v) );
533 }
534
535 #ifndef BOOST_NO_CXX17_HDR_VARIANT
536 template< class T, class I, class V >
537 T
538 initialize_variant( V&& v, mp11::mp_int<1> )
539 {
540 return T( std::in_place_index_t<I::value>(), std::move(v) );
541 }
542 #endif // BOOST_NO_CXX17_HDR_VARIANT
543
544
545 template< class T, class Ctx >
546 struct alternative_converter
547 {
548 system::result<T>& res;
549 value const& jv;
550 Ctx const& ctx;
551
552 template< class I >
553 void operator()( I ) const
554 {
555 if( res )
556 return;
557
558 using V = mp11::mp_at<T, I>;
559 auto attempt = try_value_to<V>(jv, ctx);
560 if( attempt )
561 {
562 using cat = variant_construction_category<T, V, I>;
563 res = initialize_variant<T, I>( std::move(*attempt), cat() );
564 }
565 }
566 };
567
568 template< class T, class Ctx >
569 system::result<T>
570 value_to_impl(
571 variant_conversion_tag,
572 try_value_to_tag<T>,
573 value const& jv,
574 Ctx const& ctx)
575 {
576 system::error_code ec;
577 BOOST_JSON_FAIL(ec, error::exhausted_variants);
578
579 using Is = mp11::mp_iota< mp11::mp_size<T> >;
580
581 system::result<T> res = {system::in_place_error, ec};
582 mp11::mp_for_each<Is>( alternative_converter<T, Ctx>{res, jv, ctx} );
583 return res;
584 }
585
586 template< class T, class Ctx >
587 system::result<T>
588 value_to_impl(
589 path_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
590 {
591 auto str = jv.if_string();
592 if( !str )
593 {
594 system::error_code ec;
595 BOOST_JSON_FAIL(ec, error::not_string);
596 return {boost::system::in_place_error, ec};
597 }
598
599 string_view sv = str->subview();
600 return {boost::system::in_place_value, T( sv.begin(), sv.end() )};
601 }
602
603 //----------------------------------------------------------
604 // User-provided conversions; throwing -> throwing
605 template< class T, class Ctx >
606 mp11::mp_if< mp11::mp_valid<has_user_conversion_to_impl, T>, T >
607 1 value_to_impl(
608 user_conversion_tag, value_to_tag<T> tag, value const& jv, Ctx const&)
609 {
610 1 return tag_invoke(tag, jv);
611 }
612
613 template<
614 class T,
615 class Ctx,
616 class Sup = supported_context<Ctx, T, value_to_conversion>
617 >
618 mp11::mp_if<
619 mp11::mp_valid< has_context_conversion_to_impl, typename Sup::type, T>, T >
620 1 value_to_impl(
621 context_conversion_tag,
622 value_to_tag<T> tag,
623 value const& jv,
624 Ctx const& ctx )
625 {
626 1 return tag_invoke( tag, jv, Sup::get(ctx) );
627 }
628
629 template<
630 class T,
631 class Ctx,
632 class Sup = supported_context<Ctx, T, value_to_conversion>
633 >
634 mp11::mp_if<
635 mp11::mp_valid<
636 has_full_context_conversion_to_impl, typename Sup::type, T>,
637 T>
638 value_to_impl(
639 full_context_conversion_tag,
640 value_to_tag<T> tag,
641 value const& jv,
642 Ctx const& ctx )
643 {
644 return tag_invoke( tag, jv, Sup::get(ctx), ctx );
645 }
646
647 //----------------------------------------------------------
648 // User-provided conversions; throwing -> nonthrowing
649 template< class T, class Ctx >
650 mp11::mp_if_c< !mp11::mp_valid<has_user_conversion_to_impl, T>::value, T>
651 119 value_to_impl(
652 user_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& )
653 {
654
1/1
✓ Branch 1 taken 48 times.
119 auto res = tag_invoke(try_value_to_tag<T>(), jv);
655
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 48 times.
119 if( res.has_error() )
656 24 throw_system_error( res.error() );
657 190 return std::move(*res);
658 64 }
659
660 template<
661 class T,
662 class Ctx,
663 class Sup = supported_context<Ctx, T, value_to_conversion>
664 >
665 mp11::mp_if_c<
666 !mp11::mp_valid<
667 has_context_conversion_to_impl, typename Sup::type, T>::value,
668 T>
669 3 value_to_impl(
670 context_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& ctx )
671 {
672 3 auto res = tag_invoke( try_value_to_tag<T>(), jv, Sup::get(ctx) );
673
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
3 if( res.has_error() )
674 1 throw_system_error( res.error() );
675 4 return std::move(*res);
676 }
677
678 template<
679 class T,
680 class Ctx,
681 class Sup = supported_context<Ctx, T, value_to_conversion>
682 >
683 mp11::mp_if_c<
684 !mp11::mp_valid<
685 has_full_context_conversion_to_impl, typename Sup::type, T>::value,
686 T>
687 value_to_impl(
688 full_context_conversion_tag,
689 value_to_tag<T>,
690 value const& jv,
691 Ctx const& ctx )
692 {
693 auto res = tag_invoke(try_value_to_tag<T>(), jv, Sup::get(ctx), ctx);
694 if( res.has_error() )
695 throw_system_error( res.error() );
696 return std::move(*res);
697 }
698
699 //----------------------------------------------------------
700 // User-provided conversions; nonthrowing -> nonthrowing
701 template< class T, class Ctx >
702 mp11::mp_if<
703 mp11::mp_valid<
704 has_nonthrowing_user_conversion_to_impl, T>, system::result<T> >
705 238 value_to_impl(
706 user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
707 {
708
1/1
✓ Branch 1 taken 10 times.
246 return tag_invoke(try_value_to_tag<T>(), jv);
709 }
710
711 template<
712 class T,
713 class Ctx,
714 class Sup = supported_context<Ctx, T, value_to_conversion>
715 >
716 mp11::mp_if<
717 mp11::mp_valid<
718 has_nonthrowing_context_conversion_to_impl, typename Sup::type, T>,
719 system::result<T> >
720 value_to_impl(
721 context_conversion_tag,
722 try_value_to_tag<T> tag,
723 value const& jv,
724 Ctx const& ctx )
725 {
726 return tag_invoke( tag, jv, Sup::get(ctx) );
727 }
728
729 template<
730 class T,
731 class Ctx,
732 class Sup = supported_context<Ctx, T, value_to_conversion>
733 >
734 mp11::mp_if<
735 mp11::mp_valid<
736 has_nonthrowing_full_context_conversion_to_impl,
737 typename Sup::type,
738 T>,
739 system::result<T> >
740 value_to_impl(
741 full_context_conversion_tag,
742 try_value_to_tag<T> tag,
743 value const& jv,
744 Ctx const& ctx )
745 {
746 return tag_invoke( tag, jv, Sup::get(ctx), ctx );
747 }
748
749 //----------------------------------------------------------
750 // User-provided conversions; nonthrowing -> throwing
751
752 template< class T, class... Args >
753 system::result<T>
754 72 wrap_conversion_exceptions( value_to_tag<T>, Args&& ... args )
755 {
756 #ifndef BOOST_NO_EXCEPTIONS
757 try
758 {
759 #endif
760 return {
761 boost::system::in_place_value,
762
1/1
✓ Branch 1 taken 12 times.
72 tag_invoke( value_to_tag<T>(), static_cast<Args&&>(args)... )};
763 #ifndef BOOST_NO_EXCEPTIONS
764 }
765
3/3
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 6 times.
60 catch( std::bad_alloc const&)
766 {
767 12 throw;
768 }
769 24 catch( system::system_error const& e)
770 {
771 24 return {boost::system::in_place_error, e.code()};
772 }
773 24 catch( ... )
774 {
775 12 system::error_code ec;
776 12 BOOST_JSON_FAIL(ec, error::exception);
777 12 return {boost::system::in_place_error, ec};
778 }
779 #endif
780 }
781
782 template< class T, class Ctx >
783 mp11::mp_if_c<
784 !mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>::value,
785 system::result<T> >
786 72 value_to_impl(
787 user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
788 {
789 72 return wrap_conversion_exceptions(value_to_tag<T>(), jv);
790 }
791
792 template<
793 class T,
794 class Ctx,
795 class Sup = supported_context<Ctx, T, value_to_conversion>
796 >
797 mp11::mp_if_c<
798 !mp11::mp_valid<
799 has_nonthrowing_context_conversion_to_impl,
800 typename Sup::type,
801 T>::value,
802 system::result<T> >
803 value_to_impl(
804 context_conversion_tag,
805 try_value_to_tag<T>,
806 value const& jv,
807 Ctx const& ctx )
808 {
809 return wrap_conversion_exceptions( value_to_tag<T>(), jv, Sup::get(ctx) );
810 }
811
812 template<
813 class T,
814 class Ctx,
815 class Sup = supported_context<Ctx, T, value_to_conversion>
816 >
817 mp11::mp_if_c<
818 !mp11::mp_valid<
819 has_nonthrowing_full_context_conversion_to_impl,
820 typename Sup::type,
821 T>::value,
822 system::result<T> >
823 value_to_impl(
824 full_context_conversion_tag,
825 try_value_to_tag<T>,
826 value const& jv,
827 Ctx const& ctx )
828 {
829 return wrap_conversion_exceptions(
830 value_to_tag<T>(), jv, Sup::get(ctx), ctx);
831 }
832
833 // no suitable conversion implementation
834 template< class T, class Ctx >
835 T
836 value_to_impl( no_conversion_tag, value_to_tag<T>, value const&, Ctx const& )
837 {
838 static_assert(
839 !std::is_same<T, T>::value,
840 "No suitable tag_invoke overload found for the type");
841 }
842
843 // generic wrapper over non-throwing implementations
844 template< class Impl, class T, class Ctx >
845 T
846 339 value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx )
847 {
848 339 return value_to_impl(impl, try_value_to_tag<T>(), jv, ctx).value();
849 }
850
851 template< class Ctx, class T >
852 using value_to_category = conversion_category<
853 Ctx, T, value_to_conversion >;
854
855 } // detail
856
857 #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
858 inline
859 system::result<std::nullopt_t>
860 tag_invoke(
861 try_value_to_tag<std::nullopt_t>,
862 value const& jv)
863 {
864 if( jv.is_null() )
865 return std::nullopt;
866 system::error_code ec;
867 BOOST_JSON_FAIL(ec, error::not_null);
868 return ec;
869 }
870 #endif
871
872 } // namespace json
873 } // namespace boost
874
875 #endif
876