LCOV - code coverage report
Current view: top level - json/impl - conversion.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 18 18
Test Date: 2025-12-23 17:20:51 Functions: 96.9 % 96 93

            Line data    Source code
       1              : //
       2              : // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
       3              : // Copyright (c) 2022 Dmitry Arkhipov (grisumbras@yandex.ru)
       4              : //
       5              : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       6              : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       7              : //
       8              : // Official repository: https://github.com/boostorg/json
       9              : //
      10              : 
      11              : #ifndef BOOST_JSON_IMPL_CONVERSION_HPP
      12              : #define BOOST_JSON_IMPL_CONVERSION_HPP
      13              : 
      14              : #include <boost/json/fwd.hpp>
      15              : #include <boost/json/value.hpp>
      16              : #include <boost/json/string_view.hpp>
      17              : #include <boost/describe/enumerators.hpp>
      18              : #include <boost/describe/members.hpp>
      19              : #include <boost/describe/bases.hpp>
      20              : #include <boost/mp11/algorithm.hpp>
      21              : #include <boost/mp11/utility.hpp>
      22              : #include <boost/system/result.hpp>
      23              : 
      24              : #include <iterator>
      25              : #include <tuple>
      26              : #include <utility>
      27              : #ifndef BOOST_NO_CXX17_HDR_VARIANT
      28              : # include <variant>
      29              : #endif // BOOST_NO_CXX17_HDR_VARIANT
      30              : 
      31              : namespace boost {
      32              : namespace json {
      33              : namespace detail {
      34              : 
      35              : struct no_context
      36              : {};
      37              : 
      38              : #ifdef __cpp_lib_nonmember_container_access
      39              : using std::size;
      40              : #endif
      41              : 
      42              : template<std::size_t I, class T>
      43              : using tuple_element_t = typename std::tuple_element<I, T>::type;
      44              : 
      45              : template<class T>
      46              : using iterator_type = decltype(std::begin(std::declval<T&>()));
      47              : template<class T>
      48              : using iterator_traits = std::iterator_traits< iterator_type<T> >;
      49              : 
      50              : template<class T>
      51              : using value_type = typename iterator_traits<T>::value_type;
      52              : template<class T>
      53              : using mapped_type = tuple_element_t< 1, value_type<T> >;
      54              : 
      55              : // had to make the metafunction always succeeding in order to make it work
      56              : // with msvc 14.0
      57              : template<class T>
      58              : using key_type_helper = tuple_element_t< 0, value_type<T> >;
      59              : template<class T>
      60              : using key_type = mp11::mp_eval_or<
      61              :     void,
      62              :     key_type_helper,
      63              :     T>;
      64              : 
      65              : template<class T>
      66              : using are_begin_and_end_same = std::is_same<
      67              :     iterator_type<T>,
      68              :     decltype(std::end(std::declval<T&>()))>;
      69              : 
      70              : // msvc 14.0 gets confused when std::is_same is used directly
      71              : template<class A, class B>
      72              : using is_same_msvc_140 = std::is_same<A, B>;
      73              : template<class T>
      74              : using is_its_own_value = is_same_msvc_140<value_type<T>, T>;
      75              : 
      76              : template<class T>
      77              : using not_its_own_value = mp11::mp_not< is_its_own_value<T> >;
      78              : 
      79              : template<class T>
      80              : using begin_iterator_category = typename std::iterator_traits<
      81              :     iterator_type<T>>::iterator_category;
      82              : 
      83              : template<class T>
      84              : using has_positive_tuple_size = mp11::mp_bool<
      85              :     (std::tuple_size<T>::value > 0) >;
      86              : 
      87              : template<class T>
      88              : using has_unique_keys = has_positive_tuple_size<decltype(
      89              :     std::declval<T&>().emplace(
      90              :         std::declval<value_type<T>>()))>;
      91              : 
      92              : template<class T>
      93              : using has_string_type = std::is_same<
      94              :     typename T::string_type, std::basic_string<typename T::value_type> >;
      95              : 
      96              : template<class T>
      97              : struct is_value_type_pair_helper : std::false_type
      98              : { };
      99              : template<class T1, class T2>
     100              : struct is_value_type_pair_helper<std::pair<T1, T2>> : std::true_type
     101              : { };
     102              : template<class T>
     103              : using is_value_type_pair = is_value_type_pair_helper<value_type<T>>;
     104              : 
     105              : template<class T>
     106              : using has_size_member_helper
     107              :     = std::is_convertible<decltype(std::declval<T&>().size()), std::size_t>;
     108              : template<class T>
     109              : using has_size_member = mp11::mp_valid_and_true<has_size_member_helper, T>;
     110              : template<class T>
     111              : using has_free_size_helper
     112              :     = std::is_convertible<
     113              :         decltype(size(std::declval<T const&>())),
     114              :         std::size_t>;
     115              : template<class T>
     116              : using has_free_size = mp11::mp_valid_and_true<has_free_size_helper, T>;
     117              : template<class T>
     118              : using size_implementation = mp11::mp_cond<
     119              :     has_size_member<T>, mp11::mp_int<3>,
     120              :     has_free_size<T>,   mp11::mp_int<2>,
     121              :     std::is_array<T>,   mp11::mp_int<1>,
     122              :     mp11::mp_true,      mp11::mp_int<0>>;
     123              : 
     124              : template<class T>
     125              : std::size_t
     126          155 : try_size(T&& cont, mp11::mp_int<3>)
     127              : {
     128          155 :     return cont.size();
     129              : }
     130              : 
     131              : template<class T>
     132              : std::size_t
     133            1 : try_size(T& cont, mp11::mp_int<2>)
     134              : {
     135            1 :     return size(cont);
     136              : }
     137              : 
     138              : template<class T, std::size_t N>
     139              : std::size_t
     140            1 : try_size(T(&)[N], mp11::mp_int<1>)
     141              : {
     142            1 :     return N;
     143              : }
     144              : 
     145              : template<class T>
     146              : std::size_t
     147            7 : try_size(T&, mp11::mp_int<0>)
     148              : {
     149            7 :     return 0;
     150              : }
     151              : 
     152              : template<class T>
     153              : using has_push_back_helper
     154              :     = decltype(std::declval<T&>().push_back(std::declval<value_type<T>>()));
     155              : template<class T>
     156              : using has_push_back = mp11::mp_valid<has_push_back_helper, T>;
     157              : template<class T>
     158              : using inserter_implementation = mp11::mp_cond<
     159              :     is_tuple_like<T>, mp11::mp_int<2>,
     160              :     has_push_back<T>, mp11::mp_int<1>,
     161              :     mp11::mp_true,    mp11::mp_int<0>>;
     162              : 
     163              : template<class T>
     164              : iterator_type<T>
     165           56 : inserter(
     166              :     T& target,
     167              :     mp11::mp_int<2>)
     168              : {
     169           56 :     return target.begin();
     170              : }
     171              : 
     172              : template<class T>
     173              : std::back_insert_iterator<T>
     174          590 : inserter(
     175              :     T& target,
     176              :     mp11::mp_int<1>)
     177              : {
     178          590 :     return std::back_inserter(target);
     179              : }
     180              : 
     181              : template<class T>
     182              : std::insert_iterator<T>
     183           72 : inserter(
     184              :     T& target,
     185              :     mp11::mp_int<0>)
     186              : {
     187           72 :     return std::inserter( target, target.end() );
     188              : }
     189              : 
     190              : using value_from_conversion = mp11::mp_true;
     191              : using value_to_conversion = mp11::mp_false;
     192              : 
     193              : struct user_conversion_tag { };
     194              : struct context_conversion_tag : user_conversion_tag { };
     195              : struct full_context_conversion_tag : context_conversion_tag { };
     196              : struct native_conversion_tag { };
     197              : struct value_conversion_tag : native_conversion_tag { };
     198              : struct object_conversion_tag : native_conversion_tag { };
     199              : struct array_conversion_tag : native_conversion_tag { };
     200              : struct string_conversion_tag : native_conversion_tag { };
     201              : struct bool_conversion_tag : native_conversion_tag { };
     202              : struct number_conversion_tag : native_conversion_tag { };
     203              : struct integral_conversion_tag : number_conversion_tag { };
     204              : struct floating_point_conversion_tag : number_conversion_tag { };
     205              : struct null_like_conversion_tag { };
     206              : struct string_like_conversion_tag { };
     207              : struct map_like_conversion_tag { };
     208              : struct path_conversion_tag { };
     209              : struct sequence_conversion_tag { };
     210              : struct tuple_conversion_tag { };
     211              : struct described_class_conversion_tag { };
     212              : struct described_enum_conversion_tag { };
     213              : struct variant_conversion_tag { };
     214              : struct optional_conversion_tag { };
     215              : struct no_conversion_tag { };
     216              : 
     217              : template<class... Args>
     218              : using supports_tag_invoke = decltype(tag_invoke( std::declval<Args>()... ));
     219              : 
     220              : template<class T>
     221              : using has_user_conversion_from_impl = supports_tag_invoke<
     222              :     value_from_tag, value&, T&& >;
     223              : template<class T>
     224              : using has_user_conversion_to_impl = supports_tag_invoke<
     225              :     value_to_tag<T>, value const& >;
     226              : template<class T>
     227              : using has_nonthrowing_user_conversion_to_impl = supports_tag_invoke<
     228              :     try_value_to_tag<T>, value const& >;
     229              : template< class T, class Dir >
     230              : using has_user_conversion1 = mp11::mp_if<
     231              :     std::is_same<Dir, value_from_conversion>,
     232              :     mp11::mp_valid<has_user_conversion_from_impl, T>,
     233              :     mp11::mp_or<
     234              :         mp11::mp_valid<has_user_conversion_to_impl, T>,
     235              :         mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>>>;
     236              : 
     237              : template< class Ctx, class T >
     238              : using has_context_conversion_from_impl = supports_tag_invoke<
     239              :     value_from_tag, value&, T&&, Ctx const& >;
     240              : template< class Ctx, class T >
     241              : using has_context_conversion_to_impl = supports_tag_invoke<
     242              :     value_to_tag<T>, value const&, Ctx const& >;
     243              : template< class Ctx, class T >
     244              : using has_nonthrowing_context_conversion_to_impl = supports_tag_invoke<
     245              :     try_value_to_tag<T>, value const&, Ctx const& >;
     246              : template< class Ctx, class T, class Dir >
     247              : using has_user_conversion2 = mp11::mp_if<
     248              :     std::is_same<Dir, value_from_conversion>,
     249              :     mp11::mp_valid<has_context_conversion_from_impl, Ctx, T>,
     250              :     mp11::mp_or<
     251              :         mp11::mp_valid<has_context_conversion_to_impl, Ctx, T>,
     252              :         mp11::mp_valid<has_nonthrowing_context_conversion_to_impl, Ctx, T>>>;
     253              : 
     254              : template< class Ctx, class T >
     255              : using has_full_context_conversion_from_impl = supports_tag_invoke<
     256              :     value_from_tag, value&, T&&, Ctx const&, Ctx const& >;
     257              : template< class Ctx, class T >
     258              : using has_full_context_conversion_to_impl = supports_tag_invoke<
     259              :     value_to_tag<T>, value const&, Ctx const&,  Ctx const& >;
     260              : template< class Ctx, class T >
     261              : using has_nonthrowing_full_context_conversion_to_impl = supports_tag_invoke<
     262              :     try_value_to_tag<T>, value const&, Ctx const&, Ctx const& >;
     263              : template< class Ctx, class T, class Dir >
     264              : using has_user_conversion3 = mp11::mp_if<
     265              :     std::is_same<Dir, value_from_conversion>,
     266              :     mp11::mp_valid<has_full_context_conversion_from_impl, Ctx, T>,
     267              :     mp11::mp_or<
     268              :         mp11::mp_valid<has_full_context_conversion_to_impl, Ctx, T>,
     269              :         mp11::mp_valid<
     270              :             has_nonthrowing_full_context_conversion_to_impl, Ctx, T>>>;
     271              : 
     272              : template< class T >
     273              : using described_non_public_members = describe::describe_members<
     274              :     T, describe::mod_private | describe::mod_protected>;
     275              : template< class T >
     276              : using described_bases = describe::describe_bases<
     277              :     T, describe::mod_any_access>;
     278              : 
     279              : #if defined(BOOST_MSVC) && BOOST_MSVC < 1920
     280              : 
     281              : template< class T >
     282              : struct described_member_t_impl;
     283              : 
     284              : template< class T, class C >
     285              : struct described_member_t_impl<T C::*>
     286              : {
     287              :     using type = T;
     288              : };
     289              : 
     290              : template< class T, class D >
     291              : using described_member_t = remove_cvref<
     292              :     typename described_member_t_impl<
     293              :         remove_cvref<decltype(D::pointer)> >::type>;
     294              : 
     295              : #else
     296              : 
     297              : template< class T, class D >
     298              : using described_member_t = remove_cvref<decltype(
     299              :     std::declval<T&>().* D::pointer )>;
     300              : 
     301              : #endif
     302              : 
     303              : template< class T >
     304              : using described_members = describe::describe_members<
     305              :     T, describe::mod_any_access | describe::mod_inherited>;
     306              : 
     307              : // user conversion (via tag_invoke)
     308              : template< class Ctx, class T, class Dir >
     309              : using user_conversion_category = mp11::mp_cond<
     310              :     has_user_conversion3<Ctx, T, Dir>, full_context_conversion_tag,
     311              :     has_user_conversion2<Ctx, T, Dir>, context_conversion_tag,
     312              :     has_user_conversion1<T, Dir>,      user_conversion_tag>;
     313              : 
     314              : // native conversions (constructors and member functions of value)
     315              : template< class T >
     316              : using native_conversion_category = mp11::mp_cond<
     317              :     std::is_same<T, value>,  value_conversion_tag,
     318              :     std::is_same<T, array>,  array_conversion_tag,
     319              :     std::is_same<T, object>, object_conversion_tag,
     320              :     std::is_same<T, string>, string_conversion_tag>;
     321              : 
     322              : // generic conversions
     323              : template< class T, class Ctx >
     324              : using generic_conversion_category = mp11::mp_cond<
     325              :     std::is_same<T, bool>,     bool_conversion_tag,
     326              :     std::is_integral<T>,       integral_conversion_tag,
     327              :     std::is_floating_point<T>, floating_point_conversion_tag,
     328              :     is_null_like<T>,           null_like_conversion_tag,
     329              :     is_string_like<T>,         string_like_conversion_tag,
     330              :     is_map_like<T, Ctx>,       map_like_conversion_tag,
     331              :     is_sequence_like<T>,       sequence_conversion_tag,
     332              :     is_tuple_like<T>,          tuple_conversion_tag,
     333              :     is_described_class<T>,     described_class_conversion_tag,
     334              :     is_described_enum<T>,      described_enum_conversion_tag,
     335              :     is_variant_like<T>,        variant_conversion_tag,
     336              :     is_optional_like<T>,       optional_conversion_tag,
     337              :     is_path_like<T>,           path_conversion_tag,
     338              :     // failed to find a suitable implementation
     339              :     mp11::mp_true,             no_conversion_tag>;
     340              : 
     341              : template< class T >
     342              : using nested_type = typename T::type;
     343              : template< class T1, class T2 >
     344              : using conversion_category_helper = mp11::mp_eval_if_not<
     345              :     std::is_same<detail::no_conversion_tag, T1>,
     346              :     T1,
     347              :     mp11::mp_eval_or_q, T1, mp11::mp_quote<nested_type>, T2>;
     348              : 
     349              : template< class Ctx >
     350              : using fix_context = mp11::mp_if< std::is_same<Ctx, no_context>, void, Ctx>;
     351              : 
     352              : template<class T, class Ctx>
     353              : using representation_or_void = mp11::mp_eval_or<void, represent_as_t, T, Ctx>;
     354              : 
     355              : template< class U >
     356              : using is_not_void = mp11::mp_bool< !std::is_same<void, U>::value >;
     357              : 
     358              : template< class T, class Ctxs >
     359              : struct representation_helper
     360              : {
     361              :     using size = mp11::mp_size<Ctxs>;
     362              : 
     363              :     template< class I >
     364              :     using exists = mp11::mp_less<I, size>;
     365              : 
     366              :     template< class Ctx >
     367              :     using step = representation_or_void<T, Ctx>;
     368              :     using reps = mp11::mp_transform<step, Ctxs>;
     369              :     using r_index = mp11::mp_find_if< reps, is_not_void >;
     370              : 
     371              :     using type = mp11::mp_eval_if<
     372              :         mp11::mp_not< exists<r_index> >,
     373              :         T,
     374              :         mp11::mp_at, reps, r_index>;
     375              : };
     376              : 
     377              : template< class T, class Ctx >
     378              : struct conversion_representation_impl
     379              :     : representation_helper< T, mp11::mp_list<Ctx, void> >
     380              : {};
     381              : 
     382              : template< class T >
     383              : struct conversion_representation_impl<T, no_context>
     384              :     : representation_helper< T, mp11::mp_list<void> >
     385              : {};
     386              : 
     387              : template< class T, class... Ctxs >
     388              : struct conversion_representation_impl< T, std::tuple<Ctxs...> >
     389              :     : representation_helper< T, mp11::mp_list<remove_cvref<Ctxs>..., void> >
     390              : {};
     391              : 
     392              : template< class T, class Ctx >
     393              : using conversion_representation
     394              :     = typename conversion_representation_impl<remove_cvref<T>, Ctx>::type;
     395              : 
     396              : template< class Ctx, class T, class Dir >
     397              : struct conversion_attrs
     398              : {
     399              :     using representation = conversion_representation<T, Ctx>;
     400              : 
     401              :     using category = mp11::mp_fold<
     402              :         mp11::mp_list<
     403              :             mp11::mp_defer<user_conversion_category, Ctx, representation, Dir>,
     404              :             mp11::mp_defer<native_conversion_category, representation>,
     405              :             mp11::mp_defer<generic_conversion_category, representation, Ctx>>,
     406              :         no_conversion_tag,
     407              :         conversion_category_helper>;
     408              : };
     409              : 
     410              : template< class T >
     411              : using any_conversion_tag = mp11::mp_not<
     412              :     std::is_same< T, no_conversion_tag > >;
     413              : 
     414              : template< class Ctx, class T, class Dir >
     415              : using conversion_category = typename conversion_attrs<Ctx, T, Dir>::category;
     416              : 
     417              : template< class T, class Dir, class... Ctxs >
     418              : struct conversion_attrs< std::tuple<Ctxs...>, T, Dir >
     419              : {
     420              :     using size = mp11::mp_size_t< sizeof...(Ctxs) >;
     421              :     using ctxs = mp11::mp_list< remove_cvref<Ctxs>... >;
     422              : 
     423              :     template< class I >
     424              :     using exists = mp11::mp_less<I, size>;
     425              : 
     426              :     using representation = conversion_representation< T, std::tuple<Ctxs...> >;
     427              : 
     428              :     using cats = mp11::mp_list<
     429              :         conversion_category<remove_cvref<Ctxs>, representation, Dir>... >;
     430              : 
     431              :     using context2 = mp11::mp_find< cats, full_context_conversion_tag >;
     432              :     using context1 = mp11::mp_find< cats, context_conversion_tag >;
     433              :     using context0 = mp11::mp_find< cats, user_conversion_tag >;
     434              :     using index = mp11::mp_cond<
     435              :         exists<context2>, context2,
     436              :         exists<context1>, context1,
     437              :         exists<context0>, context0,
     438              :         mp11::mp_true, mp11::mp_find_if< cats, any_conversion_tag > >;
     439              :     using category = mp11::mp_eval_or<
     440              :         no_conversion_tag,
     441              :         mp11::mp_at, cats, index >;
     442              : };
     443              : 
     444              : template <class T, class Dir>
     445              : using can_convert = mp11::mp_not<
     446              :     std::is_same<
     447              :         detail::conversion_category<no_context, T, Dir>,
     448              :         detail::no_conversion_tag>>;
     449              : 
     450              : template<class Impl1, class Impl2>
     451              : using conversion_round_trips_helper = mp11::mp_or<
     452              :     std::is_same<Impl1, Impl2>,
     453              :     std::is_base_of<user_conversion_tag, Impl1>,
     454              :     std::is_base_of<user_conversion_tag, Impl2>>;
     455              : template< class Ctx, class T, class Dir >
     456              : using conversion_round_trips  = conversion_round_trips_helper<
     457              :     conversion_category<Ctx, T, Dir>,
     458              :     conversion_category<Ctx, T, mp11::mp_not<Dir>>>;
     459              : 
     460              : template< class T1, class T2 >
     461              : struct copy_cref_helper
     462              : {
     463              :     using type = remove_cvref<T2>;
     464              : };
     465              : template< class T1, class T2 >
     466              : using copy_cref = typename copy_cref_helper< T1, T2 >::type;
     467              : 
     468              : template< class T1, class T2 >
     469              : struct copy_cref_helper<T1 const, T2>
     470              : {
     471              :     using type = remove_cvref<T2> const;
     472              : };
     473              : template< class T1, class T2 >
     474              : struct copy_cref_helper<T1&, T2>
     475              : {
     476              :     using type = copy_cref<T1, T2>&;
     477              : };
     478              : template< class T1, class T2 >
     479              : struct copy_cref_helper<T1&&, T2>
     480              : {
     481              :     using type = copy_cref<T1, T2>&&;
     482              : };
     483              : 
     484              : template< class Rng, class Traits >
     485              : using forwarded_value_helper = mp11::mp_if<
     486              :     std::is_convertible<
     487              :         typename Traits::reference,
     488              :         copy_cref<Rng, typename Traits::value_type> >,
     489              :     copy_cref<Rng, typename Traits::value_type>,
     490              :     typename Traits::value_type >;
     491              : 
     492              : template< class Rng >
     493              : using forwarded_value = forwarded_value_helper<
     494              :     Rng, iterator_traits< Rng > >;
     495              : 
     496              : template< class Ctx, class T, class Dir >
     497              : struct supported_context
     498              : {
     499              :     using type = Ctx;
     500              : 
     501              :     static
     502              :     type const&
     503           32 :     get( Ctx const& ctx ) noexcept
     504              :     {
     505           32 :         return ctx;
     506              :     }
     507              : };
     508              : 
     509              : template< class T, class Dir, class... Ctxs >
     510              : struct supported_context< std::tuple<Ctxs...>, T, Dir >
     511              : {
     512              :     using Ctx = std::tuple<Ctxs...>;
     513              :     using Attrs = conversion_attrs<Ctx, T, Dir>;
     514              :     using index = typename Attrs::index;
     515              :     using next_supported = supported_context<
     516              :         mp11::mp_at< typename Attrs::ctxs, index >, T, Dir >;
     517              :     using type = typename next_supported::type;
     518              : 
     519              :     static
     520              :     type const&
     521           19 :     get( Ctx const& ctx ) noexcept
     522              :     {
     523           19 :         return next_supported::get( std::get<index::value>( ctx ) );
     524              :     }
     525              : };
     526              : 
     527              : template< class T >
     528              : using value_result_type = typename std::decay<
     529              :     decltype( std::declval<T&>().value() )>::type;
     530              : 
     531              : template< class T >
     532              : using can_reset = decltype( std::declval<T&>().reset() );
     533              : 
     534              : template< class T >
     535              : using has_valueless_by_exception =
     536              :     decltype( std::declval<T const&>().valueless_by_exception() );
     537              : 
     538              : } // namespace detail
     539              : 
     540              : template <class T>
     541              : struct result_for<T, value>
     542              : {
     543              :     using type = system::result< detail::remove_cvref<T> >;
     544              : };
     545              : 
     546              : template<class T>
     547              : struct is_string_like
     548              :     : std::is_convertible<T, string_view>
     549              : { };
     550              : 
     551              : template<class T>
     552              : struct is_path_like
     553              :     : mp11::mp_all<
     554              :         mp11::mp_valid_and_true<detail::is_its_own_value, T>,
     555              :         mp11::mp_valid_and_true<detail::has_string_type, T>>
     556              : { };
     557              : template<class T>
     558              : struct is_sequence_like
     559              :     : mp11::mp_all<
     560              :         mp11::mp_valid_and_true<detail::are_begin_and_end_same, T>,
     561              :         mp11::mp_valid_and_true<detail::not_its_own_value, T>,
     562              :         mp11::mp_valid<detail::begin_iterator_category, T>>
     563              : { };
     564              : 
     565              : template<class T, class Ctx>
     566              : struct is_map_like
     567              :     : mp11::mp_all<
     568              :         is_sequence_like<T>,
     569              :         mp11::mp_valid_and_true<detail::is_value_type_pair, T>,
     570              :         is_string_like<
     571              :             detail::conversion_representation<
     572              :                 detail::remove_cvref< detail::key_type<T> >, Ctx>>,
     573              :         mp11::mp_valid_and_true<detail::has_unique_keys, T>>
     574              : { };
     575              : 
     576              : template<class T>
     577              : struct is_tuple_like
     578              :     : mp11::mp_valid_and_true<detail::has_positive_tuple_size, T>
     579              : { };
     580              : 
     581              : template<>
     582              : struct is_null_like<std::nullptr_t>
     583              :     : std::true_type
     584              : { };
     585              : 
     586              : #ifndef BOOST_NO_CXX17_HDR_VARIANT
     587              : template<>
     588              : struct is_null_like<std::monostate>
     589              :     : std::true_type
     590              : { };
     591              : #endif // BOOST_NO_CXX17_HDR_VARIANT
     592              : 
     593              : template<class T>
     594              : struct is_described_class
     595              :     : mp11::mp_and<
     596              :         describe::has_describe_members<T>,
     597              :         mp11::mp_not< std::is_union<T> >,
     598              :         mp11::mp_empty<
     599              :             mp11::mp_eval_or<
     600              :                 mp11::mp_list<>, detail::described_non_public_members, T>>,
     601              :         mp11::mp_empty<
     602              :             mp11::mp_eval_or<mp11::mp_list<>, detail::described_bases, T>>>
     603              : { };
     604              : 
     605              : template<class T>
     606              : struct is_described_enum
     607              :     : describe::has_describe_enumerators<T>
     608              : { };
     609              : 
     610              : template<class T>
     611              : struct is_variant_like : mp11::mp_valid<detail::has_valueless_by_exception, T>
     612              : { };
     613              : 
     614              : template<class T>
     615              : struct is_optional_like
     616              :     : mp11::mp_and<
     617              :         mp11::mp_not<std::is_void<
     618              :             mp11::mp_eval_or<void, detail::value_result_type, T>>>,
     619              :         mp11::mp_valid<detail::can_reset, T>>
     620              : { };
     621              : 
     622              : } // namespace json
     623              : } // namespace boost
     624              : 
     625              : #endif // BOOST_JSON_IMPL_CONVERSION_HPP
        

Generated by: LCOV version 2.1