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 % 143 143
Test Date: 2026-06-03 12:39:35 Functions: 96.8 % 696 674 22

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

Generated by: LCOV version 2.3