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  
#if defined(BOOST_CLANG)
318  
#if defined(BOOST_CLANG)
319  
# pragma clang diagnostic push
319  
# pragma clang diagnostic push
320  
# pragma clang diagnostic ignored "-Wmissing-braces"
320  
# pragma clang diagnostic ignored "-Wmissing-braces"
321  
#endif
321  
#endif
322  
    return {
322  
    return {
323  
        boost::system::in_place_value,
323  
        boost::system::in_place_value,
324  
        T{ (std::move(*std::get<Is>(items)))... }
324  
        T{ (std::move(*std::get<Is>(items)))... }
325  
    };
325  
    };
326  
#if defined(BOOST_CLANG)
326  
#if defined(BOOST_CLANG)
327  
# pragma clang diagnostic pop
327  
# pragma clang diagnostic pop
328  
#endif
328  
#endif
329  
}
329  
}
330  

330  

331  
template< class T, class Ctx >
331  
template< class T, class Ctx >
332  
system::result<T>
332  
system::result<T>
333  
value_to_impl(
333  
value_to_impl(
334  
    tuple_conversion_tag,
334  
    tuple_conversion_tag,
335  
    try_value_to_tag<T>,
335  
    try_value_to_tag<T>,
336  
    value const& jv,
336  
    value const& jv,
337  
    Ctx const& ctx )
337  
    Ctx const& ctx )
338  
{
338  
{
339  
    system::error_code ec;
339  
    system::error_code ec;
340  

340  

341  
    array const* arr = jv.if_array();
341  
    array const* arr = jv.if_array();
342  
    if( !arr )
342  
    if( !arr )
343  
    {
343  
    {
344  
        BOOST_JSON_FAIL(ec, error::not_array);
344  
        BOOST_JSON_FAIL(ec, error::not_array);
345  
        return {boost::system::in_place_error, ec};
345  
        return {boost::system::in_place_error, ec};
346  
    }
346  
    }
347  

347  

348  
    constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
348  
    constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
349  
    if( N != arr->size() )
349  
    if( N != arr->size() )
350  
    {
350  
    {
351  
        BOOST_JSON_FAIL(ec, error::size_mismatch);
351  
        BOOST_JSON_FAIL(ec, error::size_mismatch);
352  
        return {boost::system::in_place_error, ec};
352  
        return {boost::system::in_place_error, ec};
353  
    }
353  
    }
354  

354  

355  
    return try_make_tuple_like<T>(
355  
    return try_make_tuple_like<T>(
356  
        *arr, ctx, boost::mp11::make_index_sequence<N>());
356  
        *arr, ctx, boost::mp11::make_index_sequence<N>());
357  
}
357  
}
358  

358  

359  
template< class Ctx, class T >
359  
template< class Ctx, class T >
360  
struct to_described_member
360  
struct to_described_member
361  
{
361  
{
362  
    static_assert(
362  
    static_assert(
363  
        uniquely_named_members<T>::value,
363  
        uniquely_named_members<T>::value,
364  
        "The type has several described members with the same name.");
364  
        "The type has several described members with the same name.");
365  

365  

366  
    using Ds = described_members<T>;
366  
    using Ds = described_members<T>;
367  

367  

368  
    system::result<T>& res;
368  
    system::result<T>& res;
369  
    object const& obj;
369  
    object const& obj;
370  
    Ctx const& ctx;
370  
    Ctx const& ctx;
371  

371  

372  
    template< class I >
372  
    template< class I >
373  
    void
373  
    void
374  
    operator()(I)
374  
    operator()(I)
375  
    {
375  
    {
376  
        if( !res )
376  
        if( !res )
377  
            return;
377  
            return;
378  

378  

379  
        using D = mp11::mp_at<Ds, I>;
379  
        using D = mp11::mp_at<Ds, I>;
380  
        using M = described_member_t<T, D>;
380  
        using M = described_member_t<T, D>;
381  

381  

382  
        auto const found = obj.find(D::name);
382  
        auto const found = obj.find(D::name);
383  
        if( found == obj.end() )
383  
        if( found == obj.end() )
384  
        {
384  
        {
385  
            BOOST_IF_CONSTEXPR( !is_optional_like<M>::value )
385  
            BOOST_IF_CONSTEXPR( !is_optional_like<M>::value )
386  
            {
386  
            {
387  
                system::error_code ec;
387  
                system::error_code ec;
388  
                BOOST_JSON_FAIL(ec, error::size_mismatch);
388  
                BOOST_JSON_FAIL(ec, error::size_mismatch);
389  
                res = {boost::system::in_place_error, ec};
389  
                res = {boost::system::in_place_error, ec};
390  
            }
390  
            }
391  
            return;
391  
            return;
392  
        }
392  
        }
393  

393  

394  
#if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
394  
#if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
395  
# pragma GCC diagnostic push
395  
# pragma GCC diagnostic push
396  
# pragma GCC diagnostic ignored "-Wunused"
396  
# pragma GCC diagnostic ignored "-Wunused"
397  
# pragma GCC diagnostic ignored "-Wunused-variable"
397  
# pragma GCC diagnostic ignored "-Wunused-variable"
398  
#endif
398  
#endif
399  
        auto member_res = try_value_to<M>( found->value(), ctx );
399  
        auto member_res = try_value_to<M>( found->value(), ctx );
400  
#if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
400  
#if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
401  
# pragma GCC diagnostic pop
401  
# pragma GCC diagnostic pop
402  
#endif
402  
#endif
403  
        if( member_res )
403  
        if( member_res )
404  
            (*res).* D::pointer = std::move(*member_res);
404  
            (*res).* D::pointer = std::move(*member_res);
405  
        else
405  
        else
406  
            res = {boost::system::in_place_error, member_res.error()};
406  
            res = {boost::system::in_place_error, member_res.error()};
407  
    }
407  
    }
408  
};
408  
};
409  

