GCC Code Coverage Report


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