GCC Code Coverage Report


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