409  

410  
// described classes
410  
// described classes
411  
template< class T, class Ctx >
411  
template< class T, class Ctx >
412  
system::result<T>
412  
system::result<T>
413  
value_to_impl(
413  
value_to_impl(
414  
    described_class_conversion_tag,
414  
    described_class_conversion_tag,
415  
    try_value_to_tag<T>,
415  
    try_value_to_tag<T>,
416  
    value const& jv,
416  
    value const& jv,
417  
    Ctx const& ctx )
417  
    Ctx const& ctx )
418  
{
418  
{
419  
    BOOST_CORE_STATIC_ASSERT( std::is_default_constructible<T>::value );
419  
    BOOST_CORE_STATIC_ASSERT( std::is_default_constructible<T>::value );
420  
    system::result<T> res;
420  
    system::result<T> res;
421  

421  

422  
    auto* obj = jv.if_object();
422  
    auto* obj = jv.if_object();
423  
    if( !obj )
423  
    if( !obj )
424  
    {
424  
    {
425  
        system::error_code ec;
425  
        system::error_code ec;
426  
        BOOST_JSON_FAIL(ec, error::not_object);
426  
        BOOST_JSON_FAIL(ec, error::not_object);
427  
        res = {boost::system::in_place_error, ec};
427  
        res = {boost::system::in_place_error, ec};
428  
        return res;
428  
        return res;
429  
    }
429  
    }
430  

430  

431  
    to_described_member<Ctx, T> member_converter{res, *obj, ctx};
431  
    to_described_member<Ctx, T> member_converter{res, *obj, ctx};
432  

432  

433  
    using Ds = typename decltype(member_converter)::Ds;
433  
    using Ds = typename decltype(member_converter)::Ds;
434  
    constexpr std::size_t N = mp11::mp_size<Ds>::value;
434  
    constexpr std::size_t N = mp11::mp_size<Ds>::value;
435  
    mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
435  
    mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
436  

436  

437  
    if( !res )
437  
    if( !res )
438  
        return res;
438  
        return res;
439  

439  

440  
    return res;
440  
    return res;
441  
}
441  
}
442  

442  

443  
// described enums
443  
// described enums
444  
template< class T, class Ctx >
444  
template< class T, class Ctx >
445  
system::result<T>
445  
system::result<T>
446  
value_to_impl(
446  
value_to_impl(
447  
    described_enum_conversion_tag,
447  
    described_enum_conversion_tag,
448  
    try_value_to_tag<T>,
448  
    try_value_to_tag<T>,
449  
    value const& jv,
449  
    value const& jv,
450  
    Ctx const& )
450  
    Ctx const& )
