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

Generated by: LCOV version 2.3