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

Generated by: LCOV version 2.3