451  
{
451  
{
452  
    T val = {};
452  
    T val = {};
453  
    (void)jv;
453  
    (void)jv;
454  
#ifdef BOOST_DESCRIBE_CXX14
454  
#ifdef BOOST_DESCRIBE_CXX14
455  
    system::error_code ec;
455  
    system::error_code ec;
456  

456  

457  
    auto str = jv.if_string();
457  
    auto str = jv.if_string();
458  
    if( !str )
458  
    if( !str )
459  
    {
459  
    {
460  
        BOOST_JSON_FAIL(ec, error::not_string);
460  
        BOOST_JSON_FAIL(ec, error::not_string);
461  
        return {system::in_place_error, ec};
461  
        return {system::in_place_error, ec};
462  
    }
462  
    }
463  

463  

464  
    if( !describe::enum_from_string(str->data(), val) )
464  
    if( !describe::enum_from_string(str->data(), val) )
465  
    {
465  
    {
466  
        BOOST_JSON_FAIL(ec, error::unknown_name);
466  
        BOOST_JSON_FAIL(ec, error::unknown_name);
467  
        return {system::in_place_error, ec};
467  
        return {system::in_place_error, ec};
468  
    }
468  
    }
469  
#endif
469  
#endif
470  

470  

471  
    return {system::in_place_value, val};
471  
    return {system::in_place_value, val};
472  
}
472  
}
473  

473  

474  
// optionals
474  
// optionals
475  
template< class T, class Ctx >
475  
template< class T, class Ctx >
476  
system::result<T>
476  
system::result<T>
477  
value_to_impl(
477  
value_to_impl(
478  
    optional_conversion_tag,
478  
    optional_conversion_tag,
479  
    try_value_to_tag<T>,
479  
    try_value_to_tag<T>,
480  
    value const& jv,
480  
    value const& jv,
481  
    Ctx const& ctx)
481  
    Ctx const& ctx)
482  
{
482  
{
483  
    using Inner = value_result_type<T>;
483  
    using Inner = value_result_type<T>;
484  
    if( jv.is_null() )
484  
    if( jv.is_null() )
485  
        return {};
485  
        return {};
486  
    else
486  
    else
487  
        return try_value_to<Inner>(jv, ctx);
487  
        return try_value_to<Inner>(jv, ctx);
488  
}
488  
}
489  

489  

490  
// variants
490  
// variants
491  
template< class T, class V, class I >
491  
template< class T, class V, class I >
492  
using variant_construction_category = mp11::mp_cond<
492  
using variant_construction_category = mp11::mp_cond<
493  
    std::is_constructible< T, variant2::in_place_index_t<I::value>, V >,
493  
    std::is_constructible< T, variant2::in_place_index_t<I::value>, V >,
494  
        mp11::mp_int<2>,
494  
        mp11::mp_int<2>,
495  
#ifndef BOOST_NO_CXX17_HDR_VARIANT
495  
#ifndef BOOST_NO_CXX17_HDR_VARIANT
496  
    std::is_constructible< T, std::in_place_index_t<I::value>, V >,
496  
    std::is_constructible< T, std::in_place_index_t<I::value>, V >,
497  
        mp11::mp_int<1>,
497  
        mp11::mp_int<1>,
498  
#endif // BOOST_NO_CXX17_HDR_VARIANT
498  
#endif // BOOST_NO_CXX17_HDR_VARIANT
499  
    mp11::mp_true,
499  
    mp11::mp_true,
500  
        mp11::mp_int<0> >;
500  
        mp11::mp_int<0> >;
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<0> )
504  
initialize_variant( V&& v, mp11::mp_int<0> )
505  
{
505  
{
506  
    T t;
506  
    T t;
507  
    t.template emplace<I::value>( std::move(v) );
507  
    t.template emplace<I::value>( std::move(v) );
508  
    return t;
508  
    return t;
509  
}
509  
}
510  

510  

511  
template< class T, class I, class V >
511  
template< class T, class I, class V >
512  
T
512  
T
513  
initialize_variant( V&& v, mp11::mp_int<2> )
513  
initialize_variant( V&& v, mp11::mp_int<2> )
514  
{
514  
{
515  
    return T( variant2::in_place_index_t<I::value>(), std::move(v) );
515  
    return T( variant2::in_place_index_t<I::value>(), std::move(v) );
516  
}
516  
}
517  

517  

518  
#ifndef BOOST_NO_CXX17_HDR_VARIANT
518  
#ifndef BOOST_NO_CXX17_HDR_VARIANT
519  
template< class T, class I, class V >
519  
template< class T, class I, class V >
520  
T
520  
T
521  
initialize_variant( V&& v, mp11::mp_int<1> )
521  
initialize_variant( V&& v, mp11::mp_int<1> )
522  
{
522  
{
523  
    return T( std::in_place_index_t<I::value>(), std::move(v) );
523  
    return T( std::in_place_index_t<I::value>(), std::move(v) );
524  
}
524  
}
525  
#endif // BOOST_NO_CXX17_HDR_VARIANT
525  
#endif // BOOST_NO_CXX17_HDR_VARIANT
526  

