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) 2021 Dmitry Arkhipov (grisumbras@gmail.com)
4  
// Copyright (c) 2021 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_DETAIL_VALUE_TO_HPP
12  
#ifndef BOOST_JSON_DETAIL_VALUE_TO_HPP
13  
#define BOOST_JSON_DETAIL_VALUE_TO_HPP
13  
#define BOOST_JSON_DETAIL_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/value.hpp>
16  
#include <boost/json/value.hpp>
17  
#include <boost/json/conversion.hpp>
17  
#include <boost/json/conversion.hpp>
18  
#include <boost/json/result_for.hpp>
18  
#include <boost/json/result_for.hpp>
19  
#include <boost/describe/enum_from_string.hpp>
19  
#include <boost/describe/enum_from_string.hpp>
20  

20  

21  
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
21  
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
22  
# include <optional>
22  
# include <optional>
23  
#endif
23  
#endif
24  

24  

25  
namespace boost {
25  
namespace boost {
26  
namespace json {
26  
namespace json {
27  

27  

28  
namespace detail {
28  
namespace detail {
29  

29  

30  
template<class T>
30  
template<class T>
31  
using has_reserve_member_helper = decltype(std::declval<T&>().reserve(0));
31  
using has_reserve_member_helper = decltype(std::declval<T&>().reserve(0));
32  
template<class T>
32  
template<class T>
33  
using has_reserve_member = mp11::mp_valid<has_reserve_member_helper, T>;
33  
using has_reserve_member = mp11::mp_valid<has_reserve_member_helper, T>;
34  
template<class T>
34  
template<class T>
35  
using reserve_implementation = mp11::mp_cond<
35  
using reserve_implementation = mp11::mp_cond<
36  
    is_tuple_like<T>,      mp11::mp_int<2>,
36  
    is_tuple_like<T>,      mp11::mp_int<2>,
37  
    has_reserve_member<T>, mp11::mp_int<1>,
37  
    has_reserve_member<T>, mp11::mp_int<1>,
38  
    mp11::mp_true,         mp11::mp_int<0>>;
38  
    mp11::mp_true,         mp11::mp_int<0>>;
39  

39  

40  
template<class T>
40  
template<class T>
41  
error
41  
error
42  
try_reserve(
42  
try_reserve(
43  
    T&,
43  
    T&,
44  
    std::size_t size,
44  
    std::size_t size,
45  
    mp11::mp_int<2>)
45  
    mp11::mp_int<2>)
46  
{
46  
{
47  
    constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
47  
    constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
48  
    if ( N != size )
48  
    if ( N != size )
49  
        return error::size_mismatch;
49  
        return error::size_mismatch;
50  
    return error();
50  
    return error();
51  
}
51  
}
52  

52  

53  
template<typename T>
53  
template<typename T>
54  
error
54  
error
55  
try_reserve(
55  
try_reserve(
56  
    T& cont,
56  
    T& cont,
57  
    std::size_t size,
57  
    std::size_t size,
58  
    mp11::mp_int<1>)
58  
    mp11::mp_int<1>)
59  
{
59  
{
60  
    cont.reserve(size);
60  
    cont.reserve(size);
61  
    return error();
61  
    return error();
62  
}
62  
}
63  

63  

64  
template<typename T>
64  
template<typename T>
65  
error
65  
error
66  
try_reserve(
66  
try_reserve(
67  
    T&,
67  
    T&,
68  
    std::size_t,
68  
    std::size_t,
69  
    mp11::mp_int<0>)
69  
    mp11::mp_int<0>)
70  
{
70  
{
71  
    return error();
71  
    return error();
72  
}
72  
}
73  

73  

74  

74  

75  
// identity conversion
75  
// identity conversion
76  
template< class Ctx >
76  
template< class Ctx >
77  
system::result<value>
77  
system::result<value>
78  
value_to_impl(
78  
value_to_impl(
79  
    value_conversion_tag,
79  
    value_conversion_tag,
80  
    try_value_to_tag<value>,
80  
    try_value_to_tag<value>,
81  
    value const& jv,
81  
    value const& jv,
82  
    Ctx const& )
82  
    Ctx const& )
83  
{
83  
{
84  
    return jv;
84  
    return jv;
85  
}
85  
}
86  

86  

87  
template< class Ctx >
87  
template< class Ctx >
88  
value
88  
value
89  
value_to_impl(
89  
value_to_impl(
90  
    value_conversion_tag, value_to_tag<value>, value const& jv, Ctx const& )
90  
    value_conversion_tag, value_to_tag<value>, value const& jv, Ctx const& )
91  
{
91  
{
92  
    return jv;
92  
    return jv;
93  
}
93  
}
94  

94  

95  
// object
95  
// object
96  
template< class Ctx >
96  
template< class Ctx >
97  
system::result<object>
97  
system::result<object>
98  
value_to_impl(
98  
value_to_impl(
99  
    object_conversion_tag,
99  
    object_conversion_tag,
100  
    try_value_to_tag<object>,
100  
    try_value_to_tag<object>,
101  
    value const& jv,
101  
    value const& jv,
102  
    Ctx const& )
102  
    Ctx const& )
103  
{
103  
{
104  
    object const* obj = jv.if_object();
104  
    object const* obj = jv.if_object();
105  
    if( obj )
105  
    if( obj )
106  
        return *obj;
106  
        return *obj;
107  
    system::error_code ec;
107  
    system::error_code ec;
108  
    BOOST_JSON_FAIL(ec, error::not_object);
108  
    BOOST_JSON_FAIL(ec, error::not_object);
109  
    return ec;
109  
    return ec;
110  
}
110  
}
111  

111  

112  
// array
112  
// array
113  
template< class Ctx >
113  
template< class Ctx >
114  
system::result<array>
114  
system::result<array>
115  
value_to_impl(
115  
value_to_impl(
116  
    array_conversion_tag,
116  
    array_conversion_tag,
117  
    try_value_to_tag<array>,
117  
    try_value_to_tag<array>,
118  
    value const& jv,
118  
    value const& jv,
119  
    Ctx const& )
119  
    Ctx const& )
120  
{
120  
{
121  
    array const* arr = jv.if_array();
121  
    array const* arr = jv.if_array();
122  
    if( arr )
122  
    if( arr )
123  
        return *arr;
123  
        return *arr;
124  
    system::error_code ec;
124  
    system::error_code ec;
125  
    BOOST_JSON_FAIL(ec, error::not_array);
125  
    BOOST_JSON_FAIL(ec, error::not_array);
126  
    return ec;
126  
    return ec;
127  
}
127  
}
128  

128  

129  
// string
129  
// string
130  
template< class Ctx >
130  
template< class Ctx >
131  
system::result<string>
131  
system::result<string>
132  
value_to_impl(
132  
value_to_impl(
133  
    string_conversion_tag,
133  
    string_conversion_tag,
134  
    try_value_to_tag<string>,
134  
    try_value_to_tag<string>,
135  
    value const& jv,
135  
    value const& jv,
136  
    Ctx const& )
136  
    Ctx const& )
137  
{
137  
{
138  
    string const* str = jv.if_string();
138  
    string const* str = jv.if_string();
139  
    if( str )
139  
    if( str )
140  
        return *str;
140  
        return *str;
141  
    system::error_code ec;
141  
    system::error_code ec;
142  
    BOOST_JSON_FAIL(ec, error::not_string);
142  
    BOOST_JSON_FAIL(ec, error::not_string);
143  
    return ec;
143  
    return ec;
144  
}
144  
}
145  

145  

146  
// bool
146  
// bool
147  
template< class Ctx >
147  
template< class Ctx >
148  
system::result<bool>
148  
system::result<bool>
149  
value_to_impl(
149  
value_to_impl(
150  
    bool_conversion_tag, try_value_to_tag<bool>, value const& jv, Ctx const& )
150  
    bool_conversion_tag, try_value_to_tag<bool>, value const& jv, Ctx const& )
151  
{
151  
{
152  
    auto b = jv.if_bool();
152  
    auto b = jv.if_bool();
153  
    if( b )
153  
    if( b )
154  
        return *b;
154  
        return *b;
155  
    system::error_code ec;
155  
    system::error_code ec;
156  
    BOOST_JSON_FAIL(ec, error::not_bool);
156  
    BOOST_JSON_FAIL(ec, error::not_bool);
157  
    return {boost::system::in_place_error, ec};
157  
    return {boost::system::in_place_error, ec};
158  
}
158  
}
159  

159  

160  
// integral and floating point
160  
// integral and floating point
161  
template< class T, class Ctx >
161  
template< class T, class Ctx >
162  
system::result<T>
162  
system::result<T>
163  
value_to_impl(
163  
value_to_impl(
164  
    number_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
164  
    number_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
165  
{
165  
{
166  
    system::error_code ec;
166  
    system::error_code ec;
167  
    auto const n = jv.to_number<T>(ec);
167  
    auto const n = jv.to_number<T>(ec);
168  
    if( ec.failed() )
168  
    if( ec.failed() )
169  
        return {boost::system::in_place_error, ec};
169  
        return {boost::system::in_place_error, ec};
170  
    return {boost::system::in_place_value, n};
170  
    return {boost::system::in_place_value, n};
171  
}
171  
}
172  

172  

173  
// null-like conversion
173  
// null-like conversion
174  
template< class T, class Ctx >
174  
template< class T, class Ctx >
175  
system::result<T>
175  
system::result<T>
176  
value_to_impl(
176  
value_to_impl(
177  
    null_like_conversion_tag,
177  
    null_like_conversion_tag,
178  
    try_value_to_tag<T>,
178  
    try_value_to_tag<T>,
179  
    value const& jv,
179  
    value const& jv,
180  
    Ctx const& )
180  
    Ctx const& )
181  
{
181  
{
182  
    if( jv.is_null() )
182  
    if( jv.is_null() )
183  
        return {boost::system::in_place_value, T{}};
183  
        return {boost::system::in_place_value, T{}};
184  
    system::error_code ec;
184  
    system::error_code ec;
185  
    BOOST_JSON_FAIL(ec, error::not_null);
185  
    BOOST_JSON_FAIL(ec, error::not_null);
186  
    return {boost::system::in_place_error, ec};
186  
    return {boost::system::in_place_error, ec};
187  
}
187  
}
188  

188  

189  
// string-like types
189  
// string-like types
190  
template< class T, class Ctx >
190  
template< class T, class Ctx >
191  
system::result<T>
191  
system::result<T>
192  
value_to_impl(
192  
value_to_impl(
193  
    string_like_conversion_tag,
193  
    string_like_conversion_tag,
194  
    try_value_to_tag<T>,
194  
    try_value_to_tag<T>,
195  
    value const& jv,
195  
    value const& jv,
196  
    Ctx const& )
196  
    Ctx const& )
197  
{
197  
{
198  
    auto str = jv.if_string();
198  
    auto str = jv.if_string();
199  
    if( str )
199  
    if( str )
200  
        return {boost::system::in_place_value, T(str->subview())};
200  
        return {boost::system::in_place_value, T(str->subview())};
201  
    system::error_code ec;
201  
    system::error_code ec;
202  
    BOOST_JSON_FAIL(ec, error::not_string);
202  
    BOOST_JSON_FAIL(ec, error::not_string);
203  
    return {boost::system::in_place_error, ec};
203  
    return {boost::system::in_place_error, ec};
204  
}
204  
}
205  

205  

206  
// map-like containers
206  
// map-like containers
207  
template< class T, class Ctx >
207  
template< class T, class Ctx >
208  
system::result<T>
208  
system::result<T>
209  
value_to_impl(
209  
value_to_impl(
210  
    map_like_conversion_tag,
210  
    map_like_conversion_tag,
211  
    try_value_to_tag<T>,
211  
    try_value_to_tag<T>,
212  
    value const& jv,
212  
    value const& jv,
213  
    Ctx const& ctx )
213  
    Ctx const& ctx )
214  
{
214  
{
215  
    object const* obj = jv.if_object();
215  
    object const* obj = jv.if_object();
216  
    if( !obj )
216  
    if( !obj )
217  
    {
217  
    {
218  
        system::error_code ec;
218  
        system::error_code ec;
219  
        BOOST_JSON_FAIL(ec, error::not_object);
219  
        BOOST_JSON_FAIL(ec, error::not_object);
220  
        return {boost::system::in_place_error, ec};
220  
        return {boost::system::in_place_error, ec};
221  
    }
221  
    }
222  

222  

223  
    T res;
223  
    T res;
224  
    error const e = detail::try_reserve(
224  
    error const e = detail::try_reserve(
225  
        res, obj->size(), reserve_implementation<T>());
225  
        res, obj->size(), reserve_implementation<T>());
226  
    if( e != error() )
226  
    if( e != error() )
227  
    {
227  
    {
228  
        system::error_code ec;
228  
        system::error_code ec;
229  
        BOOST_JSON_FAIL( ec, e );
229  
        BOOST_JSON_FAIL( ec, e );
230  
        return {boost::system::in_place_error, ec};
230  
        return {boost::system::in_place_error, ec};
231  
    }
231  
    }
232  

232  

233  
    auto ins = detail::inserter(res, inserter_implementation<T>());
233  
    auto ins = detail::inserter(res, inserter_implementation<T>());
234  
    for( key_value_pair const& kv: *obj )
234  
    for( key_value_pair const& kv: *obj )
235  
    {
235  
    {
236  
        auto elem_res = try_value_to<mapped_type<T>>( kv.value(), ctx );
236  
        auto elem_res = try_value_to<mapped_type<T>>( kv.value(), ctx );
237  
        if( elem_res.has_error() )
237  
        if( elem_res.has_error() )
238  
            return {boost::system::in_place_error, elem_res.error()};
238  
            return {boost::system::in_place_error, elem_res.error()};
239  
        *ins++ = value_type<T>{
239  
        *ins++ = value_type<T>{
240  
            key_type<T>(kv.key()),
240  
            key_type<T>(kv.key()),
241  
            std::move(*elem_res)};
241  
            std::move(*elem_res)};
242  
    }
242  
    }
243  
    return res;
243  
    return res;
244  
}
244  
}
245  

245  

246  
// all other containers
246  
// all other containers
247  
template< class T, class Ctx >
247  
template< class T, class Ctx >
248  
system::result<T>
248  
system::result<T>
249  
value_to_impl(
249  
value_to_impl(
250  
    sequence_conversion_tag,
250  
    sequence_conversion_tag,
251  
    try_value_to_tag<T>,
251  
    try_value_to_tag<T>,
252  
    value const& jv,
252  
    value const& jv,
253  
    Ctx const& ctx )
253  
    Ctx const& ctx )
254  
{
254  
{
255  
    array const* arr = jv.if_array();
255  
    array const* arr = jv.if_array();
256  
    if( !arr )
256  
    if( !arr )
257  
    {
257  
    {
258  
        system::error_code ec;
258  
        system::error_code ec;
259  
        BOOST_JSON_FAIL(ec, error::not_array);
259  
        BOOST_JSON_FAIL(ec, error::not_array);
260  
        return {boost::system::in_place_error, ec};
260  
        return {boost::system::in_place_error, ec};
261  
    }
261  
    }
262  

262  

263  
    T result;
263  
    T result;
264  
    error const e = detail::try_reserve(
264  
    error const e = detail::try_reserve(
265  
        result, arr->size(), reserve_implementation<T>());
265  
        result, arr->size(), reserve_implementation<T>());
266  
    if( e != error() )
266  
    if( e != error() )
267  
    {
267  
    {
268  
        system::error_code ec;
268  
        system::error_code ec;
269  
        BOOST_JSON_FAIL( ec, e );
269  
        BOOST_JSON_FAIL( ec, e );
270  
        return {boost::system::in_place_error, ec};
270  
        return {boost::system::in_place_error, ec};
271  
    }
271  
    }
272  

272  

273  
    auto ins = detail::inserter(result, inserter_implementation<T>());
273  
    auto ins = detail::inserter(result, inserter_implementation<T>());
274  
    for( value const& val: *arr )
274  
    for( value const& val: *arr )
275  
    {
275  
    {
276  
        auto elem_res = try_value_to<value_type<T>>( val, ctx );
276  
        auto elem_res = try_value_to<value_type<T>>( val, ctx );
277  
        if( elem_res.has_error() )
277  
        if( elem_res.has_error() )
278  
            return {boost::system::in_place_error, elem_res.error()};
278  
            return {boost::system::in_place_error, elem_res.error()};
279  
        *ins++ = std::move(*elem_res);
279  
        *ins++ = std::move(*elem_res);
280  
    }
280  
    }
281  
    return result;
281  
    return result;
282  
}
282  
}
283  

283  

284  
// tuple-like types
284  
// tuple-like types
285  
template< class T, class Ctx >
285  
template< class T, class Ctx >
286  
system::result<T>
286  
system::result<T>
287  
try_make_tuple_elem(value const& jv, Ctx const& ctx, system::error_code& ec)
287  
try_make_tuple_elem(value const& jv, Ctx const& ctx, system::error_code& ec)
288  
{
288  
{
289  
    if( ec.failed() )
289  
    if( ec.failed() )
290  
        return {boost::system::in_place_error, ec};
290  
        return {boost::system::in_place_error, ec};
291  

291  

292  
    auto result = try_value_to<T>( jv, ctx );
292  
    auto result = try_value_to<T>( jv, ctx );
293  
    ec = result.error();
293  
    ec = result.error();
294  
    return result;
294  
    return result;
295  
}
295  
}
296  

296  

297  
template <class T, class Ctx, std::size_t... Is>
297  
template <class T, class Ctx, std::size_t... Is>
298  
system::result<T>
298  
system::result<T>
299  
try_make_tuple_like(
299  
try_make_tuple_like(
300  
    array const& arr, Ctx const& ctx, boost::mp11::index_sequence<Is...>)
300  
    array const& arr, Ctx const& ctx, boost::mp11::index_sequence<Is...>)
301  
{
301  
{
302  
    system::error_code ec;
302  
    system::error_code ec;
303  
    auto items = std::make_tuple(
303  
    auto items = std::make_tuple(
304  
        try_make_tuple_elem<
304  
        try_make_tuple_elem<
305  
            typename std::decay<tuple_element_t<Is, T>>::type >(
305  
            typename std::decay<tuple_element_t<Is, T>>::type >(
306  
                arr[Is], ctx, ec)
306  
                arr[Is], ctx, ec)
307  
            ...);
307  
            ...);
308  
#if defined(BOOST_GCC)
308  
#if defined(BOOST_GCC)
309  
# pragma GCC diagnostic push
309  
# pragma GCC diagnostic push
310  
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
310  
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
311  
#endif
311  
#endif
312  
    if( ec.failed() )
312  
    if( ec.failed() )
313  
        return {boost::system::in_place_error, ec};
313  
        return {boost::system::in_place_error, ec};
314  
#if defined(BOOST_GCC)
314  
#if defined(BOOST_GCC)
315  
# pragma GCC diagnostic pop
315  
# pragma GCC diagnostic pop
316  
#endif
316  
#endif
317  

317  

318  
    return {
318  
    return {
319  
        boost::system::in_place_value, T(std::move(*std::get<Is>(items))...)};
319  
        boost::system::in_place_value, T(std::move(*std::get<Is>(items))...)};
320  
}
320  
}
321  

321  

322  
template< class T, class Ctx >
322  
template< class T, class Ctx >
323  
system::result<T>
323  
system::result<T>
324  
value_to_impl(
324  
value_to_impl(
325  
    tuple_conversion_tag,
325  
    tuple_conversion_tag,
326  
    try_value_to_tag<T>,
326  
    try_value_to_tag<T>,
327  
    value const& jv,
327  
    value const& jv,
328  
    Ctx const& ctx )
328  
    Ctx const& ctx )
329  
{
329  
{
330  
    system::error_code ec;
330  
    system::error_code ec;
331  

331  

332  
    array const* arr = jv.if_array();
332  
    array const* arr = jv.if_array();
333  
    if( !arr )
333  
    if( !arr )
334  
    {
334  
    {
335  
        BOOST_JSON_FAIL(ec, error::not_array);
335  
        BOOST_JSON_FAIL(ec, error::not_array);
336  
        return {boost::system::in_place_error, ec};
336  
        return {boost::system::in_place_error, ec};
337  
    }
337  
    }
338  

338  

339  
    constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
339  
    constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
340  
    if( N != arr->size() )
340  
    if( N != arr->size() )
341  
    {
341  
    {
342  
        BOOST_JSON_FAIL(ec, error::size_mismatch);
342  
        BOOST_JSON_FAIL(ec, error::size_mismatch);
343  
        return {boost::system::in_place_error, ec};
343  
        return {boost::system::in_place_error, ec};
344  
    }
344  
    }
345  

345  

346  
    return try_make_tuple_like<T>(
346  
    return try_make_tuple_like<T>(
347  
        *arr, ctx, boost::mp11::make_index_sequence<N>());
347  
        *arr, ctx, boost::mp11::make_index_sequence<N>());
348  
}
348  
}
349  

349  

350  
template< class Ctx, class T >
350  
template< class Ctx, class T >
351  
struct to_described_member
351  
struct to_described_member
352  
{
352  
{
353  
    static_assert(
353  
    static_assert(
354  
        uniquely_named_members<T>::value,
354  
        uniquely_named_members<T>::value,
355  
        "The type has several described members with the same name.");
355  
        "The type has several described members with the same name.");
356  

356  

357  
    using Ds = described_members<T>;
357  
    using Ds = described_members<T>;
358  

358  

359  
    system::result<T>& res;
359  
    system::result<T>& res;
360  
    object const& obj;
360  
    object const& obj;
361  
    Ctx const& ctx;
361  
    Ctx const& ctx;
362  

362  

363  
    template< class I >
363  
    template< class I >
364  
    void
364  
    void
365  
    operator()(I)
365  
    operator()(I)
366  
    {
366  
    {
367  
        if( !res )
367  
        if( !res )
368  
            return;
368  
            return;
369  

369  

370  
        using D = mp11::mp_at<Ds, I>;
370  
        using D = mp11::mp_at<Ds, I>;
371  
        using M = described_member_t<T, D>;
371  
        using M = described_member_t<T, D>;
372  

372  

373  
        auto const found = obj.find(D::name);
373  
        auto const found = obj.find(D::name);
374  
        if( found == obj.end() )
374  
        if( found == obj.end() )
375  
        {
375  
        {
376  
            BOOST_IF_CONSTEXPR( !is_optional_like<M>::value )
376  
            BOOST_IF_CONSTEXPR( !is_optional_like<M>::value )
377  
            {
377  
            {
378  
                system::error_code ec;
378  
                system::error_code ec;
379  
                BOOST_JSON_FAIL(ec, error::size_mismatch);
379  
                BOOST_JSON_FAIL(ec, error::size_mismatch);
380  
                res = {boost::system::in_place_error, ec};
380  
                res = {boost::system::in_place_error, ec};
381  
            }
381  
            }
382  
            return;
382  
            return;
383  
        }
383  
        }
384  

384  

385  
#if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
385  
#if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
386  
# pragma GCC diagnostic push
386  
# pragma GCC diagnostic push
387  
# pragma GCC diagnostic ignored "-Wunused"
387  
# pragma GCC diagnostic ignored "-Wunused"
388  
# pragma GCC diagnostic ignored "-Wunused-variable"
388  
# pragma GCC diagnostic ignored "-Wunused-variable"
389  
#endif
389  
#endif
390  
        auto member_res = try_value_to<M>( found->value(), ctx );
390  
        auto member_res = try_value_to<M>( found->value(), ctx );
391  
#if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
391  
#if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
392  
# pragma GCC diagnostic pop
392  
# pragma GCC diagnostic pop
393  
#endif
393  
#endif
394  
        if( member_res )
394  
        if( member_res )
395  
            (*res).* D::pointer = std::move(*member_res);
395  
            (*res).* D::pointer = std::move(*member_res);
396  
        else
396  
        else
397  
            res = {boost::system::in_place_error, member_res.error()};
397  
            res = {boost::system::in_place_error, member_res.error()};
398  
    }
398  
    }
399  
};
399  
};
400  

400  

401  
// described classes
401  
// described classes
402  
template< class T, class Ctx >
402  
template< class T, class Ctx >
403  
system::result<T>
403  
system::result<T>
404  
value_to_impl(
404  
value_to_impl(
405  
    described_class_conversion_tag,
405  
    described_class_conversion_tag,
406  
    try_value_to_tag<T>,
406  
    try_value_to_tag<T>,
407  
    value const& jv,
407  
    value const& jv,
408  
    Ctx const& ctx )
408  
    Ctx const& ctx )
409  
{
409  
{
410  
    BOOST_CORE_STATIC_ASSERT( std::is_default_constructible<T>::value );
410  
    BOOST_CORE_STATIC_ASSERT( std::is_default_constructible<T>::value );
411  
    system::result<T> res;
411  
    system::result<T> res;
412  

412  

413  
    auto* obj = jv.if_object();
413  
    auto* obj = jv.if_object();
414  
    if( !obj )
414  
    if( !obj )
415  
    {
415  
    {
416  
        system::error_code ec;
416  
        system::error_code ec;
417  
        BOOST_JSON_FAIL(ec, error::not_object);
417  
        BOOST_JSON_FAIL(ec, error::not_object);
418  
        res = {boost::system::in_place_error, ec};
418  
        res = {boost::system::in_place_error, ec};
419  
        return res;
419  
        return res;
420  
    }
420  
    }
421  

421  

422  
    to_described_member<Ctx, T> member_converter{res, *obj, ctx};
422  
    to_described_member<Ctx, T> member_converter{res, *obj, ctx};
423  

423  

424  
    using Ds = typename decltype(member_converter)::Ds;
424  
    using Ds = typename decltype(member_converter)::Ds;
425  
    constexpr std::size_t N = mp11::mp_size<Ds>::value;
425  
    constexpr std::size_t N = mp11::mp_size<Ds>::value;
426  
    mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
426  
    mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
427  

427  

428  
    if( !res )
428  
    if( !res )
429  
        return res;
429  
        return res;
430  

430  

431  
    return res;
431  
    return res;
432  
}
432  
}
433  

433  

434  
// described enums
434  
// described enums
435  
template< class T, class Ctx >
435  
template< class T, class Ctx >
436  
system::result<T>
436  
system::result<T>
437  
value_to_impl(
437  
value_to_impl(
438  
    described_enum_conversion_tag,
438  
    described_enum_conversion_tag,
439  
    try_value_to_tag<T>,
439  
    try_value_to_tag<T>,
440  
    value const& jv,
440  
    value const& jv,
441  
    Ctx const& )
441  
    Ctx const& )
442  
{
442  
{
443  
    T val = {};
443  
    T val = {};
444  
    (void)jv;
444  
    (void)jv;
445  
#ifdef BOOST_DESCRIBE_CXX14
445  
#ifdef BOOST_DESCRIBE_CXX14
446  
    system::error_code ec;
446  
    system::error_code ec;
447  

447  

448  
    auto str = jv.if_string();
448  
    auto str = jv.if_string();
449  
    if( !str )
449  
    if( !str )
450  
    {
450  
    {
451  
        BOOST_JSON_FAIL(ec, error::not_string);
451  
        BOOST_JSON_FAIL(ec, error::not_string);
452  
        return {system::in_place_error, ec};
452  
        return {system::in_place_error, ec};
453  
    }
453  
    }
454  

454  

455  
    if( !describe::enum_from_string(str->data(), val) )
455  
    if( !describe::enum_from_string(str->data(), val) )
456  
    {
456  
    {
457  
        BOOST_JSON_FAIL(ec, error::unknown_name);
457  
        BOOST_JSON_FAIL(ec, error::unknown_name);
458  
        return {system::in_place_error, ec};
458  
        return {system::in_place_error, ec};
459  
    }
459  
    }
460  
#endif
460  
#endif
461  

461  

462  
    return {system::in_place_value, val};
462  
    return {system::in_place_value, val};
463  
}
463  
}
464  

464  

465  
// optionals
465  
// optionals
466  
template< class T, class Ctx >
466  
template< class T, class Ctx >
467  
system::result<T>
467  
system::result<T>
468  
value_to_impl(
468  
value_to_impl(
469  
    optional_conversion_tag,
469  
    optional_conversion_tag,
470  
    try_value_to_tag<T>,
470  
    try_value_to_tag<T>,
471  
    value const& jv,
471  
    value const& jv,
472  
    Ctx const& ctx)
472  
    Ctx const& ctx)
473  
{
473  
{
474  
    using Inner = value_result_type<T>;
474  
    using Inner = value_result_type<T>;
475  
    if( jv.is_null() )
475  
    if( jv.is_null() )
476  
        return {};
476  
        return {};
477  
    else
477  
    else
478  
        return try_value_to<Inner>(jv, ctx);
478  
        return try_value_to<Inner>(jv, ctx);
479  
}
479  
}
480  

480  

481  
// variants
481  
// variants
482  
template< class T, class V, class I >
482  
template< class T, class V, class I >
483  
using variant_construction_category = mp11::mp_cond<
483  
using variant_construction_category = mp11::mp_cond<
484  
    std::is_constructible< T, variant2::in_place_index_t<I::value>, V >,
484  
    std::is_constructible< T, variant2::in_place_index_t<I::value>, V >,
485  
        mp11::mp_int<2>,
485  
        mp11::mp_int<2>,
486  
#ifndef BOOST_NO_CXX17_HDR_VARIANT
486  
#ifndef BOOST_NO_CXX17_HDR_VARIANT
487  
    std::is_constructible< T, std::in_place_index_t<I::value>, V >,
487  
    std::is_constructible< T, std::in_place_index_t<I::value>, V >,
488  
        mp11::mp_int<1>,
488  
        mp11::mp_int<1>,
489  
#endif // BOOST_NO_CXX17_HDR_VARIANT
489  
#endif // BOOST_NO_CXX17_HDR_VARIANT
490  
    mp11::mp_true,
490  
    mp11::mp_true,
491  
        mp11::mp_int<0> >;
491  
        mp11::mp_int<0> >;
492  

492  

493  
template< class T, class I, class V >
493  
template< class T, class I, class V >
494  
T
494  
T
495  
initialize_variant( V&& v, mp11::mp_int<0> )
495  
initialize_variant( V&& v, mp11::mp_int<0> )
496  
{
496  
{
497  
    T t;
497  
    T t;
498  
    t.template emplace<I::value>( std::move(v) );
498  
    t.template emplace<I::value>( std::move(v) );
499  
    return t;
499  
    return t;
500  
}
500  
}
501  

501  

502  
template< class T, class I, class V >
502  
template< class T, class I, class V >
503  
T
503  
T
504  
initialize_variant( V&& v, mp11::mp_int<2> )
504  
initialize_variant( V&& v, mp11::mp_int<2> )
505  
{
505  
{
506  
    return T( variant2::in_place_index_t<I::value>(), std::move(v) );
506  
    return T( variant2::in_place_index_t<I::value>(), std::move(v) );
507  
}
507  
}
508  

508  

509  
#ifndef BOOST_NO_CXX17_HDR_VARIANT
509  
#ifndef BOOST_NO_CXX17_HDR_VARIANT
510  
template< class T, class I, class V >
510  
template< class T, class I, class V >
511  
T
511  
T
512  
initialize_variant( V&& v, mp11::mp_int<1> )
512  
initialize_variant( V&& v, mp11::mp_int<1> )
513  
{
513  
{
514  
    return T( std::in_place_index_t<I::value>(), std::move(v) );
514  
    return T( std::in_place_index_t<I::value>(), std::move(v) );
515  
}
515  
}
516  
#endif // BOOST_NO_CXX17_HDR_VARIANT
516  
#endif // BOOST_NO_CXX17_HDR_VARIANT
517  

517  

518  

518  

519  
template< class T, class Ctx >
519  
template< class T, class Ctx >
520  
struct alternative_converter
520  
struct alternative_converter
521  
{
521  
{
522  
    system::result<T>& res;
522  
    system::result<T>& res;
523  
    value const& jv;
523  
    value const& jv;
524  
    Ctx const& ctx;
524  
    Ctx const& ctx;
525  

525  

526  
    template< class I >
526  
    template< class I >
527  
    void operator()( I ) const
527  
    void operator()( I ) const
528  
    {
528  
    {
529  
        if( res )
529  
        if( res )
530  
            return;
530  
            return;
531  

531  

532  
        using V = mp11::mp_at<T, I>;
532  
        using V = mp11::mp_at<T, I>;
533  
        auto attempt = try_value_to<V>(jv, ctx);
533  
        auto attempt = try_value_to<V>(jv, ctx);
534  
        if( attempt )
534  
        if( attempt )
535  
        {
535  
        {
536  
            using cat = variant_construction_category<T, V, I>;
536  
            using cat = variant_construction_category<T, V, I>;
537  
            res = initialize_variant<T, I>( std::move(*attempt), cat() );
537  
            res = initialize_variant<T, I>( std::move(*attempt), cat() );
538  
        }
538  
        }
539  
    }
539  
    }
540  
};
540  
};
541  

541  

542  
template< class T, class Ctx >
542  
template< class T, class Ctx >
543  
system::result<T>
543  
system::result<T>
544  
value_to_impl(
544  
value_to_impl(
545  
    variant_conversion_tag,
545  
    variant_conversion_tag,
546  
    try_value_to_tag<T>,
546  
    try_value_to_tag<T>,
547  
    value const& jv,
547  
    value const& jv,
548  
    Ctx const& ctx)
548  
    Ctx const& ctx)
549  
{
549  
{
550  
    system::error_code ec;
550  
    system::error_code ec;
551  
    BOOST_JSON_FAIL(ec, error::exhausted_variants);
551  
    BOOST_JSON_FAIL(ec, error::exhausted_variants);
552  

552  

553  
    using Is = mp11::mp_iota< mp11::mp_size<T> >;
553  
    using Is = mp11::mp_iota< mp11::mp_size<T> >;
554  

554  

555  
    system::result<T> res = {system::in_place_error, ec};
555  
    system::result<T> res = {system::in_place_error, ec};
556  
    mp11::mp_for_each<Is>( alternative_converter<T, Ctx>{res, jv, ctx} );
556  
    mp11::mp_for_each<Is>( alternative_converter<T, Ctx>{res, jv, ctx} );
557  
    return res;
557  
    return res;
558  
}
558  
}
559  

559  

560  
template< class T, class Ctx >
560  
template< class T, class Ctx >
561  
system::result<T>
561  
system::result<T>
562  
value_to_impl(
562  
value_to_impl(
563  
    path_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
563  
    path_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
564  
{
564  
{
565  
    auto str = jv.if_string();
565  
    auto str = jv.if_string();
566  
    if( !str )
566  
    if( !str )
567  
    {
567  
    {
568  
        system::error_code ec;
568  
        system::error_code ec;
569  
        BOOST_JSON_FAIL(ec, error::not_string);
569  
        BOOST_JSON_FAIL(ec, error::not_string);
570  
        return {boost::system::in_place_error, ec};
570  
        return {boost::system::in_place_error, ec};
571  
    }
571  
    }
572  

572  

573  
    string_view sv = str->subview();
573  
    string_view sv = str->subview();
574  
    return {boost::system::in_place_value, T( sv.begin(), sv.end() )};
574  
    return {boost::system::in_place_value, T( sv.begin(), sv.end() )};
575  
}
575  
}
576  

576  

577  
//----------------------------------------------------------
577  
//----------------------------------------------------------
578  
// User-provided conversions; throwing -> throwing
578  
// User-provided conversions; throwing -> throwing
579  
template< class T, class Ctx >
579  
template< class T, class Ctx >
580  
mp11::mp_if< mp11::mp_valid<has_user_conversion_to_impl, T>, T >
580  
mp11::mp_if< mp11::mp_valid<has_user_conversion_to_impl, T>, T >
581  
value_to_impl(
581  
value_to_impl(
582  
    user_conversion_tag, value_to_tag<T> tag, value const& jv, Ctx const&)
582  
    user_conversion_tag, value_to_tag<T> tag, value const& jv, Ctx const&)
583  
{
583  
{
584  
    return tag_invoke(tag, jv);
584  
    return tag_invoke(tag, jv);
585  
}
585  
}
586  

586  

587  
template<
587  
template<
588  
    class T,
588  
    class T,
589  
    class Ctx,
589  
    class Ctx,
590  
    class Sup = supported_context<Ctx, T, value_to_conversion>
590  
    class Sup = supported_context<Ctx, T, value_to_conversion>
591  
>
591  
>
592  
mp11::mp_if<
592  
mp11::mp_if<
593  
    mp11::mp_valid< has_context_conversion_to_impl, typename Sup::type, T>, T >
593  
    mp11::mp_valid< has_context_conversion_to_impl, typename Sup::type, T>, T >
594  
value_to_impl(
594  
value_to_impl(
595  
    context_conversion_tag,
595  
    context_conversion_tag,
596  
    value_to_tag<T> tag,
596  
    value_to_tag<T> tag,
597  
    value const& jv,
597  
    value const& jv,
598  
    Ctx const& ctx )
598  
    Ctx const& ctx )
599  
{
599  
{
600  
    return tag_invoke( tag, jv, Sup::get(ctx) );
600  
    return tag_invoke( tag, jv, Sup::get(ctx) );
601  
}
601  
}
602  

602  

603  
template<
603  
template<
604  
    class T,
604  
    class T,
605  
    class Ctx,
605  
    class Ctx,
606  
    class Sup = supported_context<Ctx, T, value_to_conversion>
606  
    class Sup = supported_context<Ctx, T, value_to_conversion>
607  
>
607  
>
608  
mp11::mp_if<
608  
mp11::mp_if<
609  
    mp11::mp_valid<
609  
    mp11::mp_valid<
610  
        has_full_context_conversion_to_impl, typename Sup::type, T>,
610  
        has_full_context_conversion_to_impl, typename Sup::type, T>,
611  
    T>
611  
    T>
612  
value_to_impl(
612  
value_to_impl(
613  
    full_context_conversion_tag,
613  
    full_context_conversion_tag,
614  
    value_to_tag<T> tag,
614  
    value_to_tag<T> tag,
615  
    value const& jv,
615  
    value const& jv,
616  
    Ctx const& ctx )
616  
    Ctx const& ctx )
617  
{
617  
{
618  
    return tag_invoke( tag, jv, Sup::get(ctx), ctx );
618  
    return tag_invoke( tag, jv, Sup::get(ctx), ctx );
619  
}
619  
}
620  

620  

621  
//----------------------------------------------------------
621  
//----------------------------------------------------------
622  
// User-provided conversions; throwing -> nonthrowing
622  
// User-provided conversions; throwing -> nonthrowing
623  
template< class T, class Ctx >
623  
template< class T, class Ctx >
624  
mp11::mp_if_c< !mp11::mp_valid<has_user_conversion_to_impl, T>::value, T>
624  
mp11::mp_if_c< !mp11::mp_valid<has_user_conversion_to_impl, T>::value, T>
625  
value_to_impl(
625  
value_to_impl(
626  
    user_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& )
626  
    user_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& )
627  
{
627  
{
628  
    auto res = tag_invoke(try_value_to_tag<T>(), jv);
628  
    auto res = tag_invoke(try_value_to_tag<T>(), jv);
629  
    if( res.has_error() )
629  
    if( res.has_error() )
630  
        throw_system_error( res.error() );
630  
        throw_system_error( res.error() );
631  
    return std::move(*res);
631  
    return std::move(*res);
632  
}
632  
}
633  

633  

634  
template<
634  
template<
635  
    class T,
635  
    class T,
636  
    class Ctx,
636  
    class Ctx,
637  
    class Sup = supported_context<Ctx, T, value_to_conversion>
637  
    class Sup = supported_context<Ctx, T, value_to_conversion>
638  
>
638  
>
639  
mp11::mp_if_c<
639  
mp11::mp_if_c<
640  
    !mp11::mp_valid<
640  
    !mp11::mp_valid<
641  
        has_context_conversion_to_impl, typename Sup::type, T>::value,
641  
        has_context_conversion_to_impl, typename Sup::type, T>::value,
642  
    T>
642  
    T>
643  
value_to_impl(
643  
value_to_impl(
644  
    context_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& ctx )
644  
    context_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& ctx )
645  
{
645  
{
646  
    auto res = tag_invoke( try_value_to_tag<T>(), jv, Sup::get(ctx) );
646  
    auto res = tag_invoke( try_value_to_tag<T>(), jv, Sup::get(ctx) );
647  
    if( res.has_error() )
647  
    if( res.has_error() )
648  
        throw_system_error( res.error() );
648  
        throw_system_error( res.error() );
649  
    return std::move(*res);
649  
    return std::move(*res);
650  
}
650  
}
651  

651  

652  
template<
652  
template<
653  
    class T,
653  
    class T,
654  
    class Ctx,
654  
    class Ctx,
655  
    class Sup = supported_context<Ctx, T, value_to_conversion>
655  
    class Sup = supported_context<Ctx, T, value_to_conversion>
656  
>
656  
>
657  
mp11::mp_if_c<
657  
mp11::mp_if_c<
658  
    !mp11::mp_valid<
658  
    !mp11::mp_valid<
659  
        has_full_context_conversion_to_impl, typename Sup::type, T>::value,
659  
        has_full_context_conversion_to_impl, typename Sup::type, T>::value,
660  
    T>
660  
    T>
661  
value_to_impl(
661  
value_to_impl(
662  
    full_context_conversion_tag,
662  
    full_context_conversion_tag,
663  
    value_to_tag<T>,
663  
    value_to_tag<T>,
664  
    value const& jv,
664  
    value const& jv,
665  
    Ctx const& ctx )
665  
    Ctx const& ctx )
666  
{
666  
{
667  
    auto res = tag_invoke(try_value_to_tag<T>(), jv, Sup::get(ctx), ctx);
667  
    auto res = tag_invoke(try_value_to_tag<T>(), jv, Sup::get(ctx), ctx);
668  
    if( res.has_error() )
668  
    if( res.has_error() )
669  
        throw_system_error( res.error() );
669  
        throw_system_error( res.error() );
670  
    return std::move(*res);
670  
    return std::move(*res);
671  
}
671  
}
672  

672  

673  
//----------------------------------------------------------
673  
//----------------------------------------------------------
674  
// User-provided conversions; nonthrowing -> nonthrowing
674  
// User-provided conversions; nonthrowing -> nonthrowing
675  
template< class T, class Ctx >
675  
template< class T, class Ctx >
676  
mp11::mp_if<
676  
mp11::mp_if<
677  
    mp11::mp_valid<
677  
    mp11::mp_valid<
678  
        has_nonthrowing_user_conversion_to_impl, T>, system::result<T> >
678  
        has_nonthrowing_user_conversion_to_impl, T>, system::result<T> >
679  
value_to_impl(
679  
value_to_impl(
680  
    user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
680  
    user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
681  
{
681  
{
682  
    return tag_invoke(try_value_to_tag<T>(), jv);
682  
    return tag_invoke(try_value_to_tag<T>(), jv);
683  
}
683  
}
684  

684  

685  
template<
685  
template<
686  
    class T,
686  
    class T,
687  
    class Ctx,
687  
    class Ctx,
688  
    class Sup = supported_context<Ctx, T, value_to_conversion>
688  
    class Sup = supported_context<Ctx, T, value_to_conversion>
689  
>
689  
>
690  
mp11::mp_if<
690  
mp11::mp_if<
691  
    mp11::mp_valid<
691  
    mp11::mp_valid<
692  
        has_nonthrowing_context_conversion_to_impl, typename Sup::type, T>,
692  
        has_nonthrowing_context_conversion_to_impl, typename Sup::type, T>,
693  
    system::result<T> >
693  
    system::result<T> >
694  
value_to_impl(
694  
value_to_impl(
695  
    context_conversion_tag,
695  
    context_conversion_tag,
696  
    try_value_to_tag<T> tag,
696  
    try_value_to_tag<T> tag,
697  
    value const& jv,
697  
    value const& jv,
698  
    Ctx const& ctx )
698  
    Ctx const& ctx )
699  
{
699  
{
700  
    return tag_invoke( tag, jv, Sup::get(ctx) );
700  
    return tag_invoke( tag, jv, Sup::get(ctx) );
701  
}
701  
}
702  

702  

703  
template<
703  
template<
704  
    class T,
704  
    class T,
705  
    class Ctx,
705  
    class Ctx,
706  
    class Sup = supported_context<Ctx, T, value_to_conversion>
706  
    class Sup = supported_context<Ctx, T, value_to_conversion>
707  
>
707  
>
708  
mp11::mp_if<
708  
mp11::mp_if<
709  
    mp11::mp_valid<
709  
    mp11::mp_valid<
710  
        has_nonthrowing_full_context_conversion_to_impl,
710  
        has_nonthrowing_full_context_conversion_to_impl,
711  
        typename Sup::type,
711  
        typename Sup::type,
712  
        T>,
712  
        T>,
713  
    system::result<T> >
713  
    system::result<T> >
714  
value_to_impl(
714  
value_to_impl(
715  
    full_context_conversion_tag,
715  
    full_context_conversion_tag,
716  
    try_value_to_tag<T> tag,
716  
    try_value_to_tag<T> tag,
717  
    value const& jv,
717  
    value const& jv,
718  
    Ctx const& ctx )
718  
    Ctx const& ctx )
719  
{
719  
{
720  
    return tag_invoke( tag, jv, Sup::get(ctx), ctx );
720  
    return tag_invoke( tag, jv, Sup::get(ctx), ctx );
721  
}
721  
}
722  

722  

723  
//----------------------------------------------------------
723  
//----------------------------------------------------------
724  
// User-provided conversions; nonthrowing -> throwing
724  
// User-provided conversions; nonthrowing -> throwing
725  

725  

726  
template< class T, class... Args >
726  
template< class T, class... Args >
727  
system::result<T>
727  
system::result<T>
728  
wrap_conversion_exceptions( value_to_tag<T>, Args&& ... args )
728  
wrap_conversion_exceptions( value_to_tag<T>, Args&& ... args )
729  
{
729  
{
730  
#ifndef BOOST_NO_EXCEPTIONS
730  
#ifndef BOOST_NO_EXCEPTIONS
731  
    try
731  
    try
732  
    {
732  
    {
733  
#endif
733  
#endif
734  
        return {
734  
        return {
735  
            boost::system::in_place_value,
735  
            boost::system::in_place_value,
736  
            tag_invoke( value_to_tag<T>(), static_cast<Args&&>(args)... )};
736  
            tag_invoke( value_to_tag<T>(), static_cast<Args&&>(args)... )};
737  
#ifndef BOOST_NO_EXCEPTIONS
737  
#ifndef BOOST_NO_EXCEPTIONS
738  
    }
738  
    }
739  
    catch( std::bad_alloc const&)
739  
    catch( std::bad_alloc const&)
740  
    {
740  
    {
741  
        throw;
741  
        throw;
742  
    }
742  
    }
743  
    catch( system::system_error const& e)
743  
    catch( system::system_error const& e)
744  
    {
744  
    {
745  
        return {boost::system::in_place_error, e.code()};
745  
        return {boost::system::in_place_error, e.code()};
746  
    }
746  
    }
747  
    catch( ... )
747  
    catch( ... )
748  
    {
748  
    {
749  
        system::error_code ec;
749  
        system::error_code ec;
750  
        BOOST_JSON_FAIL(ec, error::exception);
750  
        BOOST_JSON_FAIL(ec, error::exception);
751  
        return {boost::system::in_place_error, ec};
751  
        return {boost::system::in_place_error, ec};
752  
    }
752  
    }
753  
#endif
753  
#endif
754  
}
754  
}
755  

755  

756  
template< class T, class Ctx >
756  
template< class T, class Ctx >
757  
mp11::mp_if_c<
757  
mp11::mp_if_c<
758  
    !mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>::value,
758  
    !mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>::value,
759  
    system::result<T> >
759  
    system::result<T> >
760  
value_to_impl(
760  
value_to_impl(
761  
    user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
761  
    user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
762  
{
762  
{
763  
    return wrap_conversion_exceptions(value_to_tag<T>(), jv);
763  
    return wrap_conversion_exceptions(value_to_tag<T>(), jv);
764  
}
764  
}
765  

765  

766  
template<
766  
template<
767  
    class T,
767  
    class T,
768  
    class Ctx,
768  
    class Ctx,
769  
    class Sup = supported_context<Ctx, T, value_to_conversion>
769  
    class Sup = supported_context<Ctx, T, value_to_conversion>
770  
>
770  
>
771  
mp11::mp_if_c<
771  
mp11::mp_if_c<
772  
    !mp11::mp_valid<
772  
    !mp11::mp_valid<
773  
        has_nonthrowing_context_conversion_to_impl,
773  
        has_nonthrowing_context_conversion_to_impl,
774  
        typename Sup::type,
774  
        typename Sup::type,
775  
        T>::value,
775  
        T>::value,
776  
    system::result<T> >
776  
    system::result<T> >
777  
value_to_impl(
777  
value_to_impl(
778  
    context_conversion_tag,
778  
    context_conversion_tag,
779  
    try_value_to_tag<T>,
779  
    try_value_to_tag<T>,
780  
    value const& jv,
780  
    value const& jv,
781  
    Ctx const& ctx )
781  
    Ctx const& ctx )
782  
{
782  
{
783  
    return wrap_conversion_exceptions( value_to_tag<T>(), jv, Sup::get(ctx) );
783  
    return wrap_conversion_exceptions( value_to_tag<T>(), jv, Sup::get(ctx) );
784  
}
784  
}
785  

785  

786  
template<
786  
template<
787  
    class T,
787  
    class T,
788  
    class Ctx,
788  
    class Ctx,
789  
    class Sup = supported_context<Ctx, T, value_to_conversion>
789  
    class Sup = supported_context<Ctx, T, value_to_conversion>
790  
>
790  
>
791  
mp11::mp_if_c<
791  
mp11::mp_if_c<
792  
    !mp11::mp_valid<
792  
    !mp11::mp_valid<
793  
        has_nonthrowing_full_context_conversion_to_impl,
793  
        has_nonthrowing_full_context_conversion_to_impl,
794  
        typename Sup::type,
794  
        typename Sup::type,
795  
        T>::value,
795  
        T>::value,
796  
    system::result<T> >
796  
    system::result<T> >
797  
value_to_impl(
797  
value_to_impl(
798  
    full_context_conversion_tag,
798  
    full_context_conversion_tag,
799  
    try_value_to_tag<T>,
799  
    try_value_to_tag<T>,
800  
    value const& jv,
800  
    value const& jv,
801  
    Ctx const& ctx )
801  
    Ctx const& ctx )
802  
{
802  
{
803  
    return wrap_conversion_exceptions(
803  
    return wrap_conversion_exceptions(
804  
        value_to_tag<T>(), jv, Sup::get(ctx), ctx);
804  
        value_to_tag<T>(), jv, Sup::get(ctx), ctx);
805  
}
805  
}
806  

806  

807  
// no suitable conversion implementation
807  
// no suitable conversion implementation
808  
template< class T, class Ctx >
808  
template< class T, class Ctx >
809  
T
809  
T
810  
value_to_impl( no_conversion_tag, value_to_tag<T>, value const&, Ctx const& )
810  
value_to_impl( no_conversion_tag, value_to_tag<T>, value const&, Ctx const& )
811  
{
811  
{
812  
    static_assert(
812  
    static_assert(
813  
        !std::is_same<T, T>::value,
813  
        !std::is_same<T, T>::value,
814  
        "No suitable tag_invoke overload found for the type");
814  
        "No suitable tag_invoke overload found for the type");
815  
}
815  
}
816  

816  

817  
// generic wrapper over non-throwing implementations
817  
// generic wrapper over non-throwing implementations
818  
template< class Impl, class T, class Ctx >
818  
template< class Impl, class T, class Ctx >
819  
T
819  
T
820  
value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx )
820  
value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx )
821  
{
821  
{
822  
    return value_to_impl(impl, try_value_to_tag<T>(), jv, ctx).value();
822  
    return value_to_impl(impl, try_value_to_tag<T>(), jv, ctx).value();
823  
}
823  
}
824  

824  

825  
template< class Ctx, class T >
825  
template< class Ctx, class T >
826  
using value_to_category = conversion_category<
826  
using value_to_category = conversion_category<
827  
    Ctx, T, value_to_conversion >;
827  
    Ctx, T, value_to_conversion >;
828  

828  

829  
} // detail
829  
} // detail
830  

830  

831  
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
831  
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
832  
inline
832  
inline
833  
system::result<std::nullopt_t>
833  
system::result<std::nullopt_t>
834  
tag_invoke(
834  
tag_invoke(
835  
    try_value_to_tag<std::nullopt_t>,
835  
    try_value_to_tag<std::nullopt_t>,
836  
    value const& jv)
836  
    value const& jv)
837  
{
837  
{
838  
    if( jv.is_null() )
838  
    if( jv.is_null() )
839  
        return std::nullopt;
839  
        return std::nullopt;
840  
    system::error_code ec;
840  
    system::error_code ec;
841  
    BOOST_JSON_FAIL(ec, error::not_null);
841  
    BOOST_JSON_FAIL(ec, error::not_null);
842  
    return ec;
842  
    return ec;
843  
}
843  
}
844  
#endif
844  
#endif
845  

845  

846  
} // namespace json
846  
} // namespace json
847  
} // namespace boost
847  
} // namespace boost
848  

848  

849  
#endif
849  
#endif