1  
//
1  
//
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3  
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
3  
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
4  
// Copyright (c) 2022 Dmitry Arkhipov (grisumbras@gmail.com)
4  
// Copyright (c) 2022 Dmitry Arkhipov (grisumbras@gmail.com)
5  
//
5  
//
6  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
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)
7  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8  
//
8  
//
9  
// Official repository: https://github.com/boostorg/json
9  
// Official repository: https://github.com/boostorg/json
10  
//
10  
//
11  

11  

12  
#ifndef BOOST_JSON_VALUE_TO_HPP
12  
#ifndef BOOST_JSON_VALUE_TO_HPP
13  
#define BOOST_JSON_VALUE_TO_HPP
13  
#define BOOST_JSON_VALUE_TO_HPP
14 -
#include <boost/core/detail/static_assert.hpp>
 
15  

14  

16  
#include <boost/json/detail/value_to.hpp>
15  
#include <boost/json/detail/value_to.hpp>
17  

16  

18  
namespace boost {
17  
namespace boost {
19  
namespace json {
18  
namespace json {
20  

19  

21  
/** Convert a @ref value to an object of type `T`.
20  
/** Convert a @ref value to an object of type `T`.
22  

21  

23  
    This function attempts to convert a @ref value
22  
    This function attempts to convert a @ref value
24  
    to `T` using
23  
    to `T` using
25  

24  

26  
    @li one of @ref value's accessors, or
25  
    @li one of @ref value's accessors, or
 
26 +

27  
    @li a library-provided generic conversion, or
27  
    @li a library-provided generic conversion, or
 
28 +

28  
    @li a user-provided overload of `tag_invoke`.
29  
    @li a user-provided overload of `tag_invoke`.
29  

30  

30 -
    Out of the box the function supports default constructible types satisfying
31 +
    Out of the box the function supports types satisfying
31 -
    {req_SequenceContainer}, arrays, arithmetic types, `bool`, `std::tuple`,
32 +
    <a href="https://en.cppreference.com/w/cpp/named_req/SequenceContainer"><em>SequenceContainer</em></a>,
32 -
    `std::pair`, `std::optional`, `std::variant`, `std::nullptr_t`, and structs
33 +
    arrays, arithmetic types, `bool`, `std::tuple`, `std::pair`,
33 -
    and enums described using Boost.Describe.
34 +
    `std::variant`, `std::optional`, `std::monostate`, and `std::nullopt_t`.
34  

35  

35  
    Conversion of other types is done by calling an overload of `tag_invoke`
36  
    Conversion of other types is done by calling an overload of `tag_invoke`
36  
    found by argument-dependent lookup. Its signature should be similar to:
37  
    found by argument-dependent lookup. Its signature should be similar to:
37  

38  

38  
    @code
39  
    @code
39  
    template< class FullContext >
40  
    template< class FullContext >
40  
    T tag_invoke( value_to_tag<T>, const value&, const Context& , const FullContext& );
41  
    T tag_invoke( value_to_tag<T>, const value&, const Context& , const FullContext& );
41  
    @endcode
42  
    @endcode
42  

43  

43  
    or
44  
    or
44  

45  

45  
    @code
46  
    @code
46  
    T tag_invoke( value_to_tag<T>, const value&, const Context& );
47  
    T tag_invoke( value_to_tag<T>, const value&, const Context& );
47  
    @endcode
48  
    @endcode
48  

49  

49  
    or
50  
    or
50  

51  

51  
    @code
52  
    @code
52  
    result<T> tag_invoke( value_to_tag<T>, const value& );
53  
    result<T> tag_invoke( value_to_tag<T>, const value& );
53  
    @endcode
54  
    @endcode
54  

55  

55  
    The overloads are checked for existence in that order and the first that
56  
    The overloads are checked for existence in that order and the first that
56 -
    matches will be selected.
57 +
    matches will be selected. <br>
57  

58  

58  
    The object returned by the function call is returned by @ref value_to as
59  
    The object returned by the function call is returned by @ref value_to as
59 -
    the result of the conversion.
60 +
    the result of the conversion. <br>
60  

61  

61  
    The `ctx` argument can be used either as a tag type to provide conversions
62  
    The `ctx` argument can be used either as a tag type to provide conversions
62  
    for third-party types, or to pass extra data to the conversion function.
63  
    for third-party types, or to pass extra data to the conversion function.
63 -
    Overload **(3)** is **deleted** and participates in overload resolution
 
64 -
    only when `U` is not @ref value. The overload exists to prevent unintented
 
65 -
    creation of temporary @ref value instances, e.g.
 
66 -

 
67 -
    @code
 
68 -
    auto flag = value_to<bool>(true);
 
69 -
    @endcode
 
70 -

 
71  

64  

72  
    @par Constraints
65  
    @par Constraints
73  
    @code
66  
    @code
74  
    ! std::is_reference< T >::value
67  
    ! std::is_reference< T >::value
75  
    @endcode
68  
    @endcode
76  

69  

77  
    @par Exception Safety
70  
    @par Exception Safety
78  
    Strong guarantee.
71  
    Strong guarantee.
79  

72  

80  
    @tparam T The type to convert to.
73  
    @tparam T The type to convert to.
81  

74  

82  
    @tparam Context The type of context passed to the conversion function.
75  
    @tparam Context The type of context passed to the conversion function.
83  

76  

84  
    @returns `jv` converted to `result<T>`.
77  
    @returns `jv` converted to `result<T>`.
85  

78  

86  
    @param jv The @ref value to convert.
79  
    @param jv The @ref value to convert.
87  

80  

88  
    @param ctx Context passed to the conversion function.
81  
    @param ctx Context passed to the conversion function.
89  

82  

90  
    @see @ref value_to_tag, @ref value_from,
83  
    @see @ref value_to_tag, @ref value_from,
91  
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1895r0.pdf">
84  
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1895r0.pdf">
92 -

 
93 -
    @{
 
94  
        tag_invoke: A general pattern for supporting customisable functions</a>
85  
        tag_invoke: A general pattern for supporting customisable functions</a>
95  
*/
86  
*/
96  
template< class T, class Context >
87  
template< class T, class Context >
97  
T
88  
T
98  
value_to( value const& jv, Context const& ctx )
89  
value_to( value const& jv, Context const& ctx )
99  
{
90  
{
100 -
    BOOST_CORE_STATIC_ASSERT( ! std::is_reference<T>::value );
91 +
    BOOST_STATIC_ASSERT(! std::is_reference<T>::value);
 
92 +

 
93 +
    using Attrs = detail::value_to_attrs<Context, T>;
 
94 +
    using Rep = typename Attrs::representation;
 
95 +
    BOOST_STATIC_ASSERT(detail::conversion_round_trips<
 
96 +
        Context, Rep, detail::value_to_conversion>::value);
 
97 +

101  
    using bare_T = detail::remove_cvref<T>;
98  
    using bare_T = detail::remove_cvref<T>;
102 -
    BOOST_CORE_STATIC_ASSERT((
99 +
    return static_cast<bare_T>(detail::value_to_impl(
103 -
        detail::conversion_round_trips<
100 +
        typename Attrs::category(), value_to_tag<Rep>(), jv, ctx ));
104 -
            Context, bare_T, detail::value_to_conversion>::value));
 
105 -
    using cat = detail::value_to_category<Context, bare_T>;
 
106 -
    return detail::value_to_impl( cat(), value_to_tag<bare_T>(), jv, ctx );
 
107  
}
101  
}
108  

102  

109 -
/// Overload
103 +
/** Convert a @ref value to an object of type `T`.
 
104 +

 
105 +
    This function attempts to convert a @ref value
 
106 +
    to `T` using
 
107 +

 
108 +
    @li one of @ref value's accessors, or
 
109 +

 
110 +
    @li a library-provided generic conversion, or
 
111 +

 
112 +
    @li a user-provided overload of `tag_invoke`.
 
113 +

 
114 +
    Out of the box the function supports types satisfying
 
115 +
    <a href="https://en.cppreference.com/w/cpp/named_req/SequenceContainer"><em>SequenceContainer</em></a>,
 
116 +
    arrays, arithmetic types, `bool`, `std::tuple`, `std::pair`,
 
117 +
    `std::variant`, `std::optional`, `std::monostate`, and `std::nullopt_t`.
 
118 +

 
119 +
    Conversion of other types is done by calling an overload of `tag_invoke`
 
120 +
    found by argument-dependent lookup. Its signature should be similar to:
 
121 +

 
122 +
    @code
 
123 +
    T tag_invoke( value_to_tag<T>, const value& );
 
124 +
    @endcode
 
125 +

 
126 +
    The object returned by the function call is
 
127 +
    returned by @ref value_to as the result of the
 
128 +
    conversion.
 
129 +

 
130 +
    @par Constraints
 
131 +
    @code
 
132 +
    ! std::is_reference< T >::value
 
133 +
    @endcode
 
134 +

 
135 +
    @par Exception Safety
 
136 +
    Strong guarantee.
 
137 +

 
138 +
    @tparam T The type to convert to.
 
139 +

 
140 +
    @returns `jv` converted to `T`.
 
141 +

 
142 +
    @param jv The @ref value to convert.
 
143 +

 
144 +
    @see @ref value_to_tag, @ref value_from,
 
145 +
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1895r0.pdf">
 
146 +
        tag_invoke: A general pattern for supporting customisable functions</a>
 
147 +
*/
110  
template<class T>
148  
template<class T>
111  
T
149  
T
112  
value_to(const value& jv)
150  
value_to(const value& jv)
113  
{
151  
{
114  
    return value_to<T>( jv, detail::no_context() );
152  
    return value_to<T>( jv, detail::no_context() );
115  
}
153  
}
116  

154  

117 -
/// Overload
155 +
/** Convert a @ref value to a `boost::system::result<T>`.
118 -
template<class T, class U
 
119 -
#ifndef BOOST_JSON_DOCS
 
120 -
    , class = typename std::enable_if<!std::is_same<U, value>::value>::type
 
121 -
#endif
 
122 -
>
 
123 -
T
 
124 -
value_to(U const& jv) = delete;
 
125 -
/// @}
 
126 -

 
127 -
/** Convert a @ref value to a @ref boost::system::result.
 
128  

156  

129 -
    This function attempts to convert a @ref value to `result<T>` using
157 +
    This function attempts to convert a @ref value
 
158 +
    to `result<T>` using
130  

159  

131  
    @li one of @ref value's accessors, or
160  
    @li one of @ref value's accessors, or
 
161 +

132  
    @li a library-provided generic conversion, or
162  
    @li a library-provided generic conversion, or
 
163 +

133  
    @li a user-provided overload of `tag_invoke`.
164  
    @li a user-provided overload of `tag_invoke`.
134  

165  

135 -
    Out of the box the function supports default constructible types satisfying
166 +
    Out of the box the function supports types satisfying
136 -
    {req_SequenceContainer}, arrays, arithmetic types, `bool`, `std::tuple`,
167 +
    <a href="https://en.cppreference.com/w/cpp/named_req/SequenceContainer"><em>SequenceContainer</em></a>,
137 -
    `std::pair`, `std::optional`, `std::variant`, `std::nullptr_t`, and structs
168 +
    arrays, arithmetic types, `bool`, `std::tuple`, `std::pair`,
138 -
    and enums described using Boost.Describe.
169 +
    `std::variant`, `std::optional`, `std::monostate`, and `std::nullopt_t`.
139  

170  

140  
    Conversion of other types is done by calling an overload of `tag_invoke`
171  
    Conversion of other types is done by calling an overload of `tag_invoke`
141  
    found by argument-dependent lookup. Its signature should be similar to:
172  
    found by argument-dependent lookup. Its signature should be similar to:
142  

173  

143  
    @code
174  
    @code
144  
    template< class FullContext >
175  
    template< class FullContext >
145  
    result<T> tag_invoke( try_value_to_tag<T>, const value&, const Context& , const FullContext& );
176  
    result<T> tag_invoke( try_value_to_tag<T>, const value&, const Context& , const FullContext& );
146  
    @endcode
177  
    @endcode
147  

178  

148  
    or
179  
    or
149  

180  

150  
    @code
181  
    @code
151  
    result<T> tag_invoke( try_value_to_tag<T>, const value&, const Context& );
182  
    result<T> tag_invoke( try_value_to_tag<T>, const value&, const Context& );
152  
    @endcode
183  
    @endcode
153  

184  

154  
    or
185  
    or
155  

186  

156  
    @code
187  
    @code
157  
    result<T> tag_invoke( try_value_to_tag<T>, const value& );
188  
    result<T> tag_invoke( try_value_to_tag<T>, const value& );
158  
    @endcode
189  
    @endcode
159  

190  

160  
    The overloads are checked for existence in that order and the first that
191  
    The overloads are checked for existence in that order and the first that
161 -
    matches will be selected.
192 +
    matches will be selected. <br>
162  

193  

163  
    If an error occurs during conversion, the result will store the error code
194  
    If an error occurs during conversion, the result will store the error code
164  
    associated with the error. If an exception is thrown, the function will
195  
    associated with the error. If an exception is thrown, the function will
165  
    attempt to retrieve the associated error code and return it, otherwise it
196  
    attempt to retrieve the associated error code and return it, otherwise it
166  
    will return `error::exception`, unless the exception type is
197  
    will return `error::exception`, unless the exception type is
167 -
    @ref std::bad_alloc, which will be allowed to propagate.
198 +
    `std::bad_alloc`, which will be allowed to propagate. <br>
168  

199  

169  
    The `ctx` argument can be used either as a tag type to provide conversions
200  
    The `ctx` argument can be used either as a tag type to provide conversions
170  
    for third-party types, or to pass extra data to the conversion function.
201  
    for third-party types, or to pass extra data to the conversion function.
171  

202  

172  
    @par Constraints
203  
    @par Constraints
173  
    @code
204  
    @code
174  
    ! std::is_reference< T >::value
205  
    ! std::is_reference< T >::value
175  
    @endcode
206  
    @endcode
176  

207  

177  
    @par Exception Safety
208  
    @par Exception Safety
178  
    Strong guarantee.
209  
    Strong guarantee.
179  

210  

180  
    @tparam T The type to convert to.
211  
    @tparam T The type to convert to.
 
212 +

181  
    @tparam Context The type of context passed to the conversion function.
213  
    @tparam Context The type of context passed to the conversion function.
182  

214  

183  
    @param jv The @ref value to convert.
215  
    @param jv The @ref value to convert.
 
216 +

184  
    @param ctx Context passed to the conversion function.
217  
    @param ctx Context passed to the conversion function.
185  

218  

186  
    @returns `jv` converted to `result<T>`.
219  
    @returns `jv` converted to `result<T>`.
187  

220  

188  
    @see @ref value_to_tag, @ref value_to, @ref value_from,
221  
    @see @ref value_to_tag, @ref value_to, @ref value_from,
189 -
         [tag_invoke: A general pattern for supporting customisable functions](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1895r0.pdf).
222 +
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1895r0.pdf">
190 -

223 +
        tag_invoke: A general pattern for supporting customisable functions</a>
191 -
    @{
 
192  
*/
224  
*/
193  
template< class T, class Context >
225  
template< class T, class Context >
194  
typename result_for<T, value>::type
226  
typename result_for<T, value>::type
195  
try_value_to( value const& jv, Context const& ctx )
227  
try_value_to( value const& jv, Context const& ctx )
196  
{
228  
{
197 -
    BOOST_CORE_STATIC_ASSERT( ! std::is_reference<T>::value );
229 +
    BOOST_STATIC_ASSERT(! std::is_reference<T>::value);
 
230 +

 
231 +
    using Attrs = detail::value_to_attrs<Context, T>;
 
232 +
    using Rep = typename Attrs::representation;
 
233 +
    BOOST_STATIC_ASSERT(detail::conversion_round_trips<
 
234 +
        Context, Rep, detail::value_to_conversion>::value);
 
235 +

198 -
    BOOST_CORE_STATIC_ASSERT((
 
199 -
        detail::conversion_round_trips<
 
200 -
            Context, bare_T, detail::value_to_conversion>::value));
 
201 -
    using cat = detail::value_to_category<Context, bare_T>;
 
202  
    using bare_T = detail::remove_cvref<T>;
236  
    using bare_T = detail::remove_cvref<T>;
203  
    return detail::value_to_impl(
237  
    return detail::value_to_impl(
204 -
        cat(), try_value_to_tag<bare_T>(), jv, ctx );
238 +
        typename Attrs::category(), try_value_to_tag<Rep>(), jv, ctx )
 
239 +
        & [](Rep&& rep) { return static_cast<bare_T>(rep); };
205  
}
240  
}
206  

241  

207 -
/// Overload
242 +
/** Convert a @ref value to a `boost::system::result<T>`.
 
243 +

 
244 +
    This function attempts to convert a @ref value
 
245 +
    to `result<T>` using
 
246 +

 
247 +
    @li one of @ref value's accessors, or
 
248 +

 
249 +
    @li a library-provided generic conversion, or
 
250 +

 
251 +
    @li a user-provided overload of `tag_invoke`.
 
252 +

 
253 +
    Out of the box the function supports types satisfying
 
254 +
    <a href="https://en.cppreference.com/w/cpp/named_req/SequenceContainer"><em>SequenceContainer</em></a>,
 
255 +
    arrays, arithmetic types, `bool`, `std::tuple`, `std::pair`,
 
256 +
    `std::variant`, `std::optional`, `std::monostate`, and `std::nullopt_t`.
 
257 +

 
258 +
    Conversion of other types is done by calling an overload of `tag_invoke`
 
259 +
    found by argument-dependent lookup. Its signature should be similar to:
 
260 +

 
261 +
    @code
 
262 +
    result<T> tag_invoke( try_value_to_tag<T>, const value& );
 
263 +
    @endcode
 
264 +

 
265 +
    If an error occurs during conversion, the result will store the error code
 
266 +
    associated with the error. If an exception is thrown, the function will
 
267 +
    attempt to retrieve the associated error code and return it, otherwise it
 
268 +
    will return `error::exception`, unless the exception type is
 
269 +
    `std::bad_alloc`, which will be allowed to propagate.
 
270 +

 
271 +
    @par Constraints
 
272 +
    @code
 
273 +
    ! std::is_reference< T >::value
 
274 +
    @endcode
 
275 +

 
276 +
    @par Exception Safety
 
277 +
    Strong guarantee.
 
278 +

 
279 +
    @tparam T The type to convert to.
 
280 +

 
281 +
    @param jv The @ref value to convert.
 
282 +

 
283 +
    @returns `jv` converted to `result<T>`.
 
284 +

 
285 +
    @see @ref value_to_tag, @ref value_to, @ref value_from,
 
286 +
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1895r0.pdf">
 
287 +
        tag_invoke: A general pattern for supporting customisable functions</a>
 
288 +
*/
208  
template<class T>
289  
template<class T>
209  
typename result_for<T, value>::type
290  
typename result_for<T, value>::type
210  
try_value_to(const value& jv)
291  
try_value_to(const value& jv)
211  
{
292  
{
212  
    return try_value_to<T>( jv, detail::no_context() );
293  
    return try_value_to<T>( jv, detail::no_context() );
213 -
/// @}
 
214  
}
294  
}
215  

295  

216 -
/** Determine if a @ref value can be converted to `T`.
296 +
/** Convert a @ref value to an object of type `T`.
 
297 +

 
298 +
    This overload is **deleted** and participates in overload resolution only
 
299 +
    when `U` is not @ref value. The overload exists to prevent unintented
 
300 +
    creation of temporary @ref value instances, e.g.
 
301 +

 
302 +
    @code
 
303 +
    auto flag = value_to<bool>(true);
 
304 +
    @endcode
 
305 +
*/
 
306 +
template<class T, class U
 
307 +
#ifndef BOOST_JSON_DOCS
 
308 +
    , class = typename std::enable_if<!std::is_same<U, value>::value>::type
 
309 +
#endif
 
310 +
>
 
311 +
T
 
312 +
value_to(U const& jv) = delete;
 
313 +

 
314 +
/** Determine a @ref value can be converted to `T`.
217  

315  

218  
    If @ref value can be converted to `T` via a
316  
    If @ref value can be converted to `T` via a
219  
    call to @ref value_to, the static data member `value`
317  
    call to @ref value_to, the static data member `value`
220  
    is defined as `true`. Otherwise, `value` is
318  
    is defined as `true`. Otherwise, `value` is
221  
    defined as `false`.
319  
    defined as `false`.
222  

320  

223  
    @see @ref value_to
321  
    @see @ref value_to
224  
*/
322  
*/
225  
#ifdef BOOST_JSON_DOCS
323  
#ifdef BOOST_JSON_DOCS
226  
template<class T>
324  
template<class T>
227  
using has_value_to = __see_below__;
325  
using has_value_to = __see_below__;
228  
#else
326  
#else
229  
template<class T>
327  
template<class T>
230  
using has_value_to = detail::can_convert<
328  
using has_value_to = detail::can_convert<
231  
    detail::remove_cvref<T>, detail::value_to_conversion>;
329  
    detail::remove_cvref<T>, detail::value_to_conversion>;
232  
#endif
330  
#endif
233  

331  

234  
} // namespace json
332  
} // namespace json
235  
} // namespace boost
333  
} // namespace boost
236  

334  

237  
#endif
335  
#endif