Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:39:00

0001 //
0002 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
0003 // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
0004 // Copyright (c) 2021 Dmitry Arkhipov (grisumbras@gmail.com)
0005 //
0006 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0007 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0008 //
0009 // Official repository: https://github.com/boostorg/json
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 // identity conversion
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 // object
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 // array
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 // string
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 // bool
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 // integral and floating point
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 // null-like conversion
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 // string-like types
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 // map-like containers
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 // all other containers
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 // tuple-like types
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 // described classes
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 // described enums
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 // optionals
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 // variants
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 // BOOST_NO_CXX17_HDR_VARIANT
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 // BOOST_NO_CXX17_HDR_VARIANT
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 // User-provided conversions; throwing -> throwing
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 // User-provided conversions; throwing -> nonthrowing
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 // User-provided conversions; nonthrowing -> nonthrowing
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 // User-provided conversions; nonthrowing -> throwing
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 // no suitable conversion implementation
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 // generic wrapper over non-throwing implementations
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 } // detail
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 } // namespace json
0881 } // namespace boost
0882 
0883 #endif