detail/value_from.hpp

100.0% Lines (46/46) 98.1% Functions (309/315)
detail/value_from.hpp
Line TLA Hits Source Code
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 295 operator()(mp11::mp_size_t<I>) const
38 {
39 using std::get;
40 590 arr.emplace_back(value_from(
41 600 get<I>(std::forward<T>(t)), ctx, arr.storage() ));
42 295 }
43 };
44
45 //----------------------------------------------------------
46 // User-provided conversion
47
48 template< class T, class Ctx >
49 void
50 35 value_from_impl( user_conversion_tag, value& jv, T&& from, Ctx const& )
51 {
52 35 tag_invoke( value_from_tag(), jv, static_cast<T&&>(from) );
53 35 }
54
55 template< class T, class Ctx >
56 void
57 26 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 26 tag_invoke( value_from_tag(), jv, static_cast<T&&>(from), Sup::get(ctx) );
61 26 }
62
63 template< class T, class Ctx >
64 void
65 2 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 2 tag_invoke(
70 2 value_from_tag(), jv, static_cast<T&&>(from), Sup::get(ctx), ctx );
71 2 }
72
73 //----------------------------------------------------------
74 // Native conversion
75
76 template< class T, class Ctx >
77 void
78 6622 value_from_impl( native_conversion_tag, value& jv, T&& from, Ctx const& )
79 {
80 6622 jv = std::forward<T>(from);
81 6622 }
82
83 // null-like types
84 template< class T, class Ctx >
85 void
86 11 value_from_impl( null_like_conversion_tag, value& jv, T&&, Ctx const& )
87 {
88 // do nothing
89 11 BOOST_ASSERT(jv.is_null());
90 (void)jv;
91 11 }
92
93 // string-like types
94 template< class T, class Ctx >
95 void
96 75 value_from_impl( string_like_conversion_tag, value& jv, T&& from, Ctx const& )
97 {
98 75 auto sv = static_cast<string_view>(from);
99 75 jv.emplace_string().assign(sv);
100 75 }
101
102 // map-like types
103 template< class T, class Ctx >
104 void
105 46 value_from_impl( map_like_conversion_tag, value& jv, T&& from, Ctx const& ctx )
106 {
107 using std::get;
108 46 object& obj = jv.emplace_object();
109 46 obj.reserve(detail::try_size(from, size_implementation<T>()));
110 145 for (auto&& elem : from)
111 297 obj.emplace(
112 99 get<0>(elem),
113 99 value_from( get<1>(elem), ctx, obj.storage() ));
114 46 }
115
116 // ranges
117 template< class T, class Ctx >
118 void
119 100 value_from_impl( sequence_conversion_tag, value& jv, T&& from, Ctx const& ctx )
120 {
121 100 array& result = jv.emplace_array();
122 100 result.reserve(detail::try_size(from, size_implementation<T>()));
123 using ForwardedValue = forwarded_value<T&&>;
124 6355 for (auto&& elem : from)
125 6445 result.emplace_back(
126 value_from(
127 // not a static_cast in order to appease clang < 4.0
128 190 ForwardedValue(elem),
129 ctx,
130 result.storage() ));
131 100 }
132
133 // tuple-like types
134 template< class T, class Ctx >
135 void
136 139 value_from_impl( tuple_conversion_tag, value& jv, T&& from, Ctx const& ctx )
137 {
138 139 constexpr std::size_t n =
139 std::tuple_size<remove_cvref<T>>::value;
140 139 array& arr = jv.emplace_array();
141 139 arr.reserve(n);
142 139 mp11::mp_for_each<mp11::mp_iota_c<n>>(
143 139 append_tuple_element< Ctx, T >{ arr, ctx, std::forward<T>(from) });
144 139 }
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 {
282 // do nothing
283 BOOST_ASSERT(jv.is_null());
284 (void)jv;
285 }
286 #endif
287
288 } // namespace json
289 } // namespace boost
290
291 #endif
292