100.00% Lines (158/158) 100.00% Functions (23/23)
TLA Baseline Branch
Line Hits Code Line Hits Code
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
HITCBC 42   41 try_reserve( 42   41 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   {
HITCBC 47   41 constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value; 47   41 constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
HITCBC 48   41 if ( N != size ) 48   41 if ( N != size )
HITCBC 49   30 return error::size_mismatch; 49   30 return error::size_mismatch;
HITCBC 50   11 return error(); 50   11 return error();
51   } 51   }
52   52  
53   template<typename T> 53   template<typename T>
54   error 54   error
HITCBC 55   74 try_reserve( 55   74 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   {
HITCBC 60   74 cont.reserve(size); 60   74 cont.reserve(size);
HITCBC 61   74 return error(); 61   74 return error();
62   } 62   }
63   63  
64   template<typename T> 64   template<typename T>
65   error 65   error
HITCBC 66   57 try_reserve( 66   57 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   {
HITCBC 71   57 return error(); 71   57 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>
HITCBC 98   12 value_to_impl( 98   12 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   {
HITCBC 104   12 object const* obj = jv.if_object(); 104   12 object const* obj = jv.if_object();
HITCBC 105   12 if( obj ) 105   12 if( obj )
HITCBC 106   6 return *obj; 106   6 return *obj;
HITCBC 107   6 system::error_code ec; 107   6 system::error_code ec;
HITCBC 108   6 BOOST_JSON_FAIL(ec, error::not_object); 108   6 BOOST_JSON_FAIL(ec, error::not_object);
HITCBC 109   6 return ec; 109   6 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>
HITCBC 115   12 value_to_impl( 115   12 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   {
HITCBC 121   12 array const* arr = jv.if_array(); 121   12 array const* arr = jv.if_array();
HITCBC 122   12 if( arr ) 122   12 if( arr )
HITCBC 123   6 return *arr; 123   6 return *arr;
HITCBC 124   6 system::error_code ec; 124   6 system::error_code ec;
HITCBC 125   6 BOOST_JSON_FAIL(ec, error::not_array); 125   6 BOOST_JSON_FAIL(ec, error::not_array);
HITCBC 126   6 return ec; 126   6 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>
HITCBC 132   12 value_to_impl( 132   12 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   {
HITCBC 138   12 string const* str = jv.if_string(); 138   12 string const* str = jv.if_string();
HITCBC 139   12 if( str ) 139   12 if( str )
HITCBC 140   6 return *str; 140   6 return *str;
HITCBC 141   6 system::error_code ec; 141   6 system::error_code ec;
HITCBC 142   6 BOOST_JSON_FAIL(ec, error::not_string); 142   6 BOOST_JSON_FAIL(ec, error::not_string);
HITCBC 143   6 return ec; 143   6 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>
HITCBC 149   49 value_to_impl( 149   49 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   {
HITCBC 152   49 auto b = jv.if_bool(); 152   49 auto b = jv.if_bool();
HITCBC 153   49 if( b ) 153   49 if( b )
HITCBC 154   42 return *b; 154   42 return *b;
HITCBC 155   7 system::error_code ec; 155   7 system::error_code ec;
HITCBC 156   7 BOOST_JSON_FAIL(ec, error::not_bool); 156   7 BOOST_JSON_FAIL(ec, error::not_bool);
HITCBC 157   7 return {boost::system::in_place_error, ec}; 157   7 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>
HITCBC 163   3396 value_to_impl( 163   3396 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   {
HITCBC 166   3396 system::error_code ec; 166   3396 system::error_code ec;
HITCBC 167   3396 auto const n = jv.to_number<T>(ec); 167   3396 auto const n = jv.to_number<T>(ec);
HITCBC 168   3396 if( ec.failed() ) 168   3396 if( ec.failed() )
HITCBC 169   55 return {boost::system::in_place_error, ec}; 169   55 return {boost::system::in_place_error, ec};
HITCBC 170   3341 return {boost::system::in_place_value, n}; 170   3341 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>
HITCBC 176   56 value_to_impl( 176   56 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   {
HITCBC 182   56 if( jv.is_null() ) 182   56 if( jv.is_null() )
HITCBC 183   35 return {boost::system::in_place_value, T{}}; 183   35 return {boost::system::in_place_value, T{}};
HITCBC 184   21 system::error_code ec; 184   21 system::error_code ec;
HITCBC 185   21 BOOST_JSON_FAIL(ec, error::not_null); 185   21 BOOST_JSON_FAIL(ec, error::not_null);
HITCBC 186   21 return {boost::system::in_place_error, ec}; 186   21 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>
HITCBC 192   79 value_to_impl( 192   79 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   {
HITCBC 198   79 auto str = jv.if_string(); 198   79 auto str = jv.if_string();
HITCBC 199   79 if( str ) 199   79 if( str )
HITCBC 200   67 return {boost::system::in_place_value, T(str->subview())}; 200   67 return {boost::system::in_place_value, T(str->subview())};
HITCBC 201   12 system::error_code ec; 201   12 system::error_code ec;
HITCBC 202   12 BOOST_JSON_FAIL(ec, error::not_string); 202   12 BOOST_JSON_FAIL(ec, error::not_string);
HITCBC 203   12 return {boost::system::in_place_error, ec}; 203   12 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>
HITCBC 209   74 value_to_impl( 209   74 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   {
HITCBC 215   74 object const* obj = jv.if_object(); 215   74 object const* obj = jv.if_object();
HITCBC 216   74 if( !obj ) 216   74 if( !obj )
217   { 217   {
HITCBC 218   12 system::error_code ec; 218   12 system::error_code ec;
HITCBC 219   12 BOOST_JSON_FAIL(ec, error::not_object); 219   12 BOOST_JSON_FAIL(ec, error::not_object);
HITCBC 220   12 return {boost::system::in_place_error, ec}; 220   12 return {boost::system::in_place_error, ec};
221   } 221   }
222   222  
HITCBC 223   62 T res; 223   62 T res;
HITCBC 224   62 error const e = detail::try_reserve( 224   62 error const e = detail::try_reserve(
225   res, obj->size(), reserve_implementation<T>()); 225   res, obj->size(), reserve_implementation<T>());
HITCBC 226   62 if( e != error() ) 226   62 if( e != error() )
227   { 227   {
HITCBC 228   12 system::error_code ec; 228   12 system::error_code ec;
HITCBC 229   12 BOOST_JSON_FAIL( ec, e ); 229   12 BOOST_JSON_FAIL( ec, e );
HITCBC 230   12 return {boost::system::in_place_error, ec}; 230   12 return {boost::system::in_place_error, ec};
231   } 231   }
232   232  
HITCBC 233   50 auto ins = detail::inserter(res, inserter_implementation<T>()); 233   50 auto ins = detail::inserter(res, inserter_implementation<T>());
HITCBC 234   147 for( key_value_pair const& kv: *obj ) 234   147 for( key_value_pair const& kv: *obj )
235   { 235   {
HITCBC 236   104 auto elem_res = try_value_to<mapped_type<T>>( kv.value(), ctx ); 236   104 auto elem_res = try_value_to<mapped_type<T>>( kv.value(), ctx );
HITCBC 237   104 if( elem_res.has_error() ) 237   104 if( elem_res.has_error() )
HITCBC 238   13 return {boost::system::in_place_error, elem_res.error()}; 238   13 return {boost::system::in_place_error, elem_res.error()};
HITCBC 239   91 *ins++ = value_type<T>{ 239   91 *ins++ = value_type<T>{
HITCBC 240   182 key_type<T>(kv.key()), 240   182 key_type<T>(kv.key()),
HITCBC 241   91 std::move(*elem_res)}; 241   91 std::move(*elem_res)};
242   } 242   }
HITCBC 243   37 return res; 243   37 return res;
HITCBC 244   62 } 244   62 }
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>
HITCBC 249   119 value_to_impl( 249   119 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   {
HITCBC 255   119 array const* arr = jv.if_array(); 255   119 array const* arr = jv.if_array();
HITCBC 256   119 if( !arr ) 256   119 if( !arr )
257   { 257   {
HITCBC 258   12 system::error_code ec; 258   12 system::error_code ec;
HITCBC 259   12 BOOST_JSON_FAIL(ec, error::not_array); 259   12 BOOST_JSON_FAIL(ec, error::not_array);
HITCBC 260   12 return {boost::system::in_place_error, ec}; 260   12 return {boost::system::in_place_error, ec};
261   } 261   }
262   262  
HITCBC 263   79 T result; 263   79 T result;
HITCBC 264   107 error const e = detail::try_reserve( 264   107 error const e = detail::try_reserve(
265   result, arr->size(), reserve_implementation<T>()); 265   result, arr->size(), reserve_implementation<T>());
HITCBC 266   107 if( e != error() ) 266   107 if( e != error() )
267   { 267   {
HITCBC 268   18 system::error_code ec; 268   18 system::error_code ec;
HITCBC 269   18 BOOST_JSON_FAIL( ec, e ); 269   18 BOOST_JSON_FAIL( ec, e );
HITCBC 270   18 return {boost::system::in_place_error, ec}; 270   18 return {boost::system::in_place_error, ec};
271   } 271   }
272   272  
HITCBC 273   89 auto ins = detail::inserter(result, inserter_implementation<T>()); 273   89 auto ins = detail::inserter(result, inserter_implementation<T>());
HITCBC 274   3344 for( value const& val: *arr ) 274   3344 for( value const& val: *arr )
275   { 275   {
HITCBC 276   3229 auto elem_res = try_value_to<value_type<T>>( val, ctx ); 276   3229 auto elem_res = try_value_to<value_type<T>>( val, ctx );
HITCBC 277   3229 if( elem_res.has_error() ) 277   3229 if( elem_res.has_error() )
HITCBC 278   13 return {boost::system::in_place_error, elem_res.error()}; 278   13 return {boost::system::in_place_error, elem_res.error()};
HITCBC 279   3216 *ins++ = std::move(*elem_res); 279   3216 *ins++ = std::move(*elem_res);
280   } 280   }
HITCBC 281   76 return result; 281   76 return result;
HITCBC 282   79 } 282   79 }
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>
HITCBC 287   248 try_make_tuple_elem(value const& jv, Ctx const& ctx, system::error_code& ec) 287   248 try_make_tuple_elem(value const& jv, Ctx const& ctx, system::error_code& ec)
288   { 288   {
HITCBC 289   248 if( ec.failed() ) 289   248 if( ec.failed() )
HITCBC 290   38 return {boost::system::in_place_error, ec}; 290   38 return {boost::system::in_place_error, ec};
291   291  
HITCBC 292   210 auto result = try_value_to<T>( jv, ctx ); 292   210 auto result = try_value_to<T>( jv, ctx );
HITCBC 293   210 ec = result.error(); 293   210 ec = result.error();
HITCBC 294   210 return result; 294   210 return result;
HITCBC 295   57 } 295   57 }
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>
HITCBC 299   97 try_make_tuple_like( 299   97 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   {
HITCBC 302   97 system::error_code ec; 302   97 system::error_code ec;
HITCBC 303   115 auto items = std::make_tuple( 303   115 auto items = std::make_tuple(
304   try_make_tuple_elem< 304   try_make_tuple_elem<
HITCBC 305   117 typename std::decay<tuple_element_t<Is, T>>::type >( 305   117 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
HITCBC 312   97 if( ec.failed() ) 312   97 if( ec.failed() )
HITCBC 313   13 return {boost::system::in_place_error, ec}; 313   13 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,
HITCBC 324   87 T{ (std::move(*std::get<Is>(items)))... } 324   87 T{ (std::move(*std::get<Is>(items)))... }
HITCBC 325   87 }; 325   87 };
326   #if defined(BOOST_CLANG) 326   #if defined(BOOST_CLANG)
327   # pragma clang diagnostic pop 327   # pragma clang diagnostic pop
328   #endif 328   #endif
HITCBC 329   54 } 329   54 }
330   330  
331   template< class T, class Ctx > 331   template< class T, class Ctx >
332   system::result<T> 332   system::result<T>
HITCBC 333   121 value_to_impl( 333   121 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   {
HITCBC 339   121 system::error_code ec; 339   121 system::error_code ec;
340   340  
HITCBC 341   121 array const* arr = jv.if_array(); 341   121 array const* arr = jv.if_array();
HITCBC 342   121 if( !arr ) 342   121 if( !arr )
343   { 343   {
HITCBC 344   12 BOOST_JSON_FAIL(ec, error::not_array); 344   12 BOOST_JSON_FAIL(ec, error::not_array);
HITCBC 345   12 return {boost::system::in_place_error, ec}; 345   12 return {boost::system::in_place_error, ec};
346   } 346   }
347   347  
HITCBC 348   109 constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value; 348   109 constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
HITCBC 349   109 if( N != arr->size() ) 349   109 if( N != arr->size() )
350   { 350   {
HITCBC 351   12 BOOST_JSON_FAIL(ec, error::size_mismatch); 351   12 BOOST_JSON_FAIL(ec, error::size_mismatch);
HITCBC 352   12 return {boost::system::in_place_error, ec}; 352   12 return {boost::system::in_place_error, ec};
353   } 353   }
354   354  
HITCBC 355   37 return try_make_tuple_like<T>( 355   37 return try_make_tuple_like<T>(
HITCBC 356   97 *arr, ctx, boost::mp11::make_index_sequence<N>()); 356   97 *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 >
HITCBC 590   1 value_to_impl( 590   1 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   {
HITCBC 593   1 return tag_invoke(tag, jv); 593   1 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 >
HITCBC 603   1 value_to_impl( 603   1 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   {
HITCBC 609   1 return tag_invoke( tag, jv, Sup::get(ctx) ); 609   1 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>
HITCBC 634   60 value_to_impl( 634   60 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   {
HITCBC 637   60 auto res = tag_invoke(try_value_to_tag<T>(), jv); 637   60 auto res = tag_invoke(try_value_to_tag<T>(), jv);
HITCBC 638   60 if( res.has_error() ) 638   60 if( res.has_error() )
HITCBC 639   12 throw_system_error( res.error() ); 639   12 throw_system_error( res.error() );
HITCBC 640   96 return std::move(*res); 640   96 return std::move(*res);
HITCBC 641   32 } 641   32 }
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>
HITCBC 652   3 value_to_impl( 652   3 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   {
HITCBC 655   3 auto res = tag_invoke( try_value_to_tag<T>(), jv, Sup::get(ctx) ); 655   3 auto res = tag_invoke( try_value_to_tag<T>(), jv, Sup::get(ctx) );
HITCBC 656   3 if( res.has_error() ) 656   3 if( res.has_error() )
HITCBC 657   1 throw_system_error( res.error() ); 657   1 throw_system_error( res.error() );
HITCBC 658   4 return std::move(*res); 658   4 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> >
HITCBC 688   124 value_to_impl( 688   124 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   {
HITCBC 691   132 return tag_invoke(try_value_to_tag<T>(), jv); 691   132 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>
HITCBC 737   54 wrap_conversion_exceptions( value_to_tag<T>, Args&& ... args ) 737   54 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,
HITCBC 745   54 tag_invoke( value_to_tag<T>(), static_cast<Args&&>(args)... )}; 745   54 tag_invoke( value_to_tag<T>(), static_cast<Args&&>(args)... )};
746   #ifndef BOOST_NO_EXCEPTIONS 746   #ifndef BOOST_NO_EXCEPTIONS
747   } 747   }
HITCBC 748   30 catch( std::bad_alloc const&) 748   30 catch( std::bad_alloc const&)
749   { 749   {
HITCBC 750   6 throw; 750   6 throw;
751   } 751   }
HITCBC 752   12 catch( system::system_error const& e) 752   12 catch( system::system_error const& e)
753   { 753   {
HITCBC 754   12 return {boost::system::in_place_error, e.code()}; 754   12 return {boost::system::in_place_error, e.code()};
755   } 755   }
HITCBC 756   12 catch( ... ) 756   12 catch( ... )
757   { 757   {
HITCBC 758   6 system::error_code ec; 758   6 system::error_code ec;
HITCBC 759   6 BOOST_JSON_FAIL(ec, error::exception); 759   6 BOOST_JSON_FAIL(ec, error::exception);
HITCBC 760   6 return {boost::system::in_place_error, ec}; 760   6 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> >
HITCBC 769   54 value_to_impl( 769   54 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   {
HITCBC 772   54 return wrap_conversion_exceptions(value_to_tag<T>(), jv); 772   54 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
HITCBC 829   345 value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx ) 829   345 value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx )
830   { 830   {
HITCBC 831   345 return value_to_impl(impl, try_value_to_tag<T>(), jv, ctx).value(); 831   345 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