// // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com) // Copyright (c) 2022 Dmitry Arkhipov (grisumbras@gmail.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Official repository: https://github.com/boostorg/json // #ifndef BOOST_JSON_DETAIL_VALUE_FROM_HPP #define BOOST_JSON_DETAIL_VALUE_FROM_HPP #include #include #include #ifndef BOOST_NO_CXX17_HDR_OPTIONAL # include #endif BOOST_JSON_NS_BEGIN namespace detail { template struct append_tuple_element { array& arr; T&& t; template void operator()(mp11::mp_size_t) const { using std::get; arr.emplace_back(value_from( get(std::forward(t)), arr.storage())); } }; //---------------------------------------------------------- // User-provided conversion template void value_from_helper( value& jv, T&& from, user_conversion_tag) { tag_invoke(value_from_tag(), jv, std::forward(from)); } //---------------------------------------------------------- // Native conversion template void value_from_helper( value& jv, T&& from, native_conversion_tag) { jv = std::forward(from); } // null-like types template void value_from_helper( value& jv, T&&, null_like_conversion_tag) { // do nothing BOOST_ASSERT(jv.is_null()); (void)jv; } // string-like types template void value_from_helper( value& jv, T&& from, string_like_conversion_tag) { auto sv = static_cast(from); jv.emplace_string().assign(sv); } // map-like types template void value_from_helper( value& jv, T&& from, map_like_conversion_tag) { using std::get; object& obj = jv.emplace_object(); obj.reserve(detail::try_size(from, size_implementation())); for (auto&& elem : from) obj.emplace(get<0>(elem), value_from( get<1>(elem), obj.storage())); } // ranges template void value_from_helper( value& jv, T&& from, sequence_conversion_tag) { array& result = jv.emplace_array(); result.reserve(detail::try_size(from, size_implementation())); for (auto&& elem : from) result.emplace_back( value_from( static_cast< forwarded_value >(elem), result.storage() )); } // tuple-like types template void value_from_helper( value& jv, T&& from, tuple_conversion_tag) { constexpr std::size_t n = std::tuple_size>::value; array& arr = jv.emplace_array(); arr.reserve(n); mp11::mp_for_each>( append_tuple_element{arr, std::forward(from)}); } // no suitable conversion implementation template void value_from_helper( value&, T&&, no_conversion_tag) { static_assert( !std::is_same::value, "No suitable tag_invoke overload found for the type"); } #ifndef BOOST_NO_CXX17_HDR_VARIANT struct value_from_visitor { value& jv; template void operator()(T&& t) { value_from(static_cast(t), jv); } }; #endif // BOOST_NO_CXX17_HDR_VARIANT template< class T > struct from_described_member { using Ds = describe::describe_members< remove_cvref, describe::mod_public | describe::mod_inherited>; object& obj; T&& from; template< class I > void operator()(I) const { using D = mp11::mp_at; obj.emplace( D::name, value_from( static_cast(from).* D::pointer, obj.storage())); } }; // described classes template void value_from_helper( value& jv, T&& from, described_class_conversion_tag) { object& obj = jv.emplace_object(); from_described_member member_converter{obj, static_cast(from)}; using Ds = typename decltype(member_converter)::Ds; constexpr std::size_t N = mp11::mp_size::value; obj.reserve(N); mp11::mp_for_each< mp11::mp_iota_c >(member_converter); } // described enums template void value_from_helper( value& jv, T from, described_enum_conversion_tag) { (void)jv; (void)from; #ifdef BOOST_DESCRIBE_CXX14 char const* const name = describe::enum_to_string(from, nullptr); if( name ) { string& str = jv.emplace_string(); str.assign(name); } else { using Integer = typename std::underlying_type< remove_cvref >::type; jv = static_cast(from); } #endif } } // detail #ifndef BOOST_NO_CXX17_HDR_OPTIONAL template void tag_invoke( value_from_tag, value& jv, std::optional const& from) { if( from ) value_from(*from, jv); else jv = nullptr; } template void tag_invoke( value_from_tag, value& jv, std::optional&& from) { if( from ) value_from(std::move(*from), jv); else jv = nullptr; } inline void tag_invoke( value_from_tag, value& jv, std::nullopt_t) { // do nothing BOOST_ASSERT(jv.is_null()); (void)jv; } #endif #ifndef BOOST_NO_CXX17_HDR_VARIANT // std::variant template void tag_invoke( value_from_tag, value& jv, std::variant&& from) { std::visit(detail::value_from_visitor{jv}, std::move(from)); } template void tag_invoke( value_from_tag, value& jv, std::variant const& from) { std::visit(detail::value_from_visitor{jv}, from); } #endif // BOOST_NO_CXX17_HDR_VARIANT BOOST_JSON_NS_END #endif