GCC Code Coverage Report


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