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

Generated by: LCOV version 2.1