LCOV - code coverage report
Current view: top level - json/detail - value_to.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 100.0 % 157 157
Test Date: 2026-03-05 09:04:27 Functions: 98.2 % 626 615 11

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

Generated by: LCOV version 2.3