TLA Line data 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_VALUE_TO_HPP
13 : #define BOOST_JSON_VALUE_TO_HPP
14 :
15 : #include <boost/core/detail/static_assert.hpp>
16 : #include <boost/json/detail/value_to.hpp>
17 :
18 : namespace boost {
19 : namespace json {
20 :
21 : /** Convert a @ref value to an object of type `T`.
22 :
23 : This function attempts to convert a @ref value to `T` using
24 :
25 : - one of @ref value's accessors, or
26 : - a library-provided generic conversion, or
27 : - a user-provided overload of `tag_invoke`.
28 :
29 : In order to perform the conversion the function selects an appropriate
30 : implementation based on the types `T` and `Context` (if provided).
31 :
32 : 1. If `Context` is available and is not `std::tuple<C...>`
33 :
34 : a. check if `use_category<T, Context>::value` is not
35 : @ref conversion_category::unknown; otherwise
36 :
37 : b. check if a `tag_invoke` overload from the list below that takes a
38 : `Context const&` exists.
39 :
40 : 2. Otherwise, if `Context` is available, and is `std::tuple<C...>` repeat
41 : steps **1** and **2** recursively for every `C` until either
42 : step **1.a** or **1.b** succeeds for some `C`.
43 :
44 : 3. Failing that,
45 :
46 : a. check if `use_category<T>::value` is not
47 : @ref conversion_category::unknown; otherwise
48 :
49 : b. check if a `tag_invoke` overload from the list below that takes only
50 : 2 parameters exists; otherwise
51 :
52 : c. check if `T` is one of @ref value, @ref array, @ref object,
53 : or @ref string; otherwise
54 :
55 : d. check if `T` matches one of the categories of types described in the
56 : table "Conversion categories" in \<\<Value Conversion>> section.
57 :
58 : These steps determine both the appropriate category of conversion for `T`,
59 : and, if necessary, the effective context `C` that will be used for
60 : conversion. If the category is selected on steps **1.a**, **3.a**, **3.c**,
61 : or **3.d**, the library provides a suitable conversion implementation.
62 : If the category is selected on steps **2.b** or **3.b**, then a
63 : user-provided `tag_invoke` overload is used.
64 :
65 : The overloads of `tag_invoke` that will be considered by this function
66 : are in the following list. Overloads that appear higher in the list have
67 : higher priority.
68 :
69 : @code
70 : template< class FullContext >
71 : result<T> tag_invoke( try_value_to_tag<T>, const value&, const Context&, const FullContext& );
72 :
73 : template< class FullContext >
74 : T tag_invoke( value_to_tag<T>, const value&, const Context&, const FullContext& );
75 :
76 : result<T> tag_invoke( try_value_to_tag<T>, const value&, const Context& );
77 :
78 : T tag_invoke( value_to_tag<T>, const value&, const Context& );
79 :
80 : result<T> tag_invoke( try_value_to_tag<T>, const value& );
81 :
82 : T tag_invoke( value_to_tag<T>, const value& );
83 : @endcode
84 :
85 : For `tag_invoke` overloads that take a parameter of type `value_to_tag<T>`
86 : the object returned by a call to that overload is returned by the function
87 : as the result of the conversion. For overloads that take a parameter of
88 : type `try_value_to_tag<T>` if the returned `result` contains a value, that
89 : value is returned as the result of the conversion. Otherwise, an exception
90 : of type @ref boost::system::system_error that stores the error is thrown.
91 :
92 : The `ctx` argument can be used either as a tag type to provide conversions
93 : for third-party types, or to pass extra data to the conversion function.
94 :
95 : Overload **(3)** is **deleted** and participates in overload resolution
96 : only when `U` is not @ref value. The overload exists to prevent unintented
97 : creation of temporary @ref value instances, e.g.
98 :
99 : @code
100 : auto flag = value_to<bool>(true);
101 : @endcode
102 :
103 : @par Constraints
104 : @code
105 : ! std::is_reference< T >::value
106 : @endcode
107 :
108 : @par Exception Safety
109 : Strong guarantee.
110 :
111 : @tparam T The type to convert to.
112 :
113 : @tparam Context The type of context passed to the conversion function.
114 :
115 : @returns `jv` converted to `T`.
116 :
117 : @param jv The @ref value to convert.
118 :
119 : @param ctx Context passed to the conversion function.
120 :
121 : @see @ref try_value_to, @ref value_from,
122 : <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1895r0.pdf">
123 : tag_invoke: A general pattern for supporting customisable functions</a>
124 :
125 : @{
126 : */
127 : template< class T, class Context >
128 : T
129 HIT 410 : value_to( value const& jv, Context const& ctx )
130 : {
131 : BOOST_CORE_STATIC_ASSERT( ! std::is_reference<T>::value );
132 : using bare_T = detail::remove_cvref<T>;
133 : using cat = detail::value_to_category<Context, bare_T>;
134 410 : return detail::value_to_impl( cat(), value_to_tag<bare_T>(), jv, ctx );
135 : }
136 :
137 : /// Overload
138 : template<class T>
139 : T
140 131 : value_to(const value& jv)
141 : {
142 192 : return value_to<T>( jv, detail::no_context() );
143 : }
144 :
145 : /// Overload
146 : template<class T, class U
147 : #ifndef BOOST_JSON_DOCS
148 : , class = typename std::enable_if<!std::is_same<U, value>::value>::type
149 : #endif
150 : >
151 : T
152 : value_to(U const& jv) = delete;
153 : /// @}
154 :
155 : /** Convert a @ref value to a @ref boost::system::result.
156 :
157 : This function attempts to convert a @ref value to `result<T>` using
158 :
159 : - one of @ref value's accessors, or
160 : - a library-provided generic conversion, or
161 : - a user-provided overload of `tag_invoke`.
162 :
163 : In order to perform the conversion the function selects an appropriate
164 : implementation based on the types `T` and `Context` (if provided).
165 :
166 : 1. If `Context` is available and is not `std::tuple<C...>`
167 :
168 : a. check if `use_category<T, Context>::value` is not
169 : @ref conversion_category::unknown; otherwise
170 :
171 : b. check if a `tag_invoke` overload from the list below that takes a
172 : `Context const&` exists.
173 :
174 : 2. Otherwise, if `Context` is available, and is `std::tuple<C...>` repeat
175 : steps **1** and **2** recursively for every `C` until either
176 : step **1.a** or **1.b** succeeds for some `C`.
177 :
178 : 3. Failing that,
179 :
180 : a. check if `use_category<T>::value` is not
181 : @ref conversion_category::unknown; otherwise
182 :
183 : b. check if a `tag_invoke` overload from the list below that takes only
184 : 2 parameters exists; otherwise
185 :
186 : c. check if `T` is one of @ref value, @ref array, @ref object,
187 : or @ref string; otherwise
188 :
189 : d. check if `T` matches one of the categories of types described in the
190 : table "Conversion categories" in \<\<Value Conversion>> section.
191 :
192 : These steps determine both the appropriate category of conversion for `T`,
193 : and, if necessary, the effective context `C` that will be used for
194 : conversion. If the category is selected on steps **1.a**, **3.a**, **3.c**,
195 : or **3.d**, the library provides a suitable conversion implementation.
196 : If the category is selected on steps **2.b** or **3.b**, then a
197 : user-provided `tag_invoke` overload is used.
198 :
199 : The overloads of `tag_invoke` that will be considered by this function
200 : are in the following list. Overloads that appear higher in the list have
201 : higher priority.
202 :
203 : @code
204 : template< class FullContext >
205 : result<T> tag_invoke( try_value_to_tag<T>, const value&, const Context&, const FullContext& );
206 :
207 : template< class FullContext >
208 : T tag_invoke( value_to_tag<T>, const value&, const Context&, const FullContext& );
209 :
210 : result<T> tag_invoke( try_value_to_tag<T>, const value&, const Context& );
211 :
212 : T tag_invoke( value_to_tag<T>, const value&, const Context& );
213 :
214 : result<T> tag_invoke( try_value_to_tag<T>, const value& );
215 :
216 : T tag_invoke( value_to_tag<T>, const value& );
217 : @endcode
218 :
219 : For `tag_invoke` overloads that take a parameter of type
220 : `try_value_to_tag<T>` the object returned by a call to that overload is
221 : returned by the function as the result of the conversion. For overloads
222 : that take a parameter of type `value_to_tag<T>` the returned object is
223 : wrapped with a `result<T>`.
224 :
225 : If an error occurs during conversion, the result will store the error code
226 : associated with the error. If an exception is thrown, the function will
227 : attempt to retrieve the associated error code and return it, otherwise it
228 : will return @ref error::exception, unless the exception type is
229 : @ref std::bad_alloc, which will be allowed to propagate.
230 :
231 : The `ctx` argument can be used either as a tag type to provide conversions
232 : for third-party types, or to pass extra data to the conversion function.
233 :
234 : @par Constraints
235 : @code
236 : ! std::is_reference< T >::value
237 : @endcode
238 :
239 : @par Exception Safety
240 : Strong guarantee.
241 :
242 : @tparam T The type to convert to.
243 : @tparam Context The type of context passed to the conversion function.
244 :
245 : @param jv The @ref value to convert.
246 : @param ctx Context passed to the conversion function.
247 :
248 : @returns `jv` converted to `result<T>`.
249 :
250 : @see @ref value_to_tag, @ref value_to, @ref value_from,
251 : [tag_invoke: A general pattern for supporting customisable functions](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1895r0.pdf).
252 :
253 : @{
254 : */
255 : template< class T, class Context >
256 : typename result_for<T, value>::type
257 3763 : try_value_to( value const& jv, Context const& ctx )
258 : {
259 : BOOST_CORE_STATIC_ASSERT( ! std::is_reference<T>::value );
260 : using bare_T = detail::remove_cvref<T>;
261 : using cat = detail::value_to_category<Context, bare_T>;
262 3573 : return detail::value_to_impl(
263 3757 : cat(), try_value_to_tag<bare_T>(), jv, ctx );
264 : }
265 :
266 : /// Overload
267 : template<class T>
268 : typename result_for<T, value>::type
269 130 : try_value_to(const value& jv)
270 : {
271 163 : return try_value_to<T>( jv, detail::no_context() );
272 : }
273 : /// @}
274 :
275 : /** Determine if a @ref value can be converted to `T`.
276 :
277 : If @ref value can be converted to `T` via a
278 : call to @ref value_to, the static data member `value`
279 : is defined as `true`. Otherwise, `value` is
280 : defined as `false`.
281 :
282 : @see @ref value_to
283 : */
284 : #ifdef BOOST_JSON_DOCS
285 : template<class T>
286 : using has_value_to = __see_below__;
287 : #else
288 : template<class T>
289 : using has_value_to = detail::can_convert<
290 : detail::remove_cvref<T>, detail::value_to_conversion>;
291 : #endif
292 :
293 : } // namespace json
294 : } // namespace boost
295 :
296 : #endif
|