value_from.hpp 6.9 KB

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