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:38:56 Functions: 98.0 % 548 537

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

Generated by: LCOV version 2.1