File indexing completed on 2025-01-18 09:39:00
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef BOOST_JSON_DETAIL_VALUE_TO_HPP
0013 #define BOOST_JSON_DETAIL_VALUE_TO_HPP
0014
0015 #include <boost/json/value.hpp>
0016 #include <boost/json/conversion.hpp>
0017 #include <boost/describe/enum_from_string.hpp>
0018
0019 #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
0020 # include <optional>
0021 #endif
0022
0023 namespace boost {
0024 namespace json {
0025
0026 namespace detail {
0027
0028 template<class T>
0029 using has_reserve_member_helper = decltype(std::declval<T&>().reserve(0));
0030 template<class T>
0031 using has_reserve_member = mp11::mp_valid<has_reserve_member_helper, T>;
0032 template<class T>
0033 using reserve_implementation = mp11::mp_cond<
0034 is_tuple_like<T>, mp11::mp_int<2>,
0035 has_reserve_member<T>, mp11::mp_int<1>,
0036 mp11::mp_true, mp11::mp_int<0>>;
0037
0038 template<class T>
0039 error
0040 try_reserve(
0041 T&,
0042 std::size_t size,
0043 mp11::mp_int<2>)
0044 {
0045 constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
0046 if ( N != size )
0047 return error::size_mismatch;
0048 return error();
0049 }
0050
0051 template<typename T>
0052 error
0053 try_reserve(
0054 T& cont,
0055 std::size_t size,
0056 mp11::mp_int<1>)
0057 {
0058 cont.reserve(size);
0059 return error();
0060 }
0061
0062 template<typename T>
0063 error
0064 try_reserve(
0065 T&,
0066 std::size_t,
0067 mp11::mp_int<0>)
0068 {
0069 return error();
0070 }
0071
0072
0073
0074 template< class Ctx >
0075 result<value>
0076 value_to_impl(
0077 value_conversion_tag,
0078 try_value_to_tag<value>,
0079 value const& jv,
0080 Ctx const& )
0081 {
0082 return jv;
0083 }
0084
0085 template< class Ctx >
0086 value
0087 value_to_impl(
0088 value_conversion_tag, value_to_tag<value>, value const& jv, Ctx const& )
0089 {
0090 return jv;
0091 }
0092
0093
0094 template< class Ctx >
0095 result<object>
0096 value_to_impl(
0097 object_conversion_tag,
0098 try_value_to_tag<object>,
0099 value const& jv,
0100 Ctx const& )
0101 {
0102 object const* obj = jv.if_object();
0103 if( obj )
0104 return *obj;
0105 error_code ec;
0106 BOOST_JSON_FAIL(ec, error::not_object);
0107 return ec;
0108 }
0109
0110
0111 template< class Ctx >
0112 result<array>
0113 value_to_impl(
0114 array_conversion_tag,
0115 try_value_to_tag<array>,
0116 value const& jv,
0117 Ctx const& )
0118 {
0119 array const* arr = jv.if_array();
0120 if( arr )
0121 return *arr;
0122 error_code ec;
0123 BOOST_JSON_FAIL(ec, error::not_array);
0124 return ec;
0125 }
0126
0127
0128 template< class Ctx >
0129 result<string>
0130 value_to_impl(
0131 string_conversion_tag,
0132 try_value_to_tag<string>,
0133 value const& jv,
0134 Ctx const& )
0135 {
0136 string const* str = jv.if_string();
0137 if( str )
0138 return *str;
0139 error_code ec;
0140 BOOST_JSON_FAIL(ec, error::not_string);
0141 return ec;
0142 }
0143
0144
0145 template< class Ctx >
0146 result<bool>
0147 value_to_impl(
0148 bool_conversion_tag, try_value_to_tag<bool>, value const& jv, Ctx const& )
0149 {
0150 auto b = jv.if_bool();
0151 if( b )
0152 return *b;
0153 error_code ec;
0154 BOOST_JSON_FAIL(ec, error::not_bool);
0155 return {boost::system::in_place_error, ec};
0156 }
0157
0158
0159 template< class T, class Ctx >
0160 result<T>
0161 value_to_impl(
0162 number_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
0163 {
0164 error_code ec;
0165 auto const n = jv.to_number<T>(ec);
0166 if( ec.failed() )
0167 return {boost::system::in_place_error, ec};
0168 return {boost::system::in_place_value, n};
0169 }
0170
0171
0172 template< class T, class Ctx >
0173 result<T>
0174 value_to_impl(
0175 null_like_conversion_tag,
0176 try_value_to_tag<T>,
0177 value const& jv,
0178 Ctx const& )
0179 {
0180 if( jv.is_null() )
0181 return {boost::system::in_place_value, T{}};
0182 error_code ec;
0183 BOOST_JSON_FAIL(ec, error::not_null);
0184 return {boost::system::in_place_error, ec};
0185 }
0186
0187
0188 template< class T, class Ctx >
0189 result<T>
0190 value_to_impl(
0191 string_like_conversion_tag,
0192 try_value_to_tag<T>,
0193 value const& jv,
0194 Ctx const& )
0195 {
0196 auto str = jv.if_string();
0197 if( str )
0198 return {boost::system::in_place_value, T(str->subview())};
0199 error_code ec;
0200 BOOST_JSON_FAIL(ec, error::not_string);
0201 return {boost::system::in_place_error, ec};
0202 }
0203
0204
0205 template< class T, class Ctx >
0206 result<T>
0207 value_to_impl(
0208 map_like_conversion_tag,
0209 try_value_to_tag<T>,
0210 value const& jv,
0211 Ctx const& ctx )
0212 {
0213 object const* obj = jv.if_object();
0214 if( !obj )
0215 {
0216 error_code ec;
0217 BOOST_JSON_FAIL(ec, error::not_object);
0218 return {boost::system::in_place_error, ec};
0219 }
0220
0221 T res;
0222 error const e = detail::try_reserve(
0223 res, obj->size(), reserve_implementation<T>());
0224 if( e != error() )
0225 {
0226 error_code ec;
0227 BOOST_JSON_FAIL( ec, e );
0228 return {boost::system::in_place_error, ec};
0229 }
0230
0231 auto ins = detail::inserter(res, inserter_implementation<T>());
0232 for( key_value_pair const& kv: *obj )
0233 {
0234 auto elem_res = try_value_to<mapped_type<T>>( kv.value(), ctx );
0235 if( elem_res.has_error() )
0236 return {boost::system::in_place_error, elem_res.error()};
0237 *ins++ = value_type<T>{
0238 key_type<T>(kv.key()),
0239 std::move(*elem_res)};
0240 }
0241 return res;
0242 }
0243
0244
0245 template< class T, class Ctx >
0246 result<T>
0247 value_to_impl(
0248 sequence_conversion_tag,
0249 try_value_to_tag<T>,
0250 value const& jv,
0251 Ctx const& ctx )
0252 {
0253 array const* arr = jv.if_array();
0254 if( !arr )
0255 {
0256 error_code ec;
0257 BOOST_JSON_FAIL(ec, error::not_array);
0258 return {boost::system::in_place_error, ec};
0259 }
0260
0261 T result;
0262 error const e = detail::try_reserve(
0263 result, arr->size(), reserve_implementation<T>());
0264 if( e != error() )
0265 {
0266 error_code ec;
0267 BOOST_JSON_FAIL( ec, e );
0268 return {boost::system::in_place_error, ec};
0269 }
0270
0271 auto ins = detail::inserter(result, inserter_implementation<T>());
0272 for( value const& val: *arr )
0273 {
0274 auto elem_res = try_value_to<value_type<T>>( val, ctx );
0275 if( elem_res.has_error() )
0276 return {boost::system::in_place_error, elem_res.error()};
0277 *ins++ = std::move(*elem_res);
0278 }
0279 return result;
0280 }
0281
0282
0283 template< class T, class Ctx >
0284 result<T>
0285 try_make_tuple_elem(value const& jv, Ctx const& ctx, error_code& ec)
0286 {
0287 if( ec.failed() )
0288 return {boost::system::in_place_error, ec};
0289
0290 auto result = try_value_to<T>( jv, ctx );
0291 ec = result.error();
0292 return result;
0293 }
0294
0295 template <class T, class Ctx, std::size_t... Is>
0296 result<T>
0297 try_make_tuple_like(
0298 array const& arr, Ctx const& ctx, boost::mp11::index_sequence<Is...>)
0299 {
0300 error_code ec;
0301 auto items = std::make_tuple(
0302 try_make_tuple_elem<
0303 typename std::decay<tuple_element_t<Is, T>>::type >(
0304 arr[Is], ctx, ec)
0305 ...);
0306 if( ec.failed() )
0307 return {boost::system::in_place_error, ec};
0308
0309 return {
0310 boost::system::in_place_value, T(std::move(*std::get<Is>(items))...)};
0311 }
0312
0313 template< class T, class Ctx >
0314 result<T>
0315 value_to_impl(
0316 tuple_conversion_tag,
0317 try_value_to_tag<T>,
0318 value const& jv,
0319 Ctx const& ctx )
0320 {
0321 error_code ec;
0322
0323 array const* arr = jv.if_array();
0324 if( !arr )
0325 {
0326 BOOST_JSON_FAIL(ec, error::not_array);
0327 return {boost::system::in_place_error, ec};
0328 }
0329
0330 constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
0331 if( N != arr->size() )
0332 {
0333 BOOST_JSON_FAIL(ec, error::size_mismatch);
0334 return {boost::system::in_place_error, ec};
0335 }
0336
0337 return try_make_tuple_like<T>(
0338 *arr, ctx, boost::mp11::make_index_sequence<N>());
0339 }
0340
0341 template< class Ctx, class T, bool non_throwing = true >
0342 struct to_described_member
0343 {
0344 using Ds = describe::describe_members<
0345 T, describe::mod_public | describe::mod_inherited>;
0346
0347 using result_type = mp11::mp_eval_if_c< !non_throwing, T, result, T >;
0348
0349 result_type& res;
0350 object const& obj;
0351 std::size_t count;
0352 Ctx const& ctx;
0353
0354 template< class I >
0355 void
0356 operator()(I)
0357 {
0358 if( !res )
0359 return;
0360
0361 using D = mp11::mp_at<Ds, I>;
0362 using M = described_member_t<T, D>;
0363
0364 auto const found = obj.find(D::name);
0365 if( found == obj.end() )
0366 {
0367 BOOST_IF_CONSTEXPR( !is_optional_like<M>::value )
0368 {
0369 error_code ec;
0370 BOOST_JSON_FAIL(ec, error::unknown_name);
0371 res = {boost::system::in_place_error, ec};
0372 }
0373 return;
0374 }
0375
0376 #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
0377 # pragma GCC diagnostic push
0378 # pragma GCC diagnostic ignored "-Wunused"
0379 # pragma GCC diagnostic ignored "-Wunused-variable"
0380 #endif
0381 auto member_res = try_value_to<M>( found->value(), ctx );
0382 #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
0383 # pragma GCC diagnostic pop
0384 #endif
0385 if( member_res )
0386 {
0387 (*res).* D::pointer = std::move(*member_res);
0388 ++count;
0389 }
0390 else
0391 res = {boost::system::in_place_error, member_res.error()};
0392 }
0393 };
0394
0395
0396 template< class T, class Ctx >
0397 result<T>
0398 value_to_impl(
0399 described_class_conversion_tag,
0400 try_value_to_tag<T>,
0401 value const& jv,
0402 Ctx const& ctx )
0403 {
0404 result<T> res;
0405
0406 auto* obj = jv.if_object();
0407 if( !obj )
0408 {
0409 error_code ec;
0410 BOOST_JSON_FAIL(ec, error::not_object);
0411 res = {boost::system::in_place_error, ec};
0412 return res;
0413 }
0414
0415 to_described_member< Ctx, T > member_converter{ res, *obj, 0u, ctx };
0416
0417 using Ds = typename decltype(member_converter)::Ds;
0418 constexpr std::size_t N = mp11::mp_size<Ds>::value;
0419 mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
0420
0421 if( !res )
0422 return res;
0423
0424 if( member_converter.count != obj->size() )
0425 {
0426 error_code ec;
0427 BOOST_JSON_FAIL(ec, error::size_mismatch);
0428 res = {boost::system::in_place_error, ec};
0429 return res;
0430 }
0431
0432 return res;
0433 }
0434
0435
0436 template< class T, class Ctx >
0437 result<T>
0438 value_to_impl(
0439 described_enum_conversion_tag,
0440 try_value_to_tag<T>,
0441 value const& jv,
0442 Ctx const& )
0443 {
0444 T val = {};
0445 (void)jv;
0446 #ifdef BOOST_DESCRIBE_CXX14
0447 error_code ec;
0448
0449 auto str = jv.if_string();
0450 if( !str )
0451 {
0452 BOOST_JSON_FAIL(ec, error::not_string);
0453 return {system::in_place_error, ec};
0454 }
0455
0456 if( !describe::enum_from_string(str->data(), val) )
0457 {
0458 BOOST_JSON_FAIL(ec, error::unknown_name);
0459 return {system::in_place_error, ec};
0460 }
0461 #endif
0462
0463 return {system::in_place_value, val};
0464 }
0465
0466
0467 template< class T, class Ctx >
0468 result<T>
0469 value_to_impl(
0470 optional_conversion_tag,
0471 try_value_to_tag<T>,
0472 value const& jv,
0473 Ctx const& ctx)
0474 {
0475 using Inner = value_result_type<T>;
0476 if( jv.is_null() )
0477 return {};
0478 else
0479 return try_value_to<Inner>(jv, ctx);
0480 }
0481
0482
0483 template< class T, class V, class I >
0484 using variant_construction_category = mp11::mp_cond<
0485 std::is_constructible< T, variant2::in_place_index_t<I::value>, V >,
0486 mp11::mp_int<2>,
0487 #ifndef BOOST_NO_CXX17_HDR_VARIANT
0488 std::is_constructible< T, std::in_place_index_t<I::value>, V >,
0489 mp11::mp_int<1>,
0490 #endif
0491 mp11::mp_true,
0492 mp11::mp_int<0> >;
0493
0494 template< class T, class I, class V >
0495 T
0496 initialize_variant( V&& v, mp11::mp_int<0> )
0497 {
0498 T t;
0499 t.template emplace<I::value>( std::move(v) );
0500 return t;
0501 }
0502
0503 template< class T, class I, class V >
0504 T
0505 initialize_variant( V&& v, mp11::mp_int<2> )
0506 {
0507 return T( variant2::in_place_index_t<I::value>(), std::move(v) );
0508 }
0509
0510 #ifndef BOOST_NO_CXX17_HDR_VARIANT
0511 template< class T, class I, class V >
0512 T
0513 initialize_variant( V&& v, mp11::mp_int<1> )
0514 {
0515 return T( std::in_place_index_t<I::value>(), std::move(v) );
0516 }
0517 #endif
0518
0519 template< class T, class Ctx >
0520 struct alternative_converter
0521 {
0522 result<T>& res;
0523 value const& jv;
0524 Ctx const& ctx;
0525
0526 template< class I >
0527 void operator()( I ) const
0528 {
0529 if( res )
0530 return;
0531
0532 using V = mp11::mp_at<T, I>;
0533 auto attempt = try_value_to<V>(jv, ctx);
0534 if( attempt )
0535 {
0536 using cat = variant_construction_category<T, V, I>;
0537 res = initialize_variant<T, I>( std::move(*attempt), cat() );
0538 }
0539 }
0540 };
0541
0542 template< class T, class Ctx >
0543 result<T>
0544 value_to_impl(
0545 variant_conversion_tag,
0546 try_value_to_tag<T>,
0547 value const& jv,
0548 Ctx const& ctx)
0549 {
0550 error_code ec;
0551 BOOST_JSON_FAIL(ec, error::exhausted_variants);
0552
0553 using Is = mp11::mp_iota< mp11::mp_size<T> >;
0554
0555 result<T> res = {system::in_place_error, ec};
0556 mp11::mp_for_each<Is>( alternative_converter<T, Ctx>{res, jv, ctx} );
0557 return res;
0558 }
0559
0560
0561
0562 template< class T, class Ctx >
0563 mp11::mp_if< mp11::mp_valid<has_user_conversion_to_impl, T>, T >
0564 value_to_impl(
0565 user_conversion_tag, value_to_tag<T> tag, value const& jv, Ctx const&)
0566 {
0567 return tag_invoke(tag, jv);
0568 }
0569
0570 template<
0571 class T,
0572 class Ctx,
0573 class Sup = supported_context<Ctx, T, value_to_conversion>
0574 >
0575 mp11::mp_if<
0576 mp11::mp_valid< has_context_conversion_to_impl, typename Sup::type, T>, T >
0577 value_to_impl(
0578 context_conversion_tag,
0579 value_to_tag<T> tag,
0580 value const& jv,
0581 Ctx const& ctx )
0582 {
0583 return tag_invoke( tag, jv, Sup::get(ctx) );
0584 }
0585
0586 template<
0587 class T,
0588 class Ctx,
0589 class Sup = supported_context<Ctx, T, value_to_conversion>
0590 >
0591 mp11::mp_if<
0592 mp11::mp_valid<
0593 has_full_context_conversion_to_impl, typename Sup::type, T>,
0594 T>
0595 value_to_impl(
0596 full_context_conversion_tag,
0597 value_to_tag<T> tag,
0598 value const& jv,
0599 Ctx const& ctx )
0600 {
0601 return tag_invoke( tag, jv, Sup::get(ctx), ctx );
0602 }
0603
0604
0605
0606 template< class T, class Ctx >
0607 mp11::mp_if_c< !mp11::mp_valid<has_user_conversion_to_impl, T>::value, T>
0608 value_to_impl(
0609 user_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& )
0610 {
0611 auto res = tag_invoke(try_value_to_tag<T>(), jv);
0612 if( res.has_error() )
0613 throw_system_error( res.error() );
0614 return std::move(*res);
0615 }
0616
0617 template<
0618 class T,
0619 class Ctx,
0620 class Sup = supported_context<Ctx, T, value_to_conversion>
0621 >
0622 mp11::mp_if_c<
0623 !mp11::mp_valid<
0624 has_context_conversion_to_impl, typename Sup::type, T>::value,
0625 T>
0626 value_to_impl(
0627 context_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& ctx )
0628 {
0629 auto res = tag_invoke( try_value_to_tag<T>(), jv, Sup::get(ctx) );
0630 if( res.has_error() )
0631 throw_system_error( res.error() );
0632 return std::move(*res);
0633 }
0634
0635 template< class Ctx >
0636 std::tuple<allow_exceptions, Ctx>
0637 make_throwing_context(Ctx const& ctx)
0638 {
0639 return std::tuple<allow_exceptions, Ctx>(allow_exceptions(), ctx);
0640 }
0641
0642 template< class... Ctxes >
0643 std::tuple<allow_exceptions, Ctxes...>
0644 make_throwing_context(std::tuple<Ctxes...> const& ctx)
0645 {
0646 return std::tuple_cat(std::make_tuple( allow_exceptions() ), ctx);
0647 }
0648
0649 template< class... Ctxes >
0650 std::tuple<allow_exceptions, Ctxes...> const&
0651 make_throwing_context(std::tuple<allow_exceptions, Ctxes...> const& ctx)
0652 noexcept
0653 {
0654 return ctx;
0655 }
0656
0657 template<
0658 class T,
0659 class Ctx,
0660 class Sup = supported_context<Ctx, T, value_to_conversion>
0661 >
0662 mp11::mp_if_c<
0663 !mp11::mp_valid<
0664 has_full_context_conversion_to_impl, typename Sup::type, T>::value,
0665 T>
0666 value_to_impl(
0667 full_context_conversion_tag,
0668 value_to_tag<T>,
0669 value const& jv,
0670 Ctx const& ctx )
0671 {
0672 auto res = tag_invoke(
0673 try_value_to_tag<T>(),
0674 jv,
0675 Sup::get(ctx),
0676 make_throwing_context(ctx));
0677 if( res.has_error() )
0678 throw_system_error( res.error() );
0679 return std::move(*res);
0680 }
0681
0682
0683
0684 template< class T, class Ctx >
0685 mp11::mp_if<
0686 mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>, result<T> >
0687 value_to_impl(
0688 user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
0689 {
0690 return tag_invoke(try_value_to_tag<T>(), jv);
0691 }
0692
0693 template<
0694 class T,
0695 class Ctx,
0696 class Sup = supported_context<Ctx, T, value_to_conversion>
0697 >
0698 mp11::mp_if<
0699 mp11::mp_valid<
0700 has_nonthrowing_context_conversion_to_impl, typename Sup::type, T>,
0701 result<T> >
0702 value_to_impl(
0703 context_conversion_tag,
0704 try_value_to_tag<T> tag,
0705 value const& jv,
0706 Ctx const& ctx )
0707 {
0708 return tag_invoke( tag, jv, Sup::get(ctx) );
0709 }
0710
0711 template<
0712 class T,
0713 class Ctx,
0714 class Sup = supported_context<Ctx, T, value_to_conversion>
0715 >
0716 mp11::mp_if<
0717 mp11::mp_valid<
0718 has_nonthrowing_full_context_conversion_to_impl,
0719 typename Sup::type,
0720 T>,
0721 result<T> >
0722 value_to_impl(
0723 full_context_conversion_tag,
0724 try_value_to_tag<T> tag,
0725 value const& jv,
0726 Ctx const& ctx )
0727 {
0728 return tag_invoke( tag, jv, Sup::get(ctx), ctx );
0729 }
0730
0731
0732
0733
0734 template< class Ctx >
0735 struct does_allow_exceptions : std::false_type
0736 { };
0737
0738 template< class... Ctxes >
0739 struct does_allow_exceptions< std::tuple<allow_exceptions, Ctxes...> >
0740 : std::true_type
0741 { };
0742
0743 template< class T, class... Args >
0744 result<T>
0745 wrap_conversion_exceptions( std::true_type, value_to_tag<T>, Args&& ... args )
0746 {
0747 return {
0748 boost::system::in_place_value,
0749 tag_invoke( value_to_tag<T>(), static_cast<Args&&>(args)... )};
0750 }
0751
0752 template< class T, class... Args >
0753 result<T>
0754 wrap_conversion_exceptions( std::false_type, value_to_tag<T>, Args&& ... args )
0755 {
0756 #ifndef BOOST_NO_EXCEPTIONS
0757 try
0758 {
0759 #endif
0760 return wrap_conversion_exceptions(
0761 std::true_type(),
0762 value_to_tag<T>(),
0763 static_cast<Args&&>(args)... );
0764 #ifndef BOOST_NO_EXCEPTIONS
0765 }
0766 catch( std::bad_alloc const&)
0767 {
0768 throw;
0769 }
0770 catch( system_error const& e)
0771 {
0772 return {boost::system::in_place_error, e.code()};
0773 }
0774 catch( ... )
0775 {
0776 error_code ec;
0777 BOOST_JSON_FAIL(ec, error::exception);
0778 return {boost::system::in_place_error, ec};
0779 }
0780 #endif
0781 }
0782
0783 template< class T, class Ctx >
0784 mp11::mp_if_c<
0785 !mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>::value,
0786 result<T> >
0787 value_to_impl(
0788 user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
0789 {
0790 return wrap_conversion_exceptions(
0791 does_allow_exceptions<Ctx>(), value_to_tag<T>(), jv);
0792 }
0793
0794 template<
0795 class T,
0796 class Ctx,
0797 class Sup = supported_context<Ctx, T, value_to_conversion>
0798 >
0799 mp11::mp_if_c<
0800 !mp11::mp_valid<
0801 has_nonthrowing_context_conversion_to_impl,
0802 typename Sup::type,
0803 T>::value,
0804 result<T> >
0805 value_to_impl(
0806 context_conversion_tag,
0807 try_value_to_tag<T>,
0808 value const& jv,
0809 Ctx const& ctx )
0810 {
0811 return wrap_conversion_exceptions(
0812 does_allow_exceptions<Ctx>(), value_to_tag<T>(), jv, Sup::get(ctx) );
0813 }
0814
0815 template<
0816 class T,
0817 class Ctx,
0818 class Sup = supported_context<Ctx, T, value_to_conversion>
0819 >
0820 mp11::mp_if_c<
0821 !mp11::mp_valid<
0822 has_nonthrowing_full_context_conversion_to_impl,
0823 typename Sup::type,
0824 T>::value,
0825 result<T> >
0826 value_to_impl(
0827 full_context_conversion_tag,
0828 try_value_to_tag<T>,
0829 value const& jv,
0830 Ctx const& ctx )
0831 {
0832 return wrap_conversion_exceptions(
0833 does_allow_exceptions<Ctx>(),
0834 value_to_tag<T>(),
0835 jv,
0836 Sup::get(ctx),
0837 ctx);
0838 }
0839
0840
0841 template< class T, class Ctx >
0842 T
0843 value_to_impl( no_conversion_tag, value_to_tag<T>, value const&, Ctx const& )
0844 {
0845 static_assert(
0846 !std::is_same<T, T>::value,
0847 "No suitable tag_invoke overload found for the type");
0848 }
0849
0850
0851 template< class Impl, class T, class Ctx >
0852 T
0853 value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx )
0854 {
0855 return value_to_impl(
0856 impl, try_value_to_tag<T>(), jv, make_throwing_context(ctx) ).value();
0857 }
0858
0859 template< class Ctx, class T >
0860 using value_to_category = conversion_category<
0861 Ctx, T, value_to_conversion >;
0862
0863 }
0864
0865 #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
0866 inline
0867 result<std::nullopt_t>
0868 tag_invoke(
0869 try_value_to_tag<std::nullopt_t>,
0870 value const& jv)
0871 {
0872 if( jv.is_null() )
0873 return std::nullopt;
0874 error_code ec;
0875 BOOST_JSON_FAIL(ec, error::not_null);
0876 return ec;
0877 }
0878 #endif
0879
0880 }
0881 }
0882
0883 #endif