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 % 166 166
Test Date: 2025-12-23 17:21:58 Functions: 97.9 % 477 467

            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           37 : try_reserve(
      42              :     T&,
      43              :     std::size_t size,
      44              :     mp11::mp_int<2>)
      45              : {
      46           37 :     constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
      47           37 :     if ( N != size )
      48           30 :         return error::size_mismatch;
      49            7 :     return error();
      50              : }
      51              : 
      52              : template<typename T>
      53              : error
      54           38 : try_reserve(
      55              :     T& cont,
      56              :     std::size_t size,
      57              :     mp11::mp_int<1>)
      58              : {
      59           38 :     cont.reserve(size);
      60           38 :     return error();
      61              : }
      62              : 
      63              : template<typename T>
      64              : error
      65           37 : try_reserve(
      66              :     T&,
      67              :     std::size_t,
      68              :     mp11::mp_int<0>)
      69              : {
      70           37 :     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           42 : value_to_impl(
     149              :     bool_conversion_tag, try_value_to_tag<bool>, value const& jv, Ctx const& )
     150              : {
     151           42 :     auto b = jv.if_bool();
     152           42 :     if( b )
     153           36 :         return *b;
     154            6 :     system::error_code ec;
     155            6 :     BOOST_JSON_FAIL(ec, error::not_bool);
     156            6 :     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         3280 : value_to_impl(
     163              :     number_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
     164              : {
     165         3280 :     system::error_code ec;
     166         3280 :     auto const n = jv.to_number<T>(ec);
     167         3280 :     if( ec.failed() )
     168           48 :         return {boost::system::in_place_error, ec};
     169         3232 :     return {boost::system::in_place_value, n};
     170              : }
     171              : 
     172              : // null-like conversion
     173              : template< class T, class Ctx >
     174              : system::result<T>
     175           48 : value_to_impl(
     176              :     null_like_conversion_tag,
     177              :     try_value_to_tag<T>,
     178              :     value const& jv,
     179              :     Ctx const& )
     180              : {
     181           48 :     if( jv.is_null() )
     182           30 :         return {boost::system::in_place_value, T{}};
     183           18 :     system::error_code ec;
     184           18 :     BOOST_JSON_FAIL(ec, error::not_null);
     185           18 :     return {boost::system::in_place_error, ec};
     186              : }
     187              : 
     188              : // string-like types
     189              : template< class T, class Ctx >
     190              : system::result<T>
     191           66 : value_to_impl(
     192              :     string_like_conversion_tag,
     193              :     try_value_to_tag<T>,
     194              :     value const& jv,
     195              :     Ctx const& )
     196              : {
     197           66 :     auto str = jv.if_string();
     198           66 :     if( str )
     199           54 :         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           54 : value_to_impl(
     209              :     map_like_conversion_tag,
     210              :     try_value_to_tag<T>,
     211              :     value const& jv,
     212              :     Ctx const& ctx )
     213              : {
     214           54 :     object const* obj = jv.if_object();
     215           54 :     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           42 :     T res;
     223           42 :     error const e = detail::try_reserve(
     224              :         res, obj->size(), reserve_implementation<T>());
     225           42 :     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           30 :     auto ins = detail::inserter(res, inserter_implementation<T>());
     233          102 :     for( key_value_pair const& kv: *obj )
     234              :     {
     235           84 :         auto elem_res = try_value_to<mapped_type<T>>( kv.value(), ctx );
     236           84 :         if( elem_res.has_error() )
     237           12 :             return {boost::system::in_place_error, elem_res.error()};
     238           72 :         *ins++ = value_type<T>{
     239          144 :             key_type<T>(kv.key()),
     240           72 :             std::move(*elem_res)};
     241              :     }
     242           18 :     return res;
     243           42 : }
     244              : 
     245              : // all other containers
     246              : template< class T, class Ctx >
     247              : system::result<T>
     248           79 : value_to_impl(
     249              :     sequence_conversion_tag,
     250              :     try_value_to_tag<T>,
     251              :     value const& jv,
     252              :     Ctx const& ctx )
     253              : {
     254           79 :     array const* arr = jv.if_array();
     255           79 :     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           43 :     T result;
     263           67 :     error const e = detail::try_reserve(
     264              :         result, arr->size(), reserve_implementation<T>());
     265           67 :     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           49 :     auto ins = detail::inserter(result, inserter_implementation<T>());
     273         3197 :     for( value const& val: *arr )
     274              :     {
     275         3142 :         auto elem_res = try_value_to<value_type<T>>( val, ctx );
     276         3142 :         if( elem_res.has_error() )
     277           12 :             return {boost::system::in_place_error, elem_res.error()};
     278         3130 :         *ins++ = std::move(*elem_res);
     279              :     }
     280           37 :     return result;
     281           43 : }
     282              : 
     283              : // tuple-like types
     284              : template< class T, class Ctx >
     285              : system::result<T>
     286          190 : try_make_tuple_elem(value const& jv, Ctx const& ctx, system::error_code& ec)
     287              : {
     288          190 :     if( ec.failed() )
     289           36 :         return {boost::system::in_place_error, ec};
     290              : 
     291          154 :     auto result = try_value_to<T>( jv, ctx );
     292          154 :     ec = result.error();
     293          154 :     return result;
     294           48 : }
     295              : 
     296              : template <class T, class Ctx, std::size_t... Is>
     297              : system::result<T>
     298           73 : try_make_tuple_like(
     299              :     array const& arr, Ctx const& ctx, boost::mp11::index_sequence<Is...>)
     300              : {
     301           73 :     system::error_code ec;
     302           85 :     auto items = std::make_tuple(
     303              :         try_make_tuple_elem<
     304           91 :             typename std::decay<tuple_element_t<Is, T>>::type >(
     305              :                 arr[Is], ctx, ec)
     306              :             ...);
     307           73 :     if( ec.failed() )
     308           12 :         return {boost::system::in_place_error, ec};
     309              : 
     310              :     return {
     311           61 :         boost::system::in_place_value, T(std::move(*std::get<Is>(items))...)};
     312           48 : }
     313              : 
     314              : template< class T, class Ctx >
     315              : system::result<T>
     316           97 : value_to_impl(
     317              :     tuple_conversion_tag,
     318              :     try_value_to_tag<T>,
     319              :     value const& jv,
     320              :     Ctx const& ctx )
     321              : {
     322           97 :     system::error_code ec;
     323              : 
     324           97 :     array const* arr = jv.if_array();
     325           97 :     if( !arr )
     326              :     {
     327           12 :         BOOST_JSON_FAIL(ec, error::not_array);
     328           12 :         return {boost::system::in_place_error, ec};
     329              :     }
     330              : 
     331           85 :     constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
     332           85 :     if( N != arr->size() )
     333              :     {
     334           12 :         BOOST_JSON_FAIL(ec, error::size_mismatch);
     335           12 :         return {boost::system::in_place_error, ec};
     336              :     }
     337              : 
     338           19 :     return try_make_tuple_like<T>(
     339           73 :         *arr, ctx, boost::mp11::make_index_sequence<N>());
     340              : }
     341              : 
     342              : template< class Ctx, class T, bool non_throwing = true >
     343              : struct to_described_member
     344              : {
     345              :     using Ds = described_members<T>;
     346              : 
     347              :     using result_type = mp11::mp_eval_if_c<
     348              :         !non_throwing, T, system::result, T>;
     349              : 
     350              :     result_type& res;
     351              :     object const& obj;
     352              :     std::size_t count;
     353              :     Ctx const& ctx;
     354              : 
     355              :     template< class I >
     356              :     void
     357              :     operator()(I)
     358              :     {
     359              :         if( !res )
     360              :             return;
     361              : 
     362              :         using D = mp11::mp_at<Ds, I>;
     363              :         using M = described_member_t<T, D>;
     364              : 
     365              :         auto const found = obj.find(D::name);
     366              :         if( found == obj.end() )
     367              :         {
     368              :             BOOST_IF_CONSTEXPR( !is_optional_like<M>::value )
     369              :             {
     370              :                 system::error_code ec;
     371              :                 BOOST_JSON_FAIL(ec, error::unknown_name);
     372              :                 res = {boost::system::in_place_error, ec};
     373              :             }
     374              :             return;
     375              :         }
     376              : 
     377              : #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
     378              : # pragma GCC diagnostic push
     379              : # pragma GCC diagnostic ignored "-Wunused"
     380              : # pragma GCC diagnostic ignored "-Wunused-variable"
     381              : #endif
     382              :         auto member_res = try_value_to<M>( found->value(), ctx );
     383              : #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
     384              : # pragma GCC diagnostic pop
     385              : #endif
     386              :         if( member_res )
     387              :         {
     388              :             (*res).* D::pointer = std::move(*member_res);
     389              :             ++count;
     390              :         }
     391              :         else
     392              :             res = {boost::system::in_place_error, member_res.error()};
     393              :     }
     394              : };
     395              : 
     396              : // described classes
     397              : template< class T, class Ctx >
     398              : system::result<T>
     399              : value_to_impl(
     400              :     described_class_conversion_tag,
     401              :     try_value_to_tag<T>,
     402              :     value const& jv,
     403              :     Ctx const& ctx )
     404              : {
     405              :     BOOST_STATIC_ASSERT( std::is_default_constructible<T>::value );
     406              :     system::result<T> res;
     407              : 
     408              :     auto* obj = jv.if_object();
     409              :     if( !obj )
     410              :     {
     411              :         system::error_code ec;
     412              :         BOOST_JSON_FAIL(ec, error::not_object);
     413              :         res = {boost::system::in_place_error, ec};
     414              :         return res;
     415              :     }
     416              : 
     417              :     to_described_member< Ctx, T > member_converter{ res, *obj, 0u, ctx };
     418              : 
     419              :     using Ds = typename decltype(member_converter)::Ds;
     420              :     constexpr std::size_t N = mp11::mp_size<Ds>::value;
     421              :     mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
     422              : 
     423              :     if( !res )
     424              :         return res;
     425              : 
     426              :     if( member_converter.count != obj->size() )
     427              :     {
     428              :         system::error_code ec;
     429              :         BOOST_JSON_FAIL(ec, error::size_mismatch);
     430              :         res = {boost::system::in_place_error, ec};
     431              :         return res;
     432              :     }
     433              : 
     434              :     return res;
     435              : }
     436              : 
     437              : // described enums
     438              : template< class T, class Ctx >
     439              : system::result<T>
     440              : value_to_impl(
     441              :     described_enum_conversion_tag,
     442              :     try_value_to_tag<T>,
     443              :     value const& jv,
     444              :     Ctx const& )
     445              : {
     446              :     T val = {};
     447              :     (void)jv;
     448              : #ifdef BOOST_DESCRIBE_CXX14
     449              :     system::error_code ec;
     450              : 
     451              :     auto str = jv.if_string();
     452              :     if( !str )
     453              :     {
     454              :         BOOST_JSON_FAIL(ec, error::not_string);
     455              :         return {system::in_place_error, ec};
     456              :     }
     457              : 
     458              :     if( !describe::enum_from_string(str->data(), val) )
     459              :     {
     460              :         BOOST_JSON_FAIL(ec, error::unknown_name);
     461              :         return {system::in_place_error, ec};
     462              :     }
     463              : #endif
     464              : 
     465              :     return {system::in_place_value, val};
     466              : }
     467              : 
     468              : // optionals
     469              : template< class T, class Ctx >
     470              : system::result<T>
     471              : value_to_impl(
     472              :     optional_conversion_tag,
     473              :     try_value_to_tag<T>,
     474              :     value const& jv,
     475              :     Ctx const& ctx)
     476              : {
     477              :     using Inner = value_result_type<T>;
     478              :     if( jv.is_null() )
     479              :         return {};
     480              :     else
     481              :         return try_value_to<Inner>(jv, ctx);
     482              : }
     483              : 
     484              : // variants
     485              : template< class T, class V, class I >
     486              : using variant_construction_category = mp11::mp_cond<
     487              :     std::is_constructible< T, variant2::in_place_index_t<I::value>, V >,
     488              :         mp11::mp_int<2>,
     489              : #ifndef BOOST_NO_CXX17_HDR_VARIANT
     490              :     std::is_constructible< T, std::in_place_index_t<I::value>, V >,
     491              :         mp11::mp_int<1>,
     492              : #endif // BOOST_NO_CXX17_HDR_VARIANT
     493              :     mp11::mp_true,
     494              :         mp11::mp_int<0> >;
     495              : 
     496              : template< class T, class I, class V >
     497              : T
     498              : initialize_variant( V&& v, mp11::mp_int<0> )
     499              : {
     500              :     T t;
     501              :     t.template emplace<I::value>( std::move(v) );
     502              :     return t;
     503              : }
     504              : 
     505              : template< class T, class I, class V >
     506              : T
     507              : initialize_variant( V&& v, mp11::mp_int<2> )
     508              : {
     509              :     return T( variant2::in_place_index_t<I::value>(), std::move(v) );
     510              : }
     511              : 
     512              : #ifndef BOOST_NO_CXX17_HDR_VARIANT
     513              : template< class T, class I, class V >
     514              : T
     515              : initialize_variant( V&& v, mp11::mp_int<1> )
     516              : {
     517              :     return T( std::in_place_index_t<I::value>(), std::move(v) );
     518              : }
     519              : #endif // BOOST_NO_CXX17_HDR_VARIANT
     520              : 
     521              : struct locally_prohibit_exceptions
     522              : {};
     523              : 
     524              : template< class Ctx >
     525              : Ctx const&
     526              : make_locally_nonthrowing_context(Ctx const& ctx) noexcept
     527              : {
     528              :     return ctx;
     529              : }
     530              : 
     531              : template< class... Ctxes >
     532              : std::tuple<Ctxes...> const&
     533              : make_locally_nonthrowing_context(std::tuple<Ctxes...> const& ctx) noexcept
     534              : {
     535              :     return ctx;
     536              : }
     537              : 
     538              : template< class... Ctxes >
     539              : std::tuple<locally_prohibit_exceptions, allow_exceptions, Ctxes...>
     540              : make_locally_nonthrowing_context(std::tuple<allow_exceptions, Ctxes...> const& ctx)
     541              :     noexcept
     542              : {
     543              :     return std::tuple_cat(std::make_tuple( locally_prohibit_exceptions() ), ctx);
     544              : }
     545              : 
     546              : template< class Ctx >
     547              : Ctx const&
     548              : remove_local_exception_prohibition(Ctx const& ctx) noexcept
     549              : {
     550              :     return ctx;
     551              : }
     552              : 
     553              : template< class T, class... Ts, std::size_t... Is>
     554              : std::tuple<Ts...>
     555              : remove_local_exception_prohibition_helper(
     556              :     std::tuple<T, Ts...> const& tup,
     557              :     mp11::index_sequence<Is...>) noexcept
     558              : {
     559              :     return std::tuple<Ts...>( std::get<Is + 1>(tup)... );
     560              : }
     561              : 
     562              : template< class... Ctxes >
     563              : std::tuple<Ctxes...>
     564              : remove_local_exception_prohibition(
     565              :     std::tuple<locally_prohibit_exceptions, Ctxes...> const& ctx) noexcept
     566              : {
     567              :     return remove_local_exception_prohibition_helper(
     568              :         ctx, mp11::index_sequence_for<Ctxes...>() );
     569              : }
     570              : 
     571              : template< class T, class Ctx >
     572              : struct alternative_converter
     573              : {
     574              :     system::result<T>& res;
     575              :     value const& jv;
     576              :     Ctx const& ctx;
     577              : 
     578              :     template< class I >
     579              :     void operator()( I ) const
     580              :     {
     581              :         if( res )
     582              :             return;
     583              : 
     584              :         auto&& local_ctx = make_locally_nonthrowing_context(ctx);
     585              :         using V = mp11::mp_at<T, I>;
     586              :         auto attempt = try_value_to<V>(jv, local_ctx);
     587              :         if( attempt )
     588              :         {
     589              :             using cat = variant_construction_category<T, V, I>;
     590              :             res = initialize_variant<T, I>( std::move(*attempt), cat() );
     591              :         }
     592              :     }
     593              : };
     594              : 
     595              : template< class T, class Ctx >
     596              : system::result<T>
     597              : value_to_impl(
     598              :     variant_conversion_tag,
     599              :     try_value_to_tag<T>,
     600              :     value const& jv,
     601              :     Ctx const& ctx)
     602              : {
     603              :     system::error_code ec;
     604              :     BOOST_JSON_FAIL(ec, error::exhausted_variants);
     605              : 
     606              :     using Is = mp11::mp_iota< mp11::mp_size<T> >;
     607              : 
     608              :     system::result<T> res = {system::in_place_error, ec};
     609              :     mp11::mp_for_each<Is>( alternative_converter<T, Ctx>{res, jv, ctx} );
     610              :     return res;
     611              : }
     612              : 
     613              : template< class T, class Ctx >
     614              : system::result<T>
     615              : value_to_impl(
     616              :     path_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
     617              : {
     618              :     auto str = jv.if_string();
     619              :     if( !str )
     620              :     {
     621              :         system::error_code ec;
     622              :         BOOST_JSON_FAIL(ec, error::not_string);
     623              :         return {boost::system::in_place_error, ec};
     624              :     }
     625              : 
     626              :     string_view sv = str->subview();
     627              :     return {boost::system::in_place_value, T( sv.begin(), sv.end() )};
     628              : }
     629              : 
     630              : //----------------------------------------------------------
     631              : // User-provided conversions; throwing -> throwing
     632              : template< class T, class Ctx >
     633              : mp11::mp_if< mp11::mp_valid<has_user_conversion_to_impl, T>, T >
     634            1 : value_to_impl(
     635              :     user_conversion_tag, value_to_tag<T> tag, value const& jv, Ctx const&)
     636              : {
     637            1 :     return tag_invoke(tag, jv);
     638              : }
     639              : 
     640              : template<
     641              :     class T,
     642              :     class Ctx,
     643              :     class Sup = supported_context<Ctx, T, value_to_conversion>
     644              : >
     645              : mp11::mp_if<
     646              :     mp11::mp_valid< has_context_conversion_to_impl, typename Sup::type, T>, T >
     647            1 : value_to_impl(
     648              :     context_conversion_tag,
     649              :     value_to_tag<T> tag,
     650              :     value const& jv,
     651              :     Ctx const& ctx )
     652              : {
     653            1 :     return tag_invoke( tag, jv, Sup::get(ctx) );
     654              : }
     655              : 
     656              : template<
     657              :     class T,
     658              :     class Ctx,
     659              :     class Sup = supported_context<Ctx, T, value_to_conversion>
     660              : >
     661              : mp11::mp_if<
     662              :     mp11::mp_valid<
     663              :         has_full_context_conversion_to_impl, typename Sup::type, T>,
     664              :     T>
     665              : value_to_impl(
     666              :     full_context_conversion_tag,
     667              :     value_to_tag<T> tag,
     668              :     value const& jv,
     669              :     Ctx const& ctx )
     670              : {
     671              :     return tag_invoke( tag, jv, Sup::get(ctx), ctx );
     672              : }
     673              : 
     674              : //----------------------------------------------------------
     675              : // User-provided conversions; throwing -> nonthrowing
     676              : template< class T, class Ctx >
     677              : mp11::mp_if_c< !mp11::mp_valid<has_user_conversion_to_impl, T>::value, T>
     678           49 : value_to_impl(
     679              :     user_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& )
     680              : {
     681           49 :     auto res = tag_invoke(try_value_to_tag<T>(), jv);
     682           49 :     if( res.has_error() )
     683           12 :         throw_system_error( res.error() );
     684           74 :     return std::move(*res);
     685           24 : }
     686              : 
     687              : template<
     688              :     class T,
     689              :     class Ctx,
     690              :     class Sup = supported_context<Ctx, T, value_to_conversion>
     691              : >
     692              : mp11::mp_if_c<
     693              :     !mp11::mp_valid<
     694              :         has_context_conversion_to_impl, typename Sup::type, T>::value,
     695              :     T>
     696            3 : value_to_impl(
     697              :     context_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& ctx )
     698              : {
     699            3 :     auto res = tag_invoke( try_value_to_tag<T>(), jv, Sup::get(ctx) );
     700            3 :     if( res.has_error() )
     701            1 :         throw_system_error( res.error() );
     702            4 :     return std::move(*res);
     703              : }
     704              : 
     705              : template< class Ctx >
     706              : std::tuple<allow_exceptions, Ctx>
     707          143 : make_throwing_context(Ctx const& ctx)
     708              : {
     709          143 :     return std::tuple<allow_exceptions, Ctx>(allow_exceptions(), ctx);
     710              : }
     711              : 
     712              : template< class... Ctxes >
     713              : std::tuple<allow_exceptions, Ctxes...>
     714          141 : make_throwing_context(std::tuple<Ctxes...> const& ctx)
     715              : {
     716          282 :     return std::tuple_cat(std::make_tuple( allow_exceptions() ), ctx);
     717              : }
     718              : 
     719              : template< class... Ctxes >
     720              : std::tuple<allow_exceptions, Ctxes...> const&
     721              : make_throwing_context(std::tuple<allow_exceptions, Ctxes...> const& ctx)
     722              :     noexcept
     723              : {
     724              :     return ctx;
     725              : }
     726              : 
     727              : template<
     728              :     class T,
     729              :     class Ctx,
     730              :     class Sup = supported_context<Ctx, T, value_to_conversion>
     731              : >
     732              : mp11::mp_if_c<
     733              :     !mp11::mp_valid<
     734              :         has_full_context_conversion_to_impl, typename Sup::type, T>::value,
     735              :     T>
     736              : value_to_impl(
     737              :     full_context_conversion_tag,
     738              :     value_to_tag<T>,
     739              :     value const& jv,
     740              :     Ctx const& ctx )
     741              : {
     742              :     auto res = tag_invoke(
     743              :         try_value_to_tag<T>(),
     744              :         jv,
     745              :         Sup::get(ctx),
     746              :         make_throwing_context(ctx));
     747              :     if( res.has_error() )
     748              :         throw_system_error( res.error() );
     749              :     return std::move(*res);
     750              : }
     751              : 
     752              : //----------------------------------------------------------
     753              : // User-provided conversions; nonthrowing -> nonthrowing
     754              : template< class T, class Ctx >
     755              : mp11::mp_if<
     756              :     mp11::mp_valid<
     757              :         has_nonthrowing_user_conversion_to_impl, T>, system::result<T> >
     758          116 : value_to_impl(
     759              :     user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
     760              : {
     761          116 :     return tag_invoke(try_value_to_tag<T>(), jv);
     762              : }
     763              : 
     764              : template<
     765              :     class T,
     766              :     class Ctx,
     767              :     class Sup = supported_context<Ctx, T, value_to_conversion>
     768              : >
     769              : mp11::mp_if<
     770              :     mp11::mp_valid<
     771              :         has_nonthrowing_context_conversion_to_impl, typename Sup::type, T>,
     772              :     system::result<T> >
     773              : value_to_impl(
     774              :     context_conversion_tag,
     775              :     try_value_to_tag<T> tag,
     776              :     value const& jv,
     777              :     Ctx const& ctx )
     778              : {
     779              :     return tag_invoke( tag, jv, Sup::get(ctx) );
     780              : }
     781              : 
     782              : template<
     783              :     class T,
     784              :     class Ctx,
     785              :     class Sup = supported_context<Ctx, T, value_to_conversion>
     786              : >
     787              : mp11::mp_if<
     788              :     mp11::mp_valid<
     789              :         has_nonthrowing_full_context_conversion_to_impl,
     790              :         typename Sup::type,
     791              :         T>,
     792              :     system::result<T> >
     793              : value_to_impl(
     794              :     full_context_conversion_tag,
     795              :     try_value_to_tag<T> tag,
     796              :     value const& jv,
     797              :     Ctx const& ctx )
     798              : {
     799              :     return tag_invoke( tag, jv, Sup::get(ctx), ctx );
     800              : }
     801              : 
     802              : //----------------------------------------------------------
     803              : // User-provided conversions; nonthrowing -> throwing
     804              : 
     805              : template< class Ctx >
     806              : struct does_allow_exceptions : std::false_type
     807              : { };
     808              : 
     809              : template< class... Ctxes >
     810              : struct does_allow_exceptions< std::tuple<allow_exceptions, Ctxes...> >
     811              :     : std::true_type
     812              : { };
     813              : 
     814              : template< class T, class... Args >
     815              : system::result<T>
     816           36 : wrap_conversion_exceptions( std::true_type, value_to_tag<T>, Args&& ... args )
     817              : {
     818              :     return {
     819              :         boost::system::in_place_value,
     820           36 :         tag_invoke( value_to_tag<T>(), static_cast<Args&&>(args)... )};
     821              : }
     822              : 
     823              : template< class T, class... Args >
     824              : system::result<T>
     825           36 : wrap_conversion_exceptions( std::false_type, value_to_tag<T>, Args&& ... args )
     826              : {
     827              : #ifndef BOOST_NO_EXCEPTIONS
     828              :     try
     829              :     {
     830              : #endif
     831           36 :         return wrap_conversion_exceptions(
     832              :             std::true_type(),
     833              :             value_to_tag<T>(),
     834           12 :             static_cast<Args&&>(args)... );
     835              : #ifndef BOOST_NO_EXCEPTIONS
     836              :     }
     837           30 :     catch( std::bad_alloc const&)
     838              :     {
     839            6 :         throw;
     840              :     }
     841           12 :     catch( system::system_error const& e)
     842              :     {
     843           12 :         return {boost::system::in_place_error, e.code()};
     844              :     }
     845           12 :     catch( ... )
     846              :     {
     847            6 :         system::error_code ec;
     848            6 :         BOOST_JSON_FAIL(ec, error::exception);
     849            6 :         return {boost::system::in_place_error, ec};
     850              :     }
     851              : #endif
     852              : }
     853              : 
     854              : template< class T, class Ctx >
     855              : mp11::mp_if_c<
     856              :     !mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>::value,
     857              :     system::result<T> >
     858           36 : value_to_impl(
     859              :     user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
     860              : {
     861           36 :     return wrap_conversion_exceptions(
     862           36 :         does_allow_exceptions<Ctx>(), value_to_tag<T>(), jv);
     863              : }
     864              : 
     865              : template<
     866              :     class T,
     867              :     class Ctx,
     868              :     class Sup = supported_context<Ctx, T, value_to_conversion>
     869              : >
     870              : mp11::mp_if_c<
     871              :     !mp11::mp_valid<
     872              :         has_nonthrowing_context_conversion_to_impl,
     873              :         typename Sup::type,
     874              :         T>::value,
     875              :     system::result<T> >
     876              : value_to_impl(
     877              :     context_conversion_tag,
     878              :     try_value_to_tag<T>,
     879              :     value const& jv,
     880              :     Ctx const& ctx )
     881              : {
     882              :     return wrap_conversion_exceptions(
     883              :         does_allow_exceptions<Ctx>(), value_to_tag<T>(), jv, Sup::get(ctx) );
     884              : }
     885              : 
     886              : template<
     887              :     class T,
     888              :     class Ctx,
     889              :     class Sup = supported_context<Ctx, T, value_to_conversion>
     890              : >
     891              : mp11::mp_if_c<
     892              :     !mp11::mp_valid<
     893              :         has_nonthrowing_full_context_conversion_to_impl,
     894              :         typename Sup::type,
     895              :         T>::value,
     896              :     system::result<T> >
     897              : value_to_impl(
     898              :     full_context_conversion_tag,
     899              :     try_value_to_tag<T>,
     900              :     value const& jv,
     901              :     Ctx const& ctx )
     902              : {
     903              :     return wrap_conversion_exceptions(
     904              :         does_allow_exceptions<Ctx>(),
     905              :         value_to_tag<T>(),
     906              :         jv,
     907              :         Sup::get(ctx),
     908              :         remove_local_exception_prohibition(ctx) );
     909              : }
     910              : 
     911              : // no suitable conversion implementation
     912              : template< class T, class Ctx >
     913              : T
     914              : value_to_impl( no_conversion_tag, value_to_tag<T>, value const&, Ctx const& )
     915              : {
     916              :     static_assert(
     917              :         !std::is_same<T, T>::value,
     918              :         "No suitable tag_invoke overload found for the type");
     919              : }
     920              : 
     921              : // generic wrapper over non-throwing implementations
     922              : template< class Impl, class T, class Ctx >
     923              : T
     924          284 : value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx )
     925              : {
     926          187 :     return value_to_impl(
     927          338 :         impl, try_value_to_tag<T>(), jv, make_throwing_context(ctx) ).value();
     928              : }
     929              : 
     930              : template< class Ctx, class T >
     931              : using value_to_category = conversion_category<
     932              :     Ctx, T, value_to_conversion >;
     933              : 
     934              : } // detail
     935              : 
     936              : #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
     937              : inline
     938              : system::result<std::nullopt_t>
     939              : tag_invoke(
     940              :     try_value_to_tag<std::nullopt_t>,
     941              :     value const& jv)
     942              : {
     943              :     if( jv.is_null() )
     944              :         return std::nullopt;
     945              :     system::error_code ec;
     946              :     BOOST_JSON_FAIL(ec, error::not_null);
     947              :     return ec;
     948              : }
     949              : #endif
     950              : 
     951              : } // namespace json
     952              : } // namespace boost
     953              : 
     954              : #endif
        

Generated by: LCOV version 2.1