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