detail/value_to.hpp

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