value_from.hpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. //
  2. // Copyright (c) 2019 Vinnie Falco ([email protected])
  3. // Copyright (c) 2020 Krystian Stasiowski ([email protected])
  4. // Copyright (c) 2022 Dmitry Arkhipov ([email protected])
  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 = described_members< remove_cvref<T> >;
  139. object& obj;
  140. Ctx const& ctx;
  141. T&& from;
  142. template< class I >
  143. void
  144. operator()(I) const
  145. {
  146. using D = mp11::mp_at<Ds, I>;
  147. obj.emplace(
  148. D::name,
  149. value_from(
  150. static_cast<T&&>(from).* D::pointer,
  151. ctx,
  152. obj.storage()));
  153. }
  154. };
  155. // described classes
  156. template< class T, class Ctx >
  157. void
  158. value_from_impl(
  159. described_class_conversion_tag, value& jv, T&& from, Ctx const& ctx )
  160. {
  161. object& obj = jv.emplace_object();
  162. from_described_member<Ctx, T> member_converter{
  163. obj, ctx, static_cast<T&&>(from)};
  164. using Ds = typename decltype(member_converter)::Ds;
  165. constexpr std::size_t N = mp11::mp_size<Ds>::value;
  166. obj.reserve(N);
  167. mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
  168. }
  169. // described enums
  170. template< class T, class Ctx >
  171. void
  172. value_from_impl(
  173. described_enum_conversion_tag, value& jv, T from, Ctx const& )
  174. {
  175. (void)jv;
  176. (void)from;
  177. #ifdef BOOST_DESCRIBE_CXX14
  178. char const* const name = describe::enum_to_string(from, nullptr);
  179. if( name )
  180. {
  181. string& str = jv.emplace_string();
  182. str.assign(name);
  183. }
  184. else
  185. {
  186. using Integer = typename std::underlying_type< remove_cvref<T> >::type;
  187. jv = static_cast<Integer>(from);
  188. }
  189. #endif
  190. }
  191. // optionals
  192. template< class T, class Ctx >
  193. void
  194. value_from_impl(
  195. optional_conversion_tag, value& jv, T&& from, Ctx const& ctx )
  196. {
  197. if( from )
  198. value_from( *from, ctx, jv );
  199. else
  200. jv = nullptr;
  201. }
  202. // variants
  203. template< class Ctx >
  204. struct value_from_visitor
  205. {
  206. value& jv;
  207. Ctx const& ctx;
  208. template<class T>
  209. void
  210. operator()(T&& t)
  211. {
  212. value_from( static_cast<T&&>(t), ctx, jv );
  213. }
  214. };
  215. template< class Ctx, class T >
  216. void
  217. value_from_impl( variant_conversion_tag, value& jv, T&& from, Ctx const& ctx )
  218. {
  219. visit( value_from_visitor<Ctx>{ jv, ctx }, static_cast<T&&>(from) );
  220. }
  221. template< class Ctx, class T >
  222. void
  223. value_from_impl( path_conversion_tag, value& jv, T&& from, Ctx const& )
  224. {
  225. std::string s = from.generic_string();
  226. string_view sv = s;
  227. jv.emplace_string().assign(sv);
  228. }
  229. //----------------------------------------------------------
  230. // Contextual conversions
  231. template< class Ctx, class T >
  232. using value_from_category = conversion_category<
  233. Ctx, T, value_from_conversion >;
  234. } // detail
  235. #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
  236. inline
  237. void
  238. tag_invoke(
  239. value_from_tag,
  240. value& jv,
  241. std::nullopt_t)
  242. {
  243. // do nothing
  244. BOOST_ASSERT(jv.is_null());
  245. (void)jv;
  246. }
  247. #endif
  248. } // namespace json
  249. } // namespace boost
  250. #endif