value_from.hpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. //
  2. // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
  3. // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
  4. // Copyright (c) 2022 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. #ifndef BOOST_JSON_DETAIL_VALUE_FROM_HPP
  12. #define BOOST_JSON_DETAIL_VALUE_FROM_HPP
  13. #include <boost/json/conversion.hpp>
  14. #include <boost/describe/enum_to_string.hpp>
  15. #include <boost/mp11/algorithm.hpp>
  16. #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
  17. # include <optional>
  18. #endif
  19. namespace boost {
  20. namespace json {
  21. namespace detail {
  22. template< class Ctx, class T >
  23. struct append_tuple_element {
  24. array& arr;
  25. Ctx const& ctx;
  26. T&& t;
  27. template<std::size_t I>
  28. void
  29. operator()(mp11::mp_size_t<I>) const
  30. {
  31. using std::get;
  32. arr.emplace_back(value_from(
  33. get<I>(std::forward<T>(t)), ctx, arr.storage() ));
  34. }
  35. };
  36. //----------------------------------------------------------
  37. // User-provided conversion
  38. template< class T, class Ctx >
  39. void
  40. value_from_impl( user_conversion_tag, value& jv, T&& from, Ctx const& )
  41. {
  42. tag_invoke( value_from_tag(), jv, static_cast<T&&>(from) );
  43. }
  44. template< class T, class Ctx >
  45. void
  46. value_from_impl( context_conversion_tag, value& jv, T&& from, Ctx const& ctx)
  47. {
  48. using Sup = supported_context<Ctx, T, value_from_conversion>;
  49. tag_invoke( value_from_tag(), jv, static_cast<T&&>(from), Sup::get(ctx) );
  50. }
  51. template< class T, class Ctx >
  52. void
  53. value_from_impl(
  54. full_context_conversion_tag, value& jv, T&& from, Ctx const& ctx)
  55. {
  56. using Sup = supported_context<Ctx, T, value_from_conversion>;
  57. tag_invoke(
  58. value_from_tag(), jv, static_cast<T&&>(from), Sup::get(ctx), ctx );
  59. }
  60. //----------------------------------------------------------
  61. // Native conversion
  62. template< class T, class Ctx >
  63. void
  64. value_from_impl( native_conversion_tag, value& jv, T&& from, Ctx const& )
  65. {
  66. jv = std::forward<T>(from);
  67. }
  68. // null-like types
  69. template< class T, class Ctx >
  70. void
  71. value_from_impl( null_like_conversion_tag, value& jv, T&&, Ctx const& )
  72. {
  73. // do nothing
  74. BOOST_ASSERT(jv.is_null());
  75. (void)jv;
  76. }
  77. // string-like types
  78. template< class T, class Ctx >
  79. void
  80. value_from_impl( string_like_conversion_tag, value& jv, T&& from, Ctx const& )
  81. {
  82. auto sv = static_cast<string_view>(from);
  83. jv.emplace_string().assign(sv);
  84. }
  85. // map-like types
  86. template< class T, class Ctx >
  87. void
  88. value_from_impl( map_like_conversion_tag, value& jv, T&& from, Ctx const& ctx )
  89. {
  90. using std::get;
  91. object& obj = jv.emplace_object();
  92. obj.reserve(detail::try_size(from, size_implementation<T>()));
  93. for (auto&& elem : from)
  94. obj.emplace(
  95. get<0>(elem),
  96. value_from( get<1>(elem), ctx, obj.storage() ));
  97. }
  98. // ranges
  99. template< class T, class Ctx >
  100. void
  101. value_from_impl( sequence_conversion_tag, value& jv, T&& from, Ctx const& ctx )
  102. {
  103. array& result = jv.emplace_array();
  104. result.reserve(detail::try_size(from, size_implementation<T>()));
  105. using ForwardedValue = forwarded_value<T&&>;
  106. for (auto&& elem : from)
  107. result.emplace_back(
  108. value_from(
  109. // not a static_cast in order to appease clang < 4.0
  110. ForwardedValue(elem),
  111. ctx,
  112. result.storage() ));
  113. }
  114. // tuple-like types
  115. template< class T, class Ctx >
  116. void
  117. value_from_impl( tuple_conversion_tag, value& jv, T&& from, Ctx const& ctx )
  118. {
  119. constexpr std::size_t n =
  120. std::tuple_size<remove_cvref<T>>::value;
  121. array& arr = jv.emplace_array();
  122. arr.reserve(n);
  123. mp11::mp_for_each<mp11::mp_iota_c<n>>(
  124. append_tuple_element< Ctx, T >{ arr, ctx, std::forward<T>(from) });
  125. }
  126. // no suitable conversion implementation
  127. template< class T, class Ctx >
  128. void
  129. value_from_impl( no_conversion_tag, value&, T&&, Ctx const& )
  130. {
  131. static_assert(
  132. !std::is_same<T, T>::value,
  133. "No suitable tag_invoke overload found for the type");
  134. }
  135. template< class Ctx, class T >
  136. struct from_described_member
  137. {
  138. using Ds = describe::describe_members<
  139. remove_cvref<T>, describe::mod_public | describe::mod_inherited>;
  140. object& obj;
  141. Ctx const& ctx;
  142. T&& from;
  143. template< class I >
  144. void
  145. operator()(I) const
  146. {
  147. using D = mp11::mp_at<Ds, I>;
  148. obj.emplace(
  149. D::name,
  150. value_from(
  151. static_cast<T&&>(from).* D::pointer,
  152. ctx,
  153. obj.storage()));
  154. }
  155. };
  156. // described classes
  157. template< class T, class Ctx >
  158. void
  159. value_from_impl(
  160. described_class_conversion_tag, value& jv, T&& from, Ctx const& ctx )
  161. {
  162. object& obj = jv.emplace_object();
  163. from_described_member<Ctx, T> member_converter{
  164. obj, ctx, static_cast<T&&>(from)};
  165. using Ds = typename decltype(member_converter)::Ds;
  166. constexpr std::size_t N = mp11::mp_size<Ds>::value;
  167. obj.reserve(N);
  168. mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
  169. }
  170. // described enums
  171. template< class T, class Ctx >
  172. void
  173. value_from_impl(
  174. described_enum_conversion_tag, value& jv, T from, Ctx const& )
  175. {
  176. (void)jv;
  177. (void)from;
  178. #ifdef BOOST_DESCRIBE_CXX14
  179. char const* const name = describe::enum_to_string(from, nullptr);
  180. if( name )
  181. {
  182. string& str = jv.emplace_string();
  183. str.assign(name);
  184. }
  185. else
  186. {
  187. using Integer = typename std::underlying_type< remove_cvref<T> >::type;
  188. jv = static_cast<Integer>(from);
  189. }
  190. #endif
  191. }
  192. // optionals
  193. template< class T, class Ctx >
  194. void
  195. value_from_impl(
  196. optional_conversion_tag, value& jv, T&& from, Ctx const& ctx )
  197. {
  198. if( from )
  199. value_from( *from, ctx, jv );
  200. else
  201. jv = nullptr;
  202. }
  203. // variants
  204. template< class Ctx >
  205. struct value_from_visitor
  206. {
  207. value& jv;
  208. Ctx const& ctx;
  209. template<class T>
  210. void
  211. operator()(T&& t)
  212. {
  213. value_from( static_cast<T&&>(t), ctx, jv );
  214. }
  215. };
  216. template< class Ctx, class T >
  217. void
  218. value_from_impl( variant_conversion_tag, value& jv, T&& from, Ctx const& ctx )
  219. {
  220. visit( value_from_visitor<Ctx>{ jv, ctx }, static_cast<T&&>(from) );
  221. }
  222. //----------------------------------------------------------
  223. // Contextual conversions
  224. template< class Ctx, class T >
  225. using value_from_category = conversion_category<
  226. Ctx, T, value_from_conversion >;
  227. } // detail
  228. #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
  229. inline
  230. void
  231. tag_invoke(
  232. value_from_tag,
  233. value& jv,
  234. std::nullopt_t)
  235. {
  236. // do nothing
  237. BOOST_ASSERT(jv.is_null());
  238. (void)jv;
  239. }
  240. #endif
  241. } // namespace json
  242. } // namespace boost
  243. #endif