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  

14  

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

17  

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

20  

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

22  

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

25  

26  
    @li one of @ref value's accessors, or
26  
    @li one of @ref value's accessors, or
27  
    @li a library-provided generic conversion, or
27  
    @li a library-provided generic conversion, or
28  
    @li a user-provided overload of `tag_invoke`.
28  
    @li a user-provided overload of `tag_invoke`.
29  

29  

30  
    Out of the box the function supports default constructible types satisfying
30  
    Out of the box the function supports default constructible types satisfying
31  
    {req_SequenceContainer}, arrays, arithmetic types, `bool`, `std::tuple`,
31  
    {req_SequenceContainer}, arrays, arithmetic types, `bool`, `std::tuple`,
32  
    `std::pair`, `std::optional`, `std::variant`, `std::nullptr_t`, and structs
32  
    `std::pair`, `std::optional`, `std::variant`, `std::nullptr_t`, and structs
33  
    and enums described using Boost.Describe.
33  
    and enums described using Boost.Describe.
34  

34  

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

37  

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

42  

43  
    or
43  
    or
44  

44  

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

48  

49  
    or
49  
    or
50  

50  

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

54  

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

57  

58  
    The object returned by the function call is returned by @ref value_to as
58  
    The object returned by the function call is returned by @ref value_to as
59  
    the result of the conversion.
59  
    the result of the conversion.
60  

60  

61  
    The `ctx` argument can be used either as a tag type to provide conversions
61  
    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.
62  
    for third-party types, or to pass extra data to the conversion function.
63  

63  

64  
    Overload **(3)** is **deleted** and participates in overload resolution
64  
    Overload **(3)** is **deleted** and participates in overload resolution
65  
    only when `U` is not @ref value. The overload exists to prevent unintented
65  
    only when `U` is not @ref value. The overload exists to prevent unintented
66  
    creation of temporary @ref value instances, e.g.
66  
    creation of temporary @ref value instances, e.g.
67  

67  

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

71  

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

76  

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

79  

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

81  

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

83  

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

85  

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

87  

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

89  

90  
    @see @ref value_to_tag, @ref value_from,
90  
    @see @ref value_to_tag, @ref value_from,
91  
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1895r0.pdf">
91  
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1895r0.pdf">
92  
        tag_invoke: A general pattern for supporting customisable functions</a>
92  
        tag_invoke: A general pattern for supporting customisable functions</a>
93  

93  

