LCOV - code coverage report
Current view: top level - json/detail - value_to.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 157 157
Test Date: 2026-01-05 13:48:39 Functions: 98.0 % 548 537

            Line data    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          230 : try_make_tuple_elem(value const& jv, Ctx const& ctx, system::error_code& ec)
     288              : {
     289          230 :     if( ec.failed() )
     290           38 :         return {boost::system::in_place_error, ec};
     291              : 
     292          192 :     auto result = try_value_to<T>( jv, ctx );
     293          192 :     ec = result.error();
     294          192 :     return result;
     295           57 : }
     296              : 
     297              : template <class T, class Ctx, std::size_t... Is>
     298              : system::result<T>
     299           91 : try_make_tuple_like(
     300              :     array const& arr, Ctx const& ctx, boost::mp11::index_sequence<Is...>)
     301              : {
     302           91 :     system::error_code ec;
     303          109 :     auto items = std::make_tuple(
     304              :         try_make_tuple_elem<
     305          111 :             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           91 :     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              :     return {
     319           78 :         boost::system::in_place_value, T(std::move(*std::get<Is>(items))...)};
     320           54 : }
     321              : 
     322              : template< class T, class Ctx >
     323              : system::result<T>
     324          115 : value_to_impl(
     325              :     tuple_conversion_tag,
     326              :     try_value_to_tag<T>,
     327              :     value const& jv,
     328              :     Ctx const& ctx )
     329              : {
     330          115 :     system::error_code ec;
     331              : 
     332          115 :     array const* arr = jv.if_array();
     333          115 :     if( !arr )
     334              :     {
     335           12 :         BOOST_JSON_FAIL(ec, error::not_array);
     336           12 :         return {boost::system::in_place_error, ec};
     337              :     }
     338              : 
     339          103 :     constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
     340          103 :     if( N != arr->size() )
     341              :     {
     342           12 :         BOOST_JSON_FAIL(ec, error::size_mismatch);
     343           12 :         return {boost::system::in_place_error, ec};
     344              :     }
     345              : 
     346           31 :     return try_make_tuple_like<T>(
     347           91 :         *arr, ctx, boost::mp11::make_index_sequence<N>());
     348              : }
     349              : 
     350              : template< class Ctx, class T >
     351              : struct to_described_member
     352              : {
     353              :     static_assert(
     354              :         uniquely_named_members<T>::value,
     355              :         "The type has several described members with the same name.");
     356              : 
     357              :     using Ds = described_members<T>;
     358              : 
     359              :     system::result<T>& res;
     360              :     object const& obj;
     361              :     Ctx const& ctx;
     362              : 
     363              :     template< class I >
     364              :     void
     365              :     operator()(I)
     366              :     {
     367              :         if( !res )
     368              :             return;
     369              : 
     370              :         using D = mp11::mp_at<Ds, I>;
     371              :         using M = described_member_t<T, D>;
     372              : 
     373              :         auto const found = obj.find(D::name);
     374              :         if( found == obj.end() )
     375              :         {
     376              :             BOOST_IF_CONSTEXPR( !is_optional_like<M>::value )
     377              :             {
     378              :                 system::error_code ec;
     379              :                 BOOST_JSON_FAIL(ec, error::size_mismatch);
     380              :                 res = {boost::system::in_place_error, ec};
     381              :             }
     382              :             return;
     383              :         }
     384              : 
     385              : #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
     386              : # pragma GCC diagnostic push
     387              : # pragma GCC diagnostic ignored "-Wunused"
     388              : # pragma GCC diagnostic ignored "-Wunused-variable"
     389              : #endif
     390              :         auto member_res = try_value_to<M>( found->value(), ctx );
     391              : #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
     392              : # pragma GCC diagnostic pop
     393              : #endif
     394              :         if( member_res )
     395              :             (*res).* D::pointer = std::move(*member_res);
     396              :         else
     397              :             res = {boost::system::in_place_error, member_res.error()};
     398              :     }
     399              : };
     400              : 
     401              : // described classes
     402              : template< class T, class Ctx >
     403              : system::result<T>
     404              : value_to_impl(
     405              :     described_class_conversion_tag,
     406              :     try_value_to_tag<T>,
     407              :     value const& jv,
     408              :     Ctx const& ctx )
     409              : {
     410              :     BOOST_CORE_STATIC_ASSERT( std::is_default_constructible<T>::value );
     411              :     system::result<T> res;
     412              : 
     413              :     auto* obj = jv.if_object();
     414              :     if( !obj )
     415              :     {
     416              :         system::error_code ec;
     417              :         BOOST_JSON_FAIL(ec, error::not_object);
     418              :         res = {boost::system::in_place_error, ec};
     419              :         return res;
     420              :     }
     421              : 
     422              :     to_described_member<Ctx, T> member_converter{res, *obj, ctx};
     423              : 
     424              :     using Ds = typename decltype(member_converter)::Ds;
     425              :     constexpr std::size_t N = mp11::mp_size<Ds>::value;
     426              :     mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
     427              : 
     428              :     if( !res )
     429              :         return res;
     430              : 
     431              :     return res;
     432              : }
     433              : 
     434              : // described enums
     435              : template< class T, class Ctx >
     436              : system::result<T>
     437              : value_to_impl(
     438              :     described_enum_conversion_tag,
     439              :     try_value_to_tag<T>,
     440              :     value const& jv,
     441              :     Ctx const& )
     442              : {
     443              :     T val = {};
     444              :     (void)jv;
     445              : #ifdef BOOST_DESCRIBE_CXX14
     446              :     system::error_code ec;
     447              : 
     448              :     auto str = jv.if_string();
     449              :     if( !str )
     450              :     {
     451              :         BOOST_JSON_FAIL(ec, error::not_string);
     452              :         return {system::in_place_error, ec};
     453              :     }
     454              : 
     455              :     if( !describe::enum_from_string(str->data(), val) )
     456              :     {
     457              :         BOOST_JSON_FAIL(ec, error::unknown_name);
     458              :         return {system::in_place_error, ec};
     459              :     }
     460              : #endif
     461              : 
     462              :     return {system::in_place_value, val};
     463              : }
     464              : 
     465              : // optionals
     466              : template< class T, class Ctx >
     467              : system::result<T>
     468              : value_to_impl(
     469              :     optional_conversion_tag,
     470              :     try_value_to_tag<T>,
     471              :     value const& jv,
     472              :     Ctx const& ctx)
     473              : {
     474              :     using Inner = value_result_type<T>;
     475              :     if( jv.is_null() )
     476              :         return {};
     477              :     else
     478              :         return try_value_to<Inner>(jv, ctx);
     479              : }
     480              : 
     481              : // variants
     482              : template< class T, class V, class I >
     483              : using variant_construction_category = mp11::mp_cond<
     484              :     std::is_constructible< T, variant2::in_place_index_t<I::value>, V >,
     485              :         mp11::mp_int<2>,
     486              : #ifndef BOOST_NO_CXX17_HDR_VARIANT
     487              :     std::is_constructible< T, std::in_place_index_t<I::value>, V >,
     488              :         mp11::mp_int<1>,
     489              : #endif // BOOST_NO_CXX17_HDR_VARIANT
     490              :     mp11::mp_true,
     491              :         mp11::mp_int<0> >;
     492              : 
     493              : template< class T, class I, class V >
     494              : T
     495              : initialize_variant( V&& v, mp11::mp_int<0> )
     496              : {
     497              :     T t;
     498              :     t.template emplace<I::value>( std::move(v) );
     499              :     return t;
     500              : }
     501              : 
     502              : template< class T, class I, class V >
     503              : T
     504              : initialize_variant( V&& v, mp11::mp_int<2> )
     505              : {
     506              :     return T( variant2::in_place_index_t<I::value>(), std::move(v) );
     507              : }
     508              : 
     509              : #ifndef BOOST_NO_CXX17_HDR_VARIANT
     510              : template< class T, class I, class V >
     511              : T
     512              : initialize_variant( V&& v, mp11::mp_int<1> )
     513              : {
     514              :     return T( std::in_place_index_t<I::value>(), std::move(v) );
     515              : }
     516              : #endif // BOOST_NO_CXX17_HDR_VARIANT
     517              : 
     518              : 
     519              : template< class T, class Ctx >
     520              : struct alternative_converter
     521              : {
     522              :     system::result<T>& res;
     523              :     value const& jv;
     524              :     Ctx const& ctx;
     525              : 
     526              :     template< class I >
     527              :     void operator()( I ) const
     528              :     {
     529              :         if( res )
     530              :             return;
     531              : 
     532              :         using V = mp11::mp_at<T, I>;
     533              :         auto attempt = try_value_to<V>(jv, ctx);
     534              :         if( attempt )
     535              :         {
     536              :             using cat = variant_construction_category<T, V, I>;
     537              :             res = initialize_variant<T, I>( std::move(*attempt), cat() );
     538              :         }
     539              :     }
     540              : };
     541              : 
     542              : template< class T, class Ctx >
     543              : system::result<T>
     544              : value_to_impl(
     545              :     variant_conversion_tag,
     546              :     try_value_to_tag<T>,
     547              :     value const& jv,
     548              :     Ctx const& ctx)
     549              : {
     550              :     system::error_code ec;
     551              :     BOOST_JSON_FAIL(ec, error::exhausted_variants);
     552              : 
     553              :     using Is = mp11::mp_iota< mp11::mp_size<T> >;
     554              : 
     555              :     system::result<T> res = {system::in_place_error, ec};
     556              :     mp11::mp_for_each<Is>( alternative_converter<T, Ctx>{res, jv, ctx} );
     557              :     return res;
     558              : }
     559              : 
     560              : template< class T, class Ctx >
     561              : system::result<T>
     562              : value_to_impl(
     563              :     path_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
     564              : {
     565              :     auto str = jv.if_string();
     566              :     if( !str )
     567              :     {
     568              :         system::error_code ec;
     569              :         BOOST_JSON_FAIL(ec, error::not_string);
     570              :         return {boost::system::in_place_error, ec};
     571              :     }
     572              : 
     573              :     string_view sv = str->subview();
     574              :     return {boost::system::in_place_value, T( sv.begin(), sv.end() )};
     575              : }
     576              : 
     577              : //----------------------------------------------------------
     578              : // User-provided conversions; throwing -> throwing
     579              : template< class T, class Ctx >
     580              : mp11::mp_if< mp11::mp_valid<has_user_conversion_to_impl, T>, T >
     581            1 : value_to_impl(
     582              :     user_conversion_tag, value_to_tag<T> tag, value const& jv, Ctx const&)
     583              : {
     584            1 :     return tag_invoke(tag, jv);
     585              : }
     586              : 
     587              : template<
     588              :     class T,
     589              :     class Ctx,
     590              :     class Sup = supported_context<Ctx, T, value_to_conversion>
     591              : >
     592              : mp11::mp_if<
     593              :     mp11::mp_valid< has_context_conversion_to_impl, typename Sup::type, T>, T >
     594            1 : value_to_impl(
     595              :     context_conversion_tag,
     596              :     value_to_tag<T> tag,
     597              :     value const& jv,
     598              :     Ctx const& ctx )
     599              : {
     600            1 :     return tag_invoke( tag, jv, Sup::get(ctx) );
     601              : }
     602              : 
     603              : template<
     604              :     class T,
     605              :     class Ctx,
     606              :     class Sup = supported_context<Ctx, T, value_to_conversion>
     607              : >
     608              : mp11::mp_if<
     609              :     mp11::mp_valid<
     610              :         has_full_context_conversion_to_impl, typename Sup::type, T>,
     611              :     T>
     612              : value_to_impl(
     613              :     full_context_conversion_tag,
     614              :     value_to_tag<T> tag,
     615              :     value const& jv,
     616              :     Ctx const& ctx )
     617              : {
     618              :     return tag_invoke( tag, jv, Sup::get(ctx), ctx );
     619              : }
     620              : 
     621              : //----------------------------------------------------------
     622              : // User-provided conversions; throwing -> nonthrowing
     623              : template< class T, class Ctx >
     624              : mp11::mp_if_c< !mp11::mp_valid<has_user_conversion_to_impl, T>::value, T>
     625           60 : value_to_impl(
     626              :     user_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& )
     627              : {
     628           60 :     auto res = tag_invoke(try_value_to_tag<T>(), jv);
     629           60 :     if( res.has_error() )
     630           12 :         throw_system_error( res.error() );
     631           96 :     return std::move(*res);
     632           32 : }
     633              : 
     634              : template<
     635              :     class T,
     636              :     class Ctx,
     637              :     class Sup = supported_context<Ctx, T, value_to_conversion>
     638              : >
     639              : mp11::mp_if_c<
     640              :     !mp11::mp_valid<
     641              :         has_context_conversion_to_impl, typename Sup::type, T>::value,
     642              :     T>
     643            3 : value_to_impl(
     644              :     context_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& ctx )
     645              : {
     646            3 :     auto res = tag_invoke( try_value_to_tag<T>(), jv, Sup::get(ctx) );
     647            3 :     if( res.has_error() )
     648            1 :         throw_system_error( res.error() );
     649            4 :     return std::move(*res);
     650              : }
     651              : 
     652              : template<
     653              :     class T,
     654              :     class Ctx,
     655              :     class Sup = supported_context<Ctx, T, value_to_conversion>
     656              : >
     657              : mp11::mp_if_c<
     658              :     !mp11::mp_valid<
     659              :         has_full_context_conversion_to_impl, typename Sup::type, T>::value,
     660              :     T>
     661              : value_to_impl(
     662              :     full_context_conversion_tag,
     663              :     value_to_tag<T>,
     664              :     value const& jv,
     665              :     Ctx const& ctx )
     666              : {
     667              :     auto res = tag_invoke(try_value_to_tag<T>(), jv, Sup::get(ctx), ctx);
     668              :     if( res.has_error() )
     669              :         throw_system_error( res.error() );
     670              :     return std::move(*res);
     671              : }
     672              : 
     673              : //----------------------------------------------------------
     674              : // User-provided conversions; nonthrowing -> nonthrowing
     675              : template< class T, class Ctx >
     676              : mp11::mp_if<
     677              :     mp11::mp_valid<
     678              :         has_nonthrowing_user_conversion_to_impl, T>, system::result<T> >
     679          124 : value_to_impl(
     680              :     user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
     681              : {
     682          132 :     return tag_invoke(try_value_to_tag<T>(), jv);
     683              : }
     684              : 
     685              : template<
     686              :     class T,
     687              :     class Ctx,
     688              :     class Sup = supported_context<Ctx, T, value_to_conversion>
     689              : >
     690              : mp11::mp_if<
     691              :     mp11::mp_valid<
     692              :         has_nonthrowing_context_conversion_to_impl, typename Sup::type, T>,
     693              :     system::result<T> >
     694              : value_to_impl(
     695              :     context_conversion_tag,
     696              :     try_value_to_tag<T> tag,
     697              :     value const& jv,
     698              :     Ctx const& ctx )
     699              : {
     700              :     return tag_invoke( tag, jv, Sup::get(ctx) );
     701              : }
     702              : 
     703              : template<
     704              :     class T,
     705              :     class Ctx,
     706              :     class Sup = supported_context<Ctx, T, value_to_conversion>
     707              : >
     708              : mp11::mp_if<
     709              :     mp11::mp_valid<
     710              :         has_nonthrowing_full_context_conversion_to_impl,
     711              :         typename Sup::type,
     712              :         T>,
     713              :     system::result<T> >
     714              : value_to_impl(
     715              :     full_context_conversion_tag,
     716              :     try_value_to_tag<T> tag,
     717              :     value const& jv,
     718              :     Ctx const& ctx )
     719              : {
     720              :     return tag_invoke( tag, jv, Sup::get(ctx), ctx );
     721              : }
     722              : 
     723              : //----------------------------------------------------------
     724              : // User-provided conversions; nonthrowing -> throwing
     725              : 
     726              : template< class T, class... Args >
     727              : system::result<T>
     728           36 : wrap_conversion_exceptions( value_to_tag<T>, Args&& ... args )
     729              : {
     730              : #ifndef BOOST_NO_EXCEPTIONS
     731              :     try
     732              :     {
     733              : #endif
     734              :         return {
     735              :             boost::system::in_place_value,
     736           36 :             tag_invoke( value_to_tag<T>(), static_cast<Args&&>(args)... )};
     737              : #ifndef BOOST_NO_EXCEPTIONS
     738              :     }
     739           30 :     catch( std::bad_alloc const&)
     740              :     {
     741            6 :         throw;
     742              :     }
     743           12 :     catch( system::system_error const& e)
     744              :     {
     745           12 :         return {boost::system::in_place_error, e.code()};
     746              :     }
     747           12 :     catch( ... )
     748              :     {
     749            6 :         system::error_code ec;
     750            6 :         BOOST_JSON_FAIL(ec, error::exception);
     751            6 :         return {boost::system::in_place_error, ec};
     752              :     }
     753              : #endif
     754              : }
     755              : 
     756              : template< class T, class Ctx >
     757              : mp11::mp_if_c<
     758              :     !mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>::value,
     759              :     system::result<T> >
     760           36 : value_to_impl(
     761              :     user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
     762              : {
     763           36 :     return wrap_conversion_exceptions(value_to_tag<T>(), jv);
     764              : }
     765              : 
     766              : template<
     767              :     class T,
     768              :     class Ctx,
     769              :     class Sup = supported_context<Ctx, T, value_to_conversion>
     770              : >
     771              : mp11::mp_if_c<
     772              :     !mp11::mp_valid<
     773              :         has_nonthrowing_context_conversion_to_impl,
     774              :         typename Sup::type,
     775              :         T>::value,
     776              :     system::result<T> >
     777              : value_to_impl(
     778              :     context_conversion_tag,
     779              :     try_value_to_tag<T>,
     780              :     value const& jv,
     781              :     Ctx const& ctx )
     782              : {
     783              :     return wrap_conversion_exceptions( value_to_tag<T>(), jv, Sup::get(ctx) );
     784              : }
     785              : 
     786              : template<
     787              :     class T,
     788              :     class Ctx,
     789              :     class Sup = supported_context<Ctx, T, value_to_conversion>
     790              : >
     791              : mp11::mp_if_c<
     792              :     !mp11::mp_valid<
     793              :         has_nonthrowing_full_context_conversion_to_impl,
     794              :         typename Sup::type,
     795              :         T>::value,
     796              :     system::result<T> >
     797              : value_to_impl(
     798              :     full_context_conversion_tag,
     799              :     try_value_to_tag<T>,
     800              :     value const& jv,
     801              :     Ctx const& ctx )
     802              : {
     803              :     return wrap_conversion_exceptions(
     804              :         value_to_tag<T>(), jv, Sup::get(ctx), ctx);
     805              : }
     806              : 
     807              : // no suitable conversion implementation
     808              : template< class T, class Ctx >
     809              : T
     810              : value_to_impl( no_conversion_tag, value_to_tag<T>, value const&, Ctx const& )
     811              : {
     812              :     static_assert(
     813              :         !std::is_same<T, T>::value,
     814              :         "No suitable tag_invoke overload found for the type");
     815              : }
     816              : 
     817              : // generic wrapper over non-throwing implementations
     818              : template< class Impl, class T, class Ctx >
     819              : T
     820          339 : value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx )
     821              : {
     822          339 :     return value_to_impl(impl, try_value_to_tag<T>(), jv, ctx).value();
     823              : }
     824              : 
     825              : template< class Ctx, class T >
     826              : using value_to_category = conversion_category<
     827              :     Ctx, T, value_to_conversion >;
     828              : 
     829              : } // detail
     830              : 
     831              : #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
     832              : inline
     833              : system::result<std::nullopt_t>
     834              : tag_invoke(
     835              :     try_value_to_tag<std::nullopt_t>,
     836              :     value const& jv)
     837              : {
     838              :     if( jv.is_null() )
     839              :         return std::nullopt;
     840              :     system::error_code ec;
     841              :     BOOST_JSON_FAIL(ec, error::not_null);
     842              :     return ec;
     843              : }
     844              : #endif
     845              : 
     846              : } // namespace json
     847              : } // namespace boost
     848              : 
     849              : #endif
        

Generated by: LCOV version 2.1