GCC Code Coverage Report


Directory: libs/json/include/boost/json/
File: detail/value_to.hpp
Date: 2025-12-23 17:22:01
Exec Total Coverage
Lines: 166 166 100.0%
Functions: 311 320 97.2%
Branches: 82 83 98.8%

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