GCC Code Coverage Report


Directory: libs/json/include/boost/json/
File: detail/value_to.hpp
Date: 2026-01-06 03:55:48
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 static_assert(
378 uniquely_named_members<T>::value,
379 "The type has several described members with the same name.");
380
381 using Ds = described_members<T>;
382
383 system::result<T>& res;
384 object const& obj;
385 Ctx const& ctx;
386
387 template< class I >
388 void
389 operator()(I)
390 {
391 if( !res )
392 return;
393
394 using D = mp11::mp_at<Ds, I>;
395 using M = described_member_t<T, D>;
396
397 auto const found = obj.find(D::name);
398 if( found == obj.end() )
399 {
400 BOOST_IF_CONSTEXPR( !is_optional_like<M>::value )
401 {
402 system::error_code ec;
403 BOOST_JSON_FAIL(ec, error::size_mismatch);
404 res = {boost::system::in_place_error, ec};
405
406 BOOST_JSON_INTRUSIVE_MESSAGE(std::format("the key >> {} << is non optional and missing in path {}", D::name, BOOST_JSON_INTRUSIVE::composePath()));
407 }
408 return;
409 }
410
411 BOOST_JSON_INTRUSIVE_PATH_PUSH(D::name)
412
413 #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
414 # pragma GCC diagnostic push
415 # pragma GCC diagnostic ignored "-Wunused"
416 # pragma GCC diagnostic ignored "-Wunused-variable"
417 #endif
418 auto member_res = try_value_to<M>( found->value(), ctx );
419 #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
420 # pragma GCC diagnostic pop
421 #endif
422 if( member_res ){
423 (*res).* D::pointer = std::move(*member_res);
424 BOOST_JSON_INTRUSIVE_PATH_POP
425 }
426 else
427 res = {boost::system::in_place_error, member_res.error()};
428 }
429 };
430
431 // described classes
432 template< class T, class Ctx >
433 system::result<T>
434 value_to_impl(
435 described_class_conversion_tag,
436 try_value_to_tag<T>,
437 value const& jv,
438 Ctx const& ctx )
439 {
440 BOOST_STATIC_ASSERT( std::is_default_constructible<T>::value );
441 system::result<T> res;
442
443 auto* obj = jv.if_object();
444 if( !obj )
445 {
446 system::error_code ec;
447 BOOST_JSON_FAIL(ec, error::not_object);
448 res = {boost::system::in_place_error, ec};
449 return res;
450 }
451
452 to_described_member<Ctx, T> member_converter{res, *obj, ctx};
453
454 using Ds = typename decltype(member_converter)::Ds;
455 constexpr std::size_t N = mp11::mp_size<Ds>::value;
456 mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
457
458 if( !res )
459 return res;
460
461 return res;
462 }
463
464 // described enums
465 template< class T, class Ctx >
466 system::result<T>
467 value_to_impl(
468 described_enum_conversion_tag,
469 try_value_to_tag<T>,
470 value const& jv,
471 Ctx const& )
472 {
473 T val = {};
474 (void)jv;
475 #ifdef BOOST_DESCRIBE_CXX14
476 system::error_code ec;
477
478 auto str = jv.if_string();
479 if( !str )
480 {
481 BOOST_JSON_FAIL(ec, error::not_string);
482 return {system::in_place_error, ec};
483 }
484
485 if( !describe::enum_from_string(str->data(), val) )
486 {
487 BOOST_JSON_FAIL(ec, error::unknown_name);
488 return {system::in_place_error, ec};
489 }
490 #endif
491
492 return {system::in_place_value, val};
493 }
494
495 // optionals
496 template< class T, class Ctx >
497 system::result<T>
498 value_to_impl(
499 optional_conversion_tag,
500 try_value_to_tag<T>,
501 value const& jv,
502 Ctx const& ctx)
503 {
504 using Inner = value_result_type<T>;
505 if( jv.is_null() )
506 return {};
507 else
508 return try_value_to<Inner>(jv, ctx);
509 }
510
511 // variants
512 template< class T, class V, class I >
513 using variant_construction_category = mp11::mp_cond<
514 std::is_constructible< T, variant2::in_place_index_t<I::value>, V >,
515 mp11::mp_int<2>,
516 #ifndef BOOST_NO_CXX17_HDR_VARIANT
517 std::is_constructible< T, std::in_place_index_t<I::value>, V >,
518 mp11::mp_int<1>,
519 #endif // BOOST_NO_CXX17_HDR_VARIANT
520 mp11::mp_true,
521 mp11::mp_int<0> >;
522
523 template< class T, class I, class V >
524 T
525 initialize_variant( V&& v, mp11::mp_int<0> )
526 {
527 T t;
528 t.template emplace<I::value>( std::move(v) );
529 return t;
530 }
531
532 template< class T, class I, class V >
533 T
534 initialize_variant( V&& v, mp11::mp_int<2> )
535 {
536 return T( variant2::in_place_index_t<I::value>(), std::move(v) );
537 }
538
539 #ifndef BOOST_NO_CXX17_HDR_VARIANT
540 template< class T, class I, class V >
541 T
542 initialize_variant( V&& v, mp11::mp_int<1> )
543 {
544 return T( std::in_place_index_t<I::value>(), std::move(v) );
545 }
546 #endif // BOOST_NO_CXX17_HDR_VARIANT
547
548
549 template< class T, class Ctx >
550 struct alternative_converter
551 {
552 system::result<T>& res;
553 value const& jv;
554 Ctx const& ctx;
555
556 template< class I >
557 void operator()( I ) const
558 {
559 if( res )
560 return;
561
562 using V = mp11::mp_at<T, I>;
563 auto attempt = try_value_to<V>(jv, ctx);
564 if( attempt )
565 {
566 using cat = variant_construction_category<T, V, I>;
567 res = initialize_variant<T, I>( std::move(*attempt), cat() );
568 }
569 }
570 };
571
572 template< class T, class Ctx >
573 system::result<T>
574 value_to_impl(
575 variant_conversion_tag,
576 try_value_to_tag<T>,
577 value const& jv,
578 Ctx const& ctx)
579 {
580 system::error_code ec;
581 BOOST_JSON_FAIL(ec, error::exhausted_variants);
582
583 using Is = mp11::mp_iota< mp11::mp_size<T> >;
584
585 system::result<T> res = {system::in_place_error, ec};
586 mp11::mp_for_each<Is>( alternative_converter<T, Ctx>{res, jv, ctx} );
587 return res;
588 }
589
590 template< class T, class Ctx >
591 system::result<T>
592 value_to_impl(
593 path_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
594 {
595 auto str = jv.if_string();
596 if( !str )
597 {
598 system::error_code ec;
599 BOOST_JSON_FAIL(ec, error::not_string);
600 return {boost::system::in_place_error, ec};
601 }
602
603 string_view sv = str->subview();
604 return {boost::system::in_place_value, T( sv.begin(), sv.end() )};
605 }
606
607 //----------------------------------------------------------
608 // User-provided conversions; throwing -> throwing
609 template< class T, class Ctx >
610 mp11::mp_if< mp11::mp_valid<has_user_conversion_to_impl, T>, T >
611 1 value_to_impl(
612 user_conversion_tag, value_to_tag<T> tag, value const& jv, Ctx const&)
613 {
614 1 return tag_invoke(tag, jv);
615 }
616
617 template<
618 class T,
619 class Ctx,
620 class Sup = supported_context<Ctx, T, value_to_conversion>
621 >
622 mp11::mp_if<
623 mp11::mp_valid< has_context_conversion_to_impl, typename Sup::type, T>, T >
624 1 value_to_impl(
625 context_conversion_tag,
626 value_to_tag<T> tag,
627 value const& jv,
628 Ctx const& ctx )
629 {
630 1 return tag_invoke( tag, jv, Sup::get(ctx) );
631 }
632
633 template<
634 class T,
635 class Ctx,
636 class Sup = supported_context<Ctx, T, value_to_conversion>
637 >
638 mp11::mp_if<
639 mp11::mp_valid<
640 has_full_context_conversion_to_impl, typename Sup::type, T>,
641 T>
642 value_to_impl(
643 full_context_conversion_tag,
644 value_to_tag<T> tag,
645 value const& jv,
646 Ctx const& ctx )
647 {
648 return tag_invoke( tag, jv, Sup::get(ctx), ctx );
649 }
650
651 //----------------------------------------------------------
652 // User-provided conversions; throwing -> nonthrowing
653 template< class T, class Ctx >
654 mp11::mp_if_c< !mp11::mp_valid<has_user_conversion_to_impl, T>::value, T>
655 119 value_to_impl(
656 user_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& )
657 {
658
1/1
✓ Branch 1 taken 48 times.
119 auto res = tag_invoke(try_value_to_tag<T>(), jv);
659
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 48 times.
119 if( res.has_error() )
660 24 throw_system_error( res.error() );
661 190 return std::move(*res);
662 64 }
663
664 template<
665 class T,
666 class Ctx,
667 class Sup = supported_context<Ctx, T, value_to_conversion>
668 >
669 mp11::mp_if_c<
670 !mp11::mp_valid<
671 has_context_conversion_to_impl, typename Sup::type, T>::value,
672 T>
673 3 value_to_impl(
674 context_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& ctx )
675 {
676 3 auto res = tag_invoke( try_value_to_tag<T>(), jv, Sup::get(ctx) );
677
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
3 if( res.has_error() )
678 1 throw_system_error( res.error() );
679 4 return std::move(*res);
680 }
681
682 template<
683 class T,
684 class Ctx,
685 class Sup = supported_context<Ctx, T, value_to_conversion>
686 >
687 mp11::mp_if_c<
688 !mp11::mp_valid<
689 has_full_context_conversion_to_impl, typename Sup::type, T>::value,
690 T>
691 value_to_impl(
692 full_context_conversion_tag,
693 value_to_tag<T>,
694 value const& jv,
695 Ctx const& ctx )
696 {
697 auto res = tag_invoke(try_value_to_tag<T>(), jv, Sup::get(ctx), ctx);
698 if( res.has_error() )
699 throw_system_error( res.error() );
700 return std::move(*res);
701 }
702
703 //----------------------------------------------------------
704 // User-provided conversions; nonthrowing -> nonthrowing
705 template< class T, class Ctx >
706 mp11::mp_if<
707 mp11::mp_valid<
708 has_nonthrowing_user_conversion_to_impl, T>, system::result<T> >
709 238 value_to_impl(
710 user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
711 {
712
1/1
✓ Branch 1 taken 10 times.
246 return tag_invoke(try_value_to_tag<T>(), jv);
713 }
714
715 template<
716 class T,
717 class Ctx,
718 class Sup = supported_context<Ctx, T, value_to_conversion>
719 >
720 mp11::mp_if<
721 mp11::mp_valid<
722 has_nonthrowing_context_conversion_to_impl, typename Sup::type, T>,
723 system::result<T> >
724 value_to_impl(
725 context_conversion_tag,
726 try_value_to_tag<T> tag,
727 value const& jv,
728 Ctx const& ctx )
729 {
730 return tag_invoke( tag, jv, Sup::get(ctx) );
731 }
732
733 template<
734 class T,
735 class Ctx,
736 class Sup = supported_context<Ctx, T, value_to_conversion>
737 >
738 mp11::mp_if<
739 mp11::mp_valid<
740 has_nonthrowing_full_context_conversion_to_impl,
741 typename Sup::type,
742 T>,
743 system::result<T> >
744 value_to_impl(
745 full_context_conversion_tag,
746 try_value_to_tag<T> tag,
747 value const& jv,
748 Ctx const& ctx )
749 {
750 return tag_invoke( tag, jv, Sup::get(ctx), ctx );
751 }
752
753 //----------------------------------------------------------
754 // User-provided conversions; nonthrowing -> throwing
755
756 template< class T, class... Args >
757 system::result<T>
758 72 wrap_conversion_exceptions( value_to_tag<T>, Args&& ... args )
759 {
760 #ifndef BOOST_NO_EXCEPTIONS
761 try
762 {
763 #endif
764 return {
765 boost::system::in_place_value,
766
1/1
✓ Branch 1 taken 12 times.
72 tag_invoke( value_to_tag<T>(), static_cast<Args&&>(args)... )};
767 #ifndef BOOST_NO_EXCEPTIONS
768 }
769
3/3
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 6 times.
60 catch( std::bad_alloc const&)
770 {
771 12 throw;
772 }
773 24 catch( system::system_error const& e)
774 {
775 24 return {boost::system::in_place_error, e.code()};
776 }
777 24 catch( ... )
778 {
779 12 system::error_code ec;
780 12 BOOST_JSON_FAIL(ec, error::exception);
781 12 return {boost::system::in_place_error, ec};
782 }
783 #endif
784 }
785
786 template< class T, class Ctx >
787 mp11::mp_if_c<
788 !mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>::value,
789 system::result<T> >
790 72 value_to_impl(
791 user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
792 {
793 72 return wrap_conversion_exceptions(value_to_tag<T>(), jv);
794 }
795
796 template<
797 class T,
798 class Ctx,
799 class Sup = supported_context<Ctx, T, value_to_conversion>
800 >
801 mp11::mp_if_c<
802 !mp11::mp_valid<
803 has_nonthrowing_context_conversion_to_impl,
804 typename Sup::type,
805 T>::value,
806 system::result<T> >
807 value_to_impl(
808 context_conversion_tag,
809 try_value_to_tag<T>,
810 value const& jv,
811 Ctx const& ctx )
812 {
813 return wrap_conversion_exceptions( value_to_tag<T>(), jv, Sup::get(ctx) );
814 }
815
816 template<
817 class T,
818 class Ctx,
819 class Sup = supported_context<Ctx, T, value_to_conversion>
820 >
821 mp11::mp_if_c<
822 !mp11::mp_valid<
823 has_nonthrowing_full_context_conversion_to_impl,
824 typename Sup::type,
825 T>::value,
826 system::result<T> >
827 value_to_impl(
828 full_context_conversion_tag,
829 try_value_to_tag<T>,
830 value const& jv,
831 Ctx const& ctx )
832 {
833 return wrap_conversion_exceptions(
834 value_to_tag<T>(), jv, Sup::get(ctx), ctx);
835 }
836
837 // no suitable conversion implementation
838 template< class T, class Ctx >
839 T
840 value_to_impl( no_conversion_tag, value_to_tag<T>, value const&, Ctx const& )
841 {
842 static_assert(
843 !std::is_same<T, T>::value,
844 "No suitable tag_invoke overload found for the type");
845 }
846
847 // generic wrapper over non-throwing implementations
848 template< class Impl, class T, class Ctx >
849 T
850 339 value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx )
851 {
852 339 return value_to_impl(impl, try_value_to_tag<T>(), jv, ctx).value();
853 }
854
855 template< class Ctx, class T >
856 using value_to_category = conversion_category<
857 Ctx, T, value_to_conversion >;
858
859 } // detail
860
861 #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
862 inline
863 system::result<std::nullopt_t>
864 tag_invoke(
865 try_value_to_tag<std::nullopt_t>,
866 value const& jv)
867 {
868 if( jv.is_null() )
869 return std::nullopt;
870 system::error_code ec;
871 BOOST_JSON_FAIL(ec, error::not_null);
872 return ec;
873 }
874 #endif
875
876 } // namespace json
877 } // namespace boost
878
879 #endif
880