526  

527  

527  

528  
template< class T, class Ctx >
528  
template< class T, class Ctx >
529  
struct alternative_converter
529  
struct alternative_converter
530  
{
530  
{
531  
    system::result<T>& res;
531  
    system::result<T>& res;
532  
    value const& jv;
532  
    value const& jv;
533  
    Ctx const& ctx;
533  
    Ctx const& ctx;
534  

534  

535  
    template< class I >
535  
    template< class I >
536  
    void operator()( I ) const
536  
    void operator()( I ) const
537  
    {
537  
    {
538  
        if( res )
538  
        if( res )
539  
            return;
539  
            return;
540  

540  

541  
        using V = mp11::mp_at<T, I>;
541  
        using V = mp11::mp_at<T, I>;
542  
        auto attempt = try_value_to<V>(jv, ctx);
542  
        auto attempt = try_value_to<V>(jv, ctx);
543  
        if( attempt )
543  
        if( attempt )
544  
        {
544  
        {
545  
            using cat = variant_construction_category<T, V, I>;
545  
            using cat = variant_construction_category<T, V, I>;
546  
            res = initialize_variant<T, I>( std::move(*attempt), cat() );
546  
            res = initialize_variant<T, I>( std::move(*attempt), cat() );
547  
        }
547  
        }
548  
    }
548  
    }
549  
};
549  
};
550  

550  

551  
template< class T, class Ctx >
551  
template< class T, class Ctx >
552  
system::result<T>
552  
system::result<T>
553  
value_to_impl(
553  
value_to_impl(
554  
    variant_conversion_tag,
554  
    variant_conversion_tag,
555  
    try_value_to_tag<T>,
555  
    try_value_to_tag<T>,
556  
    value const& jv,
556  
    value const& jv,
557  
    Ctx const& ctx)
557  
    Ctx const& ctx)
558  
{
558  
{
559  
    system::error_code ec;
559  
    system::error_code ec;
560  
    BOOST_JSON_FAIL(ec, error::exhausted_variants);
560  
    BOOST_JSON_FAIL(ec, error::exhausted_variants);
561  

561  

562  
    using Is = mp11::mp_iota< mp11::mp_size<T> >;
562  
    using Is = mp11::mp_iota< mp11::mp_size<T> >;
563  

563  

564  
    system::result<T> res = {system::in_place_error, ec};
564  
    system::result<T> res = {system::in_place_error, ec};
565  
    mp11::mp_for_each<Is>( alternative_converter<T, Ctx>{res, jv, ctx} );
565  
    mp11::mp_for_each<Is>( alternative_converter<T, Ctx>{res, jv, ctx} );
566  
    return res;
566  
    return res;
567  
}
567  
}
568  

568  

