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: 2025-12-23 17:20:51 Functions: 98.2 % 626 615

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

Generated by: LCOV version 2.1