94  
    @{
94  
    @{
95  
*/
95  
*/
96  
template< class T, class Context >
96  
template< class T, class Context >
97  
T
97  
T
98  
value_to( value const& jv, Context const& ctx )
98  
value_to( value const& jv, Context const& ctx )
99  
{
99  
{
100  
    BOOST_CORE_STATIC_ASSERT( ! std::is_reference<T>::value );
100  
    BOOST_CORE_STATIC_ASSERT( ! std::is_reference<T>::value );
101  
    using bare_T = detail::remove_cvref<T>;
101  
    using bare_T = detail::remove_cvref<T>;
102  
    BOOST_CORE_STATIC_ASSERT((
102  
    BOOST_CORE_STATIC_ASSERT((
103  
        detail::conversion_round_trips<
103  
        detail::conversion_round_trips<
104  
            Context, bare_T, detail::value_to_conversion>::value));
104  
            Context, bare_T, detail::value_to_conversion>::value));
105  
    using cat = detail::value_to_category<Context, bare_T>;
105  
    using cat = detail::value_to_category<Context, bare_T>;
106  
    return detail::value_to_impl( cat(), value_to_tag<bare_T>(), jv, ctx );
106  
    return detail::value_to_impl( cat(), value_to_tag<bare_T>(), jv, ctx );
107  
}
107  
}
108  

108  

109  
/// Overload
109  
/// Overload
110  
template<class T>
110  
template<class T>
111  
T
111  
T
112  
value_to(const value& jv)
112  
value_to(const value& jv)
113  
{
113  
{
114  
    return value_to<T>( jv, detail::no_context() );
114  
    return value_to<T>( jv, detail::no_context() );
115  
}
115  
}
116  

116  

117  
/// Overload
117  
/// Overload
118  
template<class T, class U
118  
template<class T, class U
119  
#ifndef BOOST_JSON_DOCS
119  
#ifndef BOOST_JSON_DOCS
120  
    , class = typename std::enable_if<!std::is_same<U, value>::value>::type
120  
    , class = typename std::enable_if<!std::is_same<U, value>::value>::type
121  
#endif
121  
#endif
122  
>
122  
>
123  
T
123  
T
124  
value_to(U const& jv) = delete;
124  
value_to(U const& jv) = delete;
125  
/// @}
125  
/// @}
126  

126  

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

128  

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

130  

131  
    @li one of @ref value's accessors, or
131  
    @li one of @ref value's accessors, or
132  
    @li a library-provided generic conversion, or
132  
    @li a library-provided generic conversion, or
133  
    @li a user-provided overload of `tag_invoke`.
133  
    @li a user-provided overload of `tag_invoke`.
134  

134  

135  
    Out of the box the function supports default constructible types satisfying
135  
    Out of the box the function supports default constructible types satisfying
136  
    {req_SequenceContainer}, arrays, arithmetic types, `bool`, `std::tuple`,
136  
    {req_SequenceContainer}, arrays, arithmetic types, `bool`, `std::tuple`,
137  
    `std::pair`, `std::optional`, `std::variant`, `std::nullptr_t`, and structs
137  
    `std::pair`, `std::optional`, `std::variant`, `std::nullptr_t`, and structs
138  
    and enums described using Boost.Describe.
138  
    and enums described using Boost.Describe.
139  

139  

140  
    Conversion of other types is done by calling an overload of `tag_invoke`
140  
    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:
141  
    found by argument-dependent lookup. Its signature should be similar to:
142  

142  

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

147  

148  
    or
148  
    or
149  

149  

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

153  

154  
    or
154  
    or
155  

155  

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

159  

160  
    The overloads are checked for existence in that order and the first that
160  
    The overloads are checked for existence in that order and the first that
161  
    matches will be selected.
161  
    matches will be selected.
162  

162  

163  
    If an error occurs during conversion, the result will store the error code
163  
    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
164  
    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
165  
    attempt to retrieve the associated error code and return it, otherwise it
166  
    will return `error::exception`, unless the exception type is
166  
    will return `error::exception`, unless the exception type is
167  
    @ref std::bad_alloc, which will be allowed to propagate.
167  
    @ref std::bad_alloc, which will be allowed to propagate.
168  

168  

169  
    The `ctx` argument can be used either as a tag type to provide conversions
169  
    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.
170  
    for third-party types, or to pass extra data to the conversion function.
171  

171  

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

176  

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

179  

180  
    @tparam T The type to convert to.
180  
    @tparam T The type to convert to.
181  
    @tparam Context The type of context passed to the conversion function.
181  
    @tparam Context The type of context passed to the conversion function.
182  

182  

183  
    @param jv The @ref value to convert.
183  
    @param jv The @ref value to convert.
184  
    @param ctx Context passed to the conversion function.
184  
    @param ctx Context passed to the conversion function.
185  

185  

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

187  

188  
    @see @ref value_to_tag, @ref value_to, @ref value_from,
188  
    @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).
189  
         [tag_invoke: A general pattern for supporting customisable functions](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1895r0.pdf).
190  

190  

191  
    @{
191  
    @{
192  
*/
192  
*/
193  
template< class T, class Context >
193  
template< class T, class Context >
194  
typename result_for<T, value>::type
194  
typename result_for<T, value>::type
195  
try_value_to( value const& jv, Context const& ctx )
195  
try_value_to( value const& jv, Context const& ctx )
196  
{
196  
{
197  
    BOOST_CORE_STATIC_ASSERT( ! std::is_reference<T>::value );
197  
    BOOST_CORE_STATIC_ASSERT( ! std::is_reference<T>::value );
198  
    using bare_T = detail::remove_cvref<T>;
198  
    using bare_T = detail::remove_cvref<T>;
199  
    BOOST_CORE_STATIC_ASSERT((
199  
    BOOST_CORE_STATIC_ASSERT((
200  
        detail::conversion_round_trips<
200  
        detail::conversion_round_trips<
201  
            Context, bare_T, detail::value_to_conversion>::value));
201  
            Context, bare_T, detail::value_to_conversion>::value));
202  
    using cat = detail::value_to_category<Context, bare_T>;
202  
    using cat = detail::value_to_category<Context, bare_T>;
203  
    return detail::value_to_impl(
203  
    return detail::value_to_impl(
204  
        cat(), try_value_to_tag<bare_T>(), jv, ctx );
204  
        cat(), try_value_to_tag<bare_T>(), jv, ctx );
205  
}
205  
}
206  

206  

207  
/// Overload
207  
/// Overload
208  
template<class T>
208  
template<class T>
209  
typename result_for<T, value>::type
209  
typename result_for<T, value>::type
210  
try_value_to(const value& jv)
210  
try_value_to(const value& jv)
211  
{
211  
{
212  
    return try_value_to<T>( jv, detail::no_context() );
212  
    return try_value_to<T>( jv, detail::no_context() );
213  
}
213  
}
214  
/// @}
214  
/// @}
215  

215  

216  
/** Determine if a @ref value can be converted to `T`.
216  
/** Determine if a @ref value can be converted to `T`.
217  

217  

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

222  

223  
    @see @ref value_to
223  
    @see @ref value_to
224  
*/
224  
*/
225  
#ifdef BOOST_JSON_DOCS
225  
#ifdef BOOST_JSON_DOCS
226  
template<class T>
226  
template<class T>
227  
using has_value_to = __see_below__;
227  
using has_value_to = __see_below__;
228  
#else
228  
#else
229  
template<class T>
229  
template<class T>
230  
using has_value_to = detail::can_convert<
230  
using has_value_to = detail::can_convert<
231  
    detail::remove_cvref<T>, detail::value_to_conversion>;
231  
    detail::remove_cvref<T>, detail::value_to_conversion>;
232  
#endif
232  
#endif
233  

233  

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

236  

237  
#endif
237  
#endif