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

Generated by: LCOV version 2.1