GCC Code Coverage Report


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