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

Generated by: LCOV version 2.1