569  
template< class T, class Ctx >
569  
template< class T, class Ctx >
570  
system::result<T>
570  
system::result<T>
571  
value_to_impl(
571  
value_to_impl(
572  
    path_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
572  
    path_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
573  
{
573  
{
574  
    auto str = jv.if_string();
574  
    auto str = jv.if_string();
575  
    if( !str )
575  
    if( !str )
576  
    {
576  
    {
577  
        system::error_code ec;
577  
        system::error_code ec;
578  
        BOOST_JSON_FAIL(ec, error::not_string);
578  
        BOOST_JSON_FAIL(ec, error::not_string);
579  
        return {boost::system::in_place_error, ec};
579  
        return {boost::system::in_place_error, ec};
580  
    }
580  
    }
581  

581  

582  
    string_view sv = str->subview();
582  
    string_view sv = str->subview();
583  
    return {boost::system::in_place_value, T( sv.begin(), sv.end() )};
583  
    return {boost::system::in_place_value, T( sv.begin(), sv.end() )};
584  
}
584  
}
585  

585  

586  
//----------------------------------------------------------
586  
//----------------------------------------------------------
587  
// User-provided conversions; throwing -> throwing
587  
// User-provided conversions; throwing -> throwing
588  
template< class T, class Ctx >
588  
template< class T, class Ctx >
589  
mp11::mp_if< mp11::mp_valid<has_user_conversion_to_impl, T>, T >
589  
mp11::mp_if< mp11::mp_valid<has_user_conversion_to_impl, T>, T >
590  
value_to_impl(
590  
value_to_impl(
591  
    user_conversion_tag, value_to_tag<T> tag, value const& jv, Ctx const&)
591  
    user_conversion_tag, value_to_tag<T> tag, value const& jv, Ctx const&)
592  
{
592  
{
593  
    return tag_invoke(tag, jv);
593  
    return tag_invoke(tag, jv);
594  
}
594  
}
595  

595  

596  
template<
596  
template<
597  
    class T,
597  
    class T,
598  
    class Ctx,
598  
    class Ctx,
599  
    class Sup = supported_context<Ctx, T, value_to_conversion>
599  
    class Sup = supported_context<Ctx, T, value_to_conversion>
600  
>
600  
>
601  
mp11::mp_if<
601  
mp11::mp_if<
602  
    mp11::mp_valid< has_context_conversion_to_impl, typename Sup::type, T>, T >
602  
    mp11::mp_valid< has_context_conversion_to_impl, typename Sup::type, T>, T >
603  
value_to_impl(
603  
value_to_impl(
604  
    context_conversion_tag,
604  
    context_conversion_tag,
605  
    value_to_tag<T> tag,
605  
    value_to_tag<T> tag,
606  
    value const& jv,
606  
    value const& jv,
607  
    Ctx const& ctx )
607  
    Ctx const& ctx )
608  
{
608  
{
609  
    return tag_invoke( tag, jv, Sup::get(ctx) );
609  
    return tag_invoke( tag, jv, Sup::get(ctx) );
610  
}
610  
}
611  

611  

612  
template<
612  
template<
613  
    class T,
613  
    class T,
614  
    class Ctx,
614  
    class Ctx,
615  
    class Sup = supported_context<Ctx, T, value_to_conversion>
615  
    class Sup = supported_context<Ctx, T, value_to_conversion>
616  
>
616  
>
617  
mp11::mp_if<
617  
mp11::mp_if<
618  
    mp11::mp_valid<
618  
    mp11::mp_valid<
619  
        has_full_context_conversion_to_impl, typename Sup::type, T>,
619  
        has_full_context_conversion_to_impl, typename Sup::type, T>,
620  
    T>
620  
    T>
621  
value_to_impl(
621  
value_to_impl(
622  
    full_context_conversion_tag,
622  
    full_context_conversion_tag,
623  
    value_to_tag<T> tag,
623  
    value_to_tag<T> tag,
624  
    value const& jv,
624  
    value const& jv,
625  
    Ctx const& ctx )
625  
    Ctx const& ctx )
626  
{
626  
{
627  
    return tag_invoke( tag, jv, Sup::get(ctx), ctx );
627  
    return tag_invoke( tag, jv, Sup::get(ctx), ctx );
628  
}
628  
}
629  

629  

630  
//----------------------------------------------------------
630  
//----------------------------------------------------------
631  
// User-provided conversions; throwing -> nonthrowing
631  
// User-provided conversions; throwing -> nonthrowing
632  
template< class T, class Ctx >
632  
template< class T, class Ctx >
633  
mp11::mp_if_c< !mp11::mp_valid<has_user_conversion_to_impl, T>::value, T>
633  
mp11::mp_if_c< !mp11::mp_valid<has_user_conversion_to_impl, T>::value, T>
634  
value_to_impl(
634  
value_to_impl(
635  
    user_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& )
635  
    user_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& )
636  
{
636  
{
637  
    auto res = tag_invoke(try_value_to_tag<T>(), jv);
637  
    auto res = tag_invoke(try_value_to_tag<T>(), jv);
638  
    if( res.has_error() )
638  
    if( res.has_error() )
639  
        throw_system_error( res.error() );
639  
        throw_system_error( res.error() );
640  
    return std::move(*res);
640  
    return std::move(*res);
641  
}
641  
}
642  

642  

643  
template<
643  
template<
644  
    class T,
644  
    class T,
645  
    class Ctx,
645  
    class Ctx,
646  
    class Sup = supported_context<Ctx, T, value_to_conversion>
646  
    class Sup = supported_context<Ctx, T, value_to_conversion>
647  
>
647  
>
648  
mp11::mp_if_c<
648  
mp11::mp_if_c<
649  
    !mp11::mp_valid<
649  
    !mp11::mp_valid<
650  
        has_context_conversion_to_impl, typename Sup::type, T>::value,
650  
        has_context_conversion_to_impl, typename Sup::type, T>::value,
651  
    T>
651  
    T>
652  
value_to_impl(
652  
value_to_impl(
653  
    context_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& ctx )
653  
    context_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& ctx )
654  
{
654  
{
655  
    auto res = tag_invoke( try_value_to_tag<T>(), jv, Sup::get(ctx) );
655  
    auto res = tag_invoke( try_value_to_tag<T>(), jv, Sup::get(ctx) );
656  
    if( res.has_error() )
656  
    if( res.has_error() )
657  
        throw_system_error( res.error() );
657  
        throw_system_error( res.error() );
658  
    return std::move(*res);
658  
    return std::move(*res);
659  
}
659  
}
660  

660  

661  
template<
661  
template<
662  
    class T,
662  
    class T,
663  
    class Ctx,
663  
    class Ctx,
664  
    class Sup = supported_context<Ctx, T, value_to_conversion>
664  
    class Sup = supported_context<Ctx, T, value_to_conversion>
665  
>
665  
>
666  
mp11::mp_if_c<
666  
mp11::mp_if_c<
667  
    !mp11::mp_valid<
667  
    !mp11::mp_valid<
668  
        has_full_context_conversion_to_impl, typename Sup::type, T>::value,
668  
        has_full_context_conversion_to_impl, typename Sup::type, T>::value,
669  
    T>
669  
    T>
670  
value_to_impl(
670  
value_to_impl(
671  
    full_context_conversion_tag,
671  
    full_context_conversion_tag,
672  
    value_to_tag<T>,
672  
    value_to_tag<T>,
673  
    value const& jv,
673  
    value const& jv,
674  
    Ctx const& ctx )
674  
    Ctx const& ctx )
675  
{
675  
{
676  
    auto res = tag_invoke(try_value_to_tag<T>(), jv, Sup::get(ctx), ctx);
676  
    auto res = tag_invoke(try_value_to_tag<T>(), jv, Sup::get(ctx), ctx);
677  
    if( res.has_error() )
677  
    if( res.has_error() )
678  
        throw_system_error( res.error() );
678  
        throw_system_error( res.error() );
679  
    return std::move(*res);
679  
    return std::move(*res);
680  
}
680  
}
681  

681  

682  
//----------------------------------------------------------
682  
//----------------------------------------------------------
683  
// User-provided conversions; nonthrowing -> nonthrowing
683  
// User-provided conversions; nonthrowing -> nonthrowing
684  
template< class T, class Ctx >
684  
template< class T, class Ctx >
685  
mp11::mp_if<
685  
mp11::mp_if<
686  
    mp11::mp_valid<
686  
    mp11::mp_valid<
687  
        has_nonthrowing_user_conversion_to_impl, T>, system::result<T> >
687  
        has_nonthrowing_user_conversion_to_impl, T>, system::result<T> >
688  
value_to_impl(
688  
value_to_impl(
689  
    user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
689  
    user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
690  
{
690  
{
691  
    return tag_invoke(try_value_to_tag<T>(), jv);
691  
    return tag_invoke(try_value_to_tag<T>(), jv);
692  
}
692  
}
693  

693  

694  
template<
694  
template<
695  
    class T,
695  
    class T,
696  
    class Ctx,
696  
    class Ctx,
697  
    class Sup = supported_context<Ctx, T, value_to_conversion>
697  
    class Sup = supported_context<Ctx, T, value_to_conversion>
698  
>
698  
>
699  
mp11::mp_if<
699  
mp11::mp_if<
700  
    mp11::mp_valid<
700  
    mp11::mp_valid<
701  
        has_nonthrowing_context_conversion_to_impl, typename Sup::type, T>,
701  
        has_nonthrowing_context_conversion_to_impl, typename Sup::type, T>,
702  
    system::result<T> >
702  
    system::result<T> >
703  
value_to_impl(
703  
value_to_impl(
704  
    context_conversion_tag,
704  
    context_conversion_tag,
705  
    try_value_to_tag<T> tag,
705  
    try_value_to_tag<T> tag,
706  
    value const& jv,
706  
    value const& jv,
707  
    Ctx const& ctx )
707  
    Ctx const& ctx )
708  
{
708  
{
709  
    return tag_invoke( tag, jv, Sup::get(ctx) );
709  
    return tag_invoke( tag, jv, Sup::get(ctx) );
710  
}
710  
}
711  

711  

712  
template<
712  
template<
713  
    class T,
713  
    class T,
714  
    class Ctx,
714  
    class Ctx,
715  
    class Sup = supported_context<Ctx, T, value_to_conversion>
715  
    class Sup = supported_context<Ctx, T, value_to_conversion>
716  
>
716  
>
717  
mp11::mp_if<
717  
mp11::mp_if<
718  
    mp11::mp_valid<
718  
    mp11::mp_valid<
719  
        has_nonthrowing_full_context_conversion_to_impl,
719  
        has_nonthrowing_full_context_conversion_to_impl,
720  
        typename Sup::type,
720  
        typename Sup::type,
721  
        T>,
721  
        T>,
722  
    system::result<T> >
722  
    system::result<T> >
723  
value_to_impl(
723  
value_to_impl(
724  
    full_context_conversion_tag,
724  
    full_context_conversion_tag,
725  
    try_value_to_tag<T> tag,
725  
    try_value_to_tag<T> tag,
726  
    value const& jv,
726  
    value const& jv,
727  
    Ctx const& ctx )
727  
    Ctx const& ctx )
728  
{
728  
{
729  
    return tag_invoke( tag, jv, Sup::get(ctx), ctx );
729  
    return tag_invoke( tag, jv, Sup::get(ctx), ctx );
730  
}
730  
}
731  

731  

732  
//----------------------------------------------------------
732  
//----------------------------------------------------------
733  
// User-provided conversions; nonthrowing -> throwing
733  
// User-provided conversions; nonthrowing -> throwing
734  

734  

735  
template< class T, class... Args >
735  
template< class T, class... Args >
736  
system::result<T>
736  
system::result<T>
737  
wrap_conversion_exceptions( value_to_tag<T>, Args&& ... args )
737  
wrap_conversion_exceptions( value_to_tag<T>, Args&& ... args )
738  
{
738  
{
739  
#ifndef BOOST_NO_EXCEPTIONS
739  
#ifndef BOOST_NO_EXCEPTIONS
740  
    try
740  
    try
741  
    {
741  
    {
742  
#endif
742  
#endif
743  
        return {
743  
        return {
744  
            boost::system::in_place_value,
744  
            boost::system::in_place_value,
745  
            tag_invoke( value_to_tag<T>(), static_cast<Args&&>(args)... )};
745  
            tag_invoke( value_to_tag<T>(), static_cast<Args&&>(args)... )};
746  
#ifndef BOOST_NO_EXCEPTIONS
746  
#ifndef BOOST_NO_EXCEPTIONS
747  
    }
747  
    }
748  
    catch( std::bad_alloc const&)
748  
    catch( std::bad_alloc const&)
749  
    {
749  
    {
750  
        throw;
750  
        throw;
751  
    }
751  
    }
752  
    catch( system::system_error const& e)
752  
    catch( system::system_error const& e)
753  
    {
753  
    {
754  
        return {boost::system::in_place_error, e.code()};
754  
        return {boost::system::in_place_error, e.code()};
755  
    }
755  
    }
756  
    catch( ... )
756  
    catch( ... )
757  
    {
757  
    {
758  
        system::error_code ec;
758  
        system::error_code ec;
759  
        BOOST_JSON_FAIL(ec, error::exception);
759  
        BOOST_JSON_FAIL(ec, error::exception);
760  
        return {boost::system::in_place_error, ec};
760  
        return {boost::system::in_place_error, ec};
761  
    }
761  
    }
762  
#endif
762  
#endif
763  
}
763  
}
764  

764  

765  
template< class T, class Ctx >
765  
template< class T, class Ctx >
766  
mp11::mp_if_c<
766  
mp11::mp_if_c<
767  
    !mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>::value,
767  
    !mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>::value,
768  
    system::result<T> >
768  
    system::result<T> >
769  
value_to_impl(
769  
value_to_impl(
770  
    user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
770  
    user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
771  
{
771  
{
772  
    return wrap_conversion_exceptions(value_to_tag<T>(), jv);
772  
    return wrap_conversion_exceptions(value_to_tag<T>(), jv);
773  
}
773  
}
774  

774  

775  
template<
775  
template<
776  
    class T,
776  
    class T,
777  
    class Ctx,
777  
    class Ctx,
778  
    class Sup = supported_context<Ctx, T, value_to_conversion>
778  
    class Sup = supported_context<Ctx, T, value_to_conversion>
779  
>
779  
>
780  
mp11::mp_if_c<
780  
mp11::mp_if_c<
781  
    !mp11::mp_valid<
781  
    !mp11::mp_valid<
782  
        has_nonthrowing_context_conversion_to_impl,
782  
        has_nonthrowing_context_conversion_to_impl,
783  
        typename Sup::type,
783  
        typename Sup::type,
784  
        T>::value,
784  
        T>::value,
785  
    system::result<T> >
785  
    system::result<T> >
786  
value_to_impl(
786  
value_to_impl(
787  
    context_conversion_tag,
787  
    context_conversion_tag,
788  
    try_value_to_tag<T>,
788  
    try_value_to_tag<T>,
789  
    value const& jv,
789  
    value const& jv,
790  
    Ctx const& ctx )
790  
    Ctx const& ctx )
791  
{
791  
{
792  
    return wrap_conversion_exceptions( value_to_tag<T>(), jv, Sup::get(ctx) );
792  
    return wrap_conversion_exceptions( value_to_tag<T>(), jv, Sup::get(ctx) );
793  
}
793  
}
794  

794  

795  
template<
795  
template<
796  
    class T,
796  
    class T,
797  
    class Ctx,
797  
    class Ctx,
798  
    class Sup = supported_context<Ctx, T, value_to_conversion>
798  
    class Sup = supported_context<Ctx, T, value_to_conversion>
799  
>
799  
>
800  
mp11::mp_if_c<
800  
mp11::mp_if_c<
801  
    !mp11::mp_valid<
801  
    !mp11::mp_valid<
802  
        has_nonthrowing_full_context_conversion_to_impl,
802  
        has_nonthrowing_full_context_conversion_to_impl,
803  
        typename Sup::type,
803  
        typename Sup::type,
804  
        T>::value,
804  
        T>::value,
805  
    system::result<T> >
805  
    system::result<T> >
806  
value_to_impl(
806  
value_to_impl(
807  
    full_context_conversion_tag,
807  
    full_context_conversion_tag,
808  
    try_value_to_tag<T>,
808  
    try_value_to_tag<T>,
809  
    value const& jv,
809  
    value const& jv,
810  
    Ctx const& ctx )
810  
    Ctx const& ctx )
811  
{
811  
{
812  
    return wrap_conversion_exceptions(
812  
    return wrap_conversion_exceptions(
813  
        value_to_tag<T>(), jv, Sup::get(ctx), ctx);
813  
        value_to_tag<T>(), jv, Sup::get(ctx), ctx);
814  
}
814  
}
815  

815  

816  
// no suitable conversion implementation
816  
// no suitable conversion implementation
817  
template< class T, class Ctx >
817  
template< class T, class Ctx >
818  
T
818  
T
819  
value_to_impl( no_conversion_tag, value_to_tag<T>, value const&, Ctx const& )
819  
value_to_impl( no_conversion_tag, value_to_tag<T>, value const&, Ctx const& )
820  
{
820  
{
821  
    static_assert(
821  
    static_assert(
822  
        !std::is_same<T, T>::value,
822  
        !std::is_same<T, T>::value,
823  
        "No suitable tag_invoke overload found for the type");
823  
        "No suitable tag_invoke overload found for the type");
824  
}
824  
}
825  

825  

826  
// generic wrapper over non-throwing implementations
826  
// generic wrapper over non-throwing implementations
827  
template< class Impl, class T, class Ctx >
827  
template< class Impl, class T, class Ctx >
828  
T
828  
T
829  
value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx )
829  
value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx )
830  
{
830  
{
831  
    return value_to_impl(impl, try_value_to_tag<T>(), jv, ctx).value();
831  
    return value_to_impl(impl, try_value_to_tag<T>(), jv, ctx).value();
832  
}
832  
}
833  

833  

834  
template< class Ctx, class T >
834  
template< class Ctx, class T >
835  
using value_to_category = conversion_category<
835  
using value_to_category = conversion_category<
836  
    Ctx, T, value_to_conversion >;
836  
    Ctx, T, value_to_conversion >;
837  

837  

838  
} // detail
838  
} // detail
839  

839  

840  
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
840  
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
841  
inline
841  
inline
842  
system::result<std::nullopt_t>
842  
system::result<std::nullopt_t>
843  
tag_invoke(
843  
tag_invoke(
844  
    try_value_to_tag<std::nullopt_t>,
844  
    try_value_to_tag<std::nullopt_t>,
845  
    value const& jv)
845  
    value const& jv)
846  
{
846  
{
847  
    if( jv.is_null() )
847  
    if( jv.is_null() )
848  
        return std::nullopt;
848  
        return std::nullopt;
849  
    system::error_code ec;
849  
    system::error_code ec;
850  
    BOOST_JSON_FAIL(ec, error::not_null);
850  
    BOOST_JSON_FAIL(ec, error::not_null);
851  
    return ec;
851  
    return ec;
852  
}
852  
}
853  
#endif
853  
#endif
854  

854  

855  
} // namespace json
855  
} // namespace json
856  
} // namespace boost
856  
} // namespace boost
857  

857  

858  
#endif
858  
#endif