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 + json_value_category,
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 + json_value_category, 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 + json_object_category,
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 + json_array_category,
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 + json_string_category,
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 + boolean_category, 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 + template< class Cat, class T, class Ctx >
161 - template< class T, class Ctx >  
162   system::result<T> 161   system::result<T>
HITCBC 163   3396 value_to_impl( 162   3396 value_to_impl(
164 - number_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& ) 163 + Cat,
  164 + try_value_to_tag<T>,
  165 + value const& jv,
  166 + Ctx const&,
  167 + typename std::enable_if<
  168 + Cat::value == conversion_category::integer
  169 + || Cat::value == conversion_category::floating_point>::type* = nullptr
  170 + )
165   { 171   {
HITCBC 166   3396 system::error_code ec; 172   3396 system::error_code ec;
HITCBC 167   3396 auto const n = jv.to_number<T>(ec); 173   3396 auto const n = jv.to_number<T>(ec);
HITCBC 168   3396 if( ec.failed() ) 174   3396 if( ec.failed() )
HITCBC 169   55 return {boost::system::in_place_error, ec}; 175   55 return {boost::system::in_place_error, ec};
HITCBC 170   3341 return {boost::system::in_place_value, n}; 176   3341 return {boost::system::in_place_value, n};
171   } 177   }
172   178  
173   // null-like conversion 179   // null-like conversion
174   template< class T, class Ctx > 180   template< class T, class Ctx >
175   system::result<T> 181   system::result<T>
HITCBC 176   56 value_to_impl( 182   56 value_to_impl(
177 - null_like_conversion_tag, 183 + null_category,
178   try_value_to_tag<T>, 184   try_value_to_tag<T>,
179   value const& jv, 185   value const& jv,
180   Ctx const& ) 186   Ctx const& )
181   { 187   {
HITCBC 182   56 if( jv.is_null() ) 188   56 if( jv.is_null() )
HITCBC 183   35 return {boost::system::in_place_value, T{}}; 189   35 return {boost::system::in_place_value, T{}};
HITCBC 184   21 system::error_code ec; 190   21 system::error_code ec;
HITCBC 185   21 BOOST_JSON_FAIL(ec, error::not_null); 191   21 BOOST_JSON_FAIL(ec, error::not_null);
HITCBC 186   21 return {boost::system::in_place_error, ec}; 192   21 return {boost::system::in_place_error, ec};
187   } 193   }
188   194  
189   // string-like types 195   // string-like types
190   template< class T, class Ctx > 196   template< class T, class Ctx >
191   system::result<T> 197   system::result<T>
HITCBC 192   79 value_to_impl( 198   79 value_to_impl(
193 - string_like_conversion_tag, 199 + string_category, try_value_to_tag<T>, value const& jv, Ctx const& )
194 - try_value_to_tag<T>,  
195 - value const& jv,  
196 - Ctx const& )  
197   { 200   {
HITCBC 198   79 auto str = jv.if_string(); 201   79 auto str = jv.if_string();
HITCBC 199   79 if( str ) 202   79 if( str )
HITCBC 200   67 return {boost::system::in_place_value, T(str->subview())}; 203   67 return {boost::system::in_place_value, T(str->subview())};
HITCBC 201   12 system::error_code ec; 204   12 system::error_code ec;
HITCBC 202   12 BOOST_JSON_FAIL(ec, error::not_string); 205   12 BOOST_JSON_FAIL(ec, error::not_string);
HITCBC 203   12 return {boost::system::in_place_error, ec}; 206   12 return {boost::system::in_place_error, ec};
204   } 207   }
205   208  
206   // map-like containers 209   // map-like containers
207   template< class T, class Ctx > 210   template< class T, class Ctx >
208   system::result<T> 211   system::result<T>
HITCBC 209   74 value_to_impl( 212   74 value_to_impl(
210 - map_like_conversion_tag, 213 + map_category,
211   try_value_to_tag<T>, 214   try_value_to_tag<T>,
212   value const& jv, 215   value const& jv,
213   Ctx const& ctx ) 216   Ctx const& ctx )
214   { 217   {
HITCBC 215   74 object const* obj = jv.if_object(); 218   74 object const* obj = jv.if_object();
HITCBC 216   74 if( !obj ) 219   74 if( !obj )
217   { 220   {
HITCBC 218   12 system::error_code ec; 221   12 system::error_code ec;
HITCBC 219   12 BOOST_JSON_FAIL(ec, error::not_object); 222   12 BOOST_JSON_FAIL(ec, error::not_object);
HITCBC 220   12 return {boost::system::in_place_error, ec}; 223   12 return {boost::system::in_place_error, ec};
221   } 224   }
222   225  
HITCBC 223   62 T res; 226   62 T res;
HITCBC 224   62 error const e = detail::try_reserve( 227   62 error const e = detail::try_reserve(
225   res, obj->size(), reserve_implementation<T>()); 228   res, obj->size(), reserve_implementation<T>());
HITCBC 226   62 if( e != error() ) 229   62 if( e != error() )
227   { 230   {
HITCBC 228   12 system::error_code ec; 231   12 system::error_code ec;
HITCBC 229   12 BOOST_JSON_FAIL( ec, e ); 232   12 BOOST_JSON_FAIL( ec, e );
HITCBC 230   12 return {boost::system::in_place_error, ec}; 233   12 return {boost::system::in_place_error, ec};
231   } 234   }
232   235  
HITCBC 233   50 auto ins = detail::inserter(res, inserter_implementation<T>()); 236   50 auto ins = detail::inserter(res, inserter_implementation<T>());
HITCBC 234   147 for( key_value_pair const& kv: *obj ) 237   147 for( key_value_pair const& kv: *obj )
235   { 238   {
HITCBC 236   104 auto elem_res = try_value_to<mapped_type<T>>( kv.value(), ctx ); 239   104 auto elem_res = try_value_to<mapped_type<T>>( kv.value(), ctx );
HITCBC 237   104 if( elem_res.has_error() ) 240   104 if( elem_res.has_error() )
HITCBC 238   13 return {boost::system::in_place_error, elem_res.error()}; 241   13 return {boost::system::in_place_error, elem_res.error()};
HITCBC 239   91 *ins++ = value_type<T>{ 242   91 *ins++ = value_type<T>{
HITCBC 240   182 key_type<T>(kv.key()), 243   182 key_type<T>(kv.key()),
HITCBC 241   91 std::move(*elem_res)}; 244   91 std::move(*elem_res)};
242   } 245   }
HITCBC 243   37 return res; 246   37 return res;
HITCBC 244   62 } 247   62 }
245   248  
246   // all other containers 249   // all other containers
247   template< class T, class Ctx > 250   template< class T, class Ctx >
248   system::result<T> 251   system::result<T>
HITCBC 249   119 value_to_impl( 252   119 value_to_impl(
250 - sequence_conversion_tag, 253 + sequence_category, try_value_to_tag<T>, value const& jv, Ctx const& ctx )
251 - try_value_to_tag<T>,  
252 - value const& jv,  
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_category, try_value_to_tag<T>, value const& jv, Ctx const& ctx )
335 - try_value_to_tag<T>,  
336 - value const& jv,  
337 - Ctx const& ctx )  
338   { 335   {
HITCBC 339   121 system::error_code ec; 336   121 system::error_code ec;
340   337  
HITCBC 341   121 array const* arr = jv.if_array(); 338   121 array const* arr = jv.if_array();
HITCBC 342   121 if( !arr ) 339   121 if( !arr )
343   { 340   {
HITCBC 344   12 BOOST_JSON_FAIL(ec, error::not_array); 341   12 BOOST_JSON_FAIL(ec, error::not_array);
HITCBC 345   12 return {boost::system::in_place_error, ec}; 342   12 return {boost::system::in_place_error, ec};
346   } 343   }
347   344  
HITCBC 348   109 constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value; 345   109 constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
HITCBC 349   109 if( N != arr->size() ) 346   109 if( N != arr->size() )
350   { 347   {
HITCBC 351   12 BOOST_JSON_FAIL(ec, error::size_mismatch); 348   12 BOOST_JSON_FAIL(ec, error::size_mismatch);
HITCBC 352   12 return {boost::system::in_place_error, ec}; 349   12 return {boost::system::in_place_error, ec};
353   } 350   }
354   351  
HITCBC 355   37 return try_make_tuple_like<T>( 352   37 return try_make_tuple_like<T>(
HITCBC 356   97 *arr, ctx, boost::mp11::make_index_sequence<N>()); 353   97 *arr, ctx, boost::mp11::make_index_sequence<N>());
357   } 354   }
358   355  
359   template< class Ctx, class T > 356   template< class Ctx, class T >
360   struct to_described_member 357   struct to_described_member
361   { 358   {
362   static_assert( 359   static_assert(
363   uniquely_named_members<T>::value, 360   uniquely_named_members<T>::value,
364   "The type has several described members with the same name."); 361   "The type has several described members with the same name.");
365   362  
366   using Ds = described_members<T>; 363   using Ds = described_members<T>;
367   364  
368   system::result<T>& res; 365   system::result<T>& res;
369   object const& obj; 366   object const& obj;
370   Ctx const& ctx; 367   Ctx const& ctx;
371   368  
372   template< class I > 369   template< class I >
373   void 370   void
374   operator()(I) 371   operator()(I)
375   { 372   {
376   if( !res ) 373   if( !res )
377   return; 374   return;
378   375  
379   using D = mp11::mp_at<Ds, I>; 376   using D = mp11::mp_at<Ds, I>;
380   using M = described_member_t<T, D>; 377   using M = described_member_t<T, D>;
381   378  
382   auto const found = obj.find(D::name); 379   auto const found = obj.find(D::name);
383   if( found == obj.end() ) 380   if( found == obj.end() )
384   { 381   {
385   BOOST_IF_CONSTEXPR( !is_optional_like<M>::value ) 382   BOOST_IF_CONSTEXPR( !is_optional_like<M>::value )
386   { 383   {
387   system::error_code ec; 384   system::error_code ec;
388   BOOST_JSON_FAIL(ec, error::size_mismatch); 385   BOOST_JSON_FAIL(ec, error::size_mismatch);
389   res = {boost::system::in_place_error, ec}; 386   res = {boost::system::in_place_error, ec};
390   } 387   }
391   return; 388   return;
392   } 389   }
393   390  
394   #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000 391   #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
395   # pragma GCC diagnostic push 392   # pragma GCC diagnostic push
396   # pragma GCC diagnostic ignored "-Wunused" 393   # pragma GCC diagnostic ignored "-Wunused"
397   # pragma GCC diagnostic ignored "-Wunused-variable" 394   # pragma GCC diagnostic ignored "-Wunused-variable"
398   #endif 395   #endif
399   auto member_res = try_value_to<M>( found->value(), ctx ); 396   auto member_res = try_value_to<M>( found->value(), ctx );
400   #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000 397   #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
401   # pragma GCC diagnostic pop 398   # pragma GCC diagnostic pop
402   #endif 399   #endif
403   if( member_res ) 400   if( member_res )
404   (*res).* D::pointer = std::move(*member_res); 401   (*res).* D::pointer = std::move(*member_res);
405   else 402   else
406   res = {boost::system::in_place_error, member_res.error()}; 403   res = {boost::system::in_place_error, member_res.error()};
407   } 404   }
408   }; 405   };
409   406  
410   // described classes 407   // described classes
411   template< class T, class Ctx > 408   template< class T, class Ctx >
412   system::result<T> 409   system::result<T>
413   value_to_impl( 410   value_to_impl(
414 - described_class_conversion_tag, 411 + described_class_category,
415   try_value_to_tag<T>, 412   try_value_to_tag<T>,
416   value const& jv, 413   value const& jv,
417   Ctx const& ctx ) 414   Ctx const& ctx )
418   { 415   {
419   BOOST_CORE_STATIC_ASSERT( std::is_default_constructible<T>::value ); 416   BOOST_CORE_STATIC_ASSERT( std::is_default_constructible<T>::value );
420   system::result<T> res; 417   system::result<T> res;
421   418  
422   auto* obj = jv.if_object(); 419   auto* obj = jv.if_object();
423   if( !obj ) 420   if( !obj )
424   { 421   {
425   system::error_code ec; 422   system::error_code ec;
426   BOOST_JSON_FAIL(ec, error::not_object); 423   BOOST_JSON_FAIL(ec, error::not_object);
427   res = {boost::system::in_place_error, ec}; 424   res = {boost::system::in_place_error, ec};
428   return res; 425   return res;
429   } 426   }
430   427  
431   to_described_member<Ctx, T> member_converter{res, *obj, ctx}; 428   to_described_member<Ctx, T> member_converter{res, *obj, ctx};
432   429  
433   using Ds = typename decltype(member_converter)::Ds; 430   using Ds = typename decltype(member_converter)::Ds;
434   constexpr std::size_t N = mp11::mp_size<Ds>::value; 431   constexpr std::size_t N = mp11::mp_size<Ds>::value;
435   mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter); 432   mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
436   433  
437   if( !res ) 434   if( !res )
438   return res; 435   return res;
439   436  
440   return res; 437   return res;
441   } 438   }
442   439  
443   // described enums 440   // described enums
444   template< class T, class Ctx > 441   template< class T, class Ctx >
445   system::result<T> 442   system::result<T>
446   value_to_impl( 443   value_to_impl(
447 - described_enum_conversion_tag, 444 + described_enum_category,
448   try_value_to_tag<T>, 445   try_value_to_tag<T>,
449   value const& jv, 446   value const& jv,
450   Ctx const& ) 447   Ctx const& )
451   { 448   {
452   T val = {}; 449   T val = {};
453   (void)jv; 450   (void)jv;
454   #ifdef BOOST_DESCRIBE_CXX14 451   #ifdef BOOST_DESCRIBE_CXX14
455   system::error_code ec; 452   system::error_code ec;
456   453  
457   auto str = jv.if_string(); 454   auto str = jv.if_string();
458   if( !str ) 455   if( !str )
459   { 456   {
460   BOOST_JSON_FAIL(ec, error::not_string); 457   BOOST_JSON_FAIL(ec, error::not_string);
461   return {system::in_place_error, ec}; 458   return {system::in_place_error, ec};
462   } 459   }
463   460  
464   if( !describe::enum_from_string(str->data(), val) ) 461   if( !describe::enum_from_string(str->data(), val) )
465   { 462   {
466   BOOST_JSON_FAIL(ec, error::unknown_name); 463   BOOST_JSON_FAIL(ec, error::unknown_name);
467   return {system::in_place_error, ec}; 464   return {system::in_place_error, ec};
468   } 465   }
469   #endif 466   #endif
470   467  
471   return {system::in_place_value, val}; 468   return {system::in_place_value, val};
472   } 469   }
473   470  
474   // optionals 471   // optionals
475   template< class T, class Ctx > 472   template< class T, class Ctx >
476   system::result<T> 473   system::result<T>
477   value_to_impl( 474   value_to_impl(
478 - optional_conversion_tag, 475 + optional_category,
479   try_value_to_tag<T>, 476   try_value_to_tag<T>,
480   value const& jv, 477   value const& jv,
481   Ctx const& ctx) 478   Ctx const& ctx)
482   { 479   {
483   using Inner = value_result_type<T>; 480   using Inner = value_result_type<T>;
484   if( jv.is_null() ) 481   if( jv.is_null() )
485   return {}; 482   return {};
486   else 483   else
487   return try_value_to<Inner>(jv, ctx); 484   return try_value_to<Inner>(jv, ctx);
488   } 485   }
489   486  
490   // variants 487   // variants
491   template< class T, class V, class I > 488   template< class T, class V, class I >
492   using variant_construction_category = mp11::mp_cond< 489   using variant_construction_category = mp11::mp_cond<
493   std::is_constructible< T, variant2::in_place_index_t<I::value>, V >, 490   std::is_constructible< T, variant2::in_place_index_t<I::value>, V >,
494   mp11::mp_int<2>, 491   mp11::mp_int<2>,
495   #ifndef BOOST_NO_CXX17_HDR_VARIANT 492   #ifndef BOOST_NO_CXX17_HDR_VARIANT
496   std::is_constructible< T, std::in_place_index_t<I::value>, V >, 493   std::is_constructible< T, std::in_place_index_t<I::value>, V >,
497   mp11::mp_int<1>, 494   mp11::mp_int<1>,
498   #endif // BOOST_NO_CXX17_HDR_VARIANT 495   #endif // BOOST_NO_CXX17_HDR_VARIANT
499   mp11::mp_true, 496   mp11::mp_true,
500   mp11::mp_int<0> >; 497   mp11::mp_int<0> >;
501   498  
502   template< class T, class I, class V > 499   template< class T, class I, class V >
503   T 500   T
504   initialize_variant( V&& v, mp11::mp_int<0> ) 501   initialize_variant( V&& v, mp11::mp_int<0> )
505   { 502   {
506   T t; 503   T t;
507   t.template emplace<I::value>( std::move(v) ); 504   t.template emplace<I::value>( std::move(v) );
508   return t; 505   return t;
509   } 506   }
510   507  
511   template< class T, class I, class V > 508   template< class T, class I, class V >
512   T 509   T
513   initialize_variant( V&& v, mp11::mp_int<2> ) 510   initialize_variant( V&& v, mp11::mp_int<2> )
514   { 511   {
515   return T( variant2::in_place_index_t<I::value>(), std::move(v) ); 512   return T( variant2::in_place_index_t<I::value>(), std::move(v) );
516   } 513   }
517   514  
518   #ifndef BOOST_NO_CXX17_HDR_VARIANT 515   #ifndef BOOST_NO_CXX17_HDR_VARIANT
519   template< class T, class I, class V > 516   template< class T, class I, class V >
520   T 517   T
521   initialize_variant( V&& v, mp11::mp_int<1> ) 518   initialize_variant( V&& v, mp11::mp_int<1> )
522   { 519   {
523   return T( std::in_place_index_t<I::value>(), std::move(v) ); 520   return T( std::in_place_index_t<I::value>(), std::move(v) );
524   } 521   }
525   #endif // BOOST_NO_CXX17_HDR_VARIANT 522   #endif // BOOST_NO_CXX17_HDR_VARIANT
526   523  
527   524  
528   template< class T, class Ctx > 525   template< class T, class Ctx >
529   struct alternative_converter 526   struct alternative_converter
530   { 527   {
531   system::result<T>& res; 528   system::result<T>& res;
532   value const& jv; 529   value const& jv;
533   Ctx const& ctx; 530   Ctx const& ctx;
534   531  
535   template< class I > 532   template< class I >
536   void operator()( I ) const 533   void operator()( I ) const
537   { 534   {
538   if( res ) 535   if( res )
539   return; 536   return;
540   537  
541   using V = mp11::mp_at<T, I>; 538   using V = mp11::mp_at<T, I>;
542   auto attempt = try_value_to<V>(jv, ctx); 539   auto attempt = try_value_to<V>(jv, ctx);
543   if( attempt ) 540   if( attempt )
544   { 541   {
545   using cat = variant_construction_category<T, V, I>; 542   using cat = variant_construction_category<T, V, I>;
546   res = initialize_variant<T, I>( std::move(*attempt), cat() ); 543   res = initialize_variant<T, I>( std::move(*attempt), cat() );
547   } 544   }
548   } 545   }
549   }; 546   };
550   547  
551   template< class T, class Ctx > 548   template< class T, class Ctx >
552   system::result<T> 549   system::result<T>
553   value_to_impl( 550   value_to_impl(
554 - variant_conversion_tag, 551 + variant_category,
555   try_value_to_tag<T>, 552   try_value_to_tag<T>,
556   value const& jv, 553   value const& jv,
557   Ctx const& ctx) 554   Ctx const& ctx)
558   { 555   {
559   system::error_code ec; 556   system::error_code ec;
560   BOOST_JSON_FAIL(ec, error::exhausted_variants); 557   BOOST_JSON_FAIL(ec, error::exhausted_variants);
561   558  
562   using Is = mp11::mp_iota< mp11::mp_size<T> >; 559   using Is = mp11::mp_iota< mp11::mp_size<T> >;
563   560  
564   system::result<T> res = {system::in_place_error, ec}; 561   system::result<T> res = {system::in_place_error, ec};
565   mp11::mp_for_each<Is>( alternative_converter<T, Ctx>{res, jv, ctx} ); 562   mp11::mp_for_each<Is>( alternative_converter<T, Ctx>{res, jv, ctx} );
566   return res; 563   return res;
567   } 564   }
568   565  
569   template< class T, class Ctx > 566   template< class T, class Ctx >
570   system::result<T> 567   system::result<T>
571   value_to_impl( 568   value_to_impl(
572 - path_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& ) 569 + path_category, try_value_to_tag<T>, value const& jv, Ctx const& )
573   { 570   {
574   auto str = jv.if_string(); 571   auto str = jv.if_string();
575   if( !str ) 572   if( !str )
576   { 573   {
577   system::error_code ec; 574   system::error_code ec;
578   BOOST_JSON_FAIL(ec, error::not_string); 575   BOOST_JSON_FAIL(ec, error::not_string);
579   return {boost::system::in_place_error, ec}; 576   return {boost::system::in_place_error, ec};
580   } 577   }
581   578  
582   string_view sv = str->subview(); 579   string_view sv = str->subview();
583   return {boost::system::in_place_value, T( sv.begin(), sv.end() )}; 580   return {boost::system::in_place_value, T( sv.begin(), sv.end() )};
584   } 581   }
585   582  
586   //---------------------------------------------------------- 583   //----------------------------------------------------------
587   // User-provided conversions; throwing -> throwing 584   // User-provided conversions; throwing -> throwing
588   template< class T, class Ctx > 585   template< class T, class Ctx >
589   mp11::mp_if< mp11::mp_valid<has_user_conversion_to_impl, T>, T > 586   mp11::mp_if< mp11::mp_valid<has_user_conversion_to_impl, T>, T >
HITCBC 590   1 value_to_impl( 587   1 value_to_impl(
591 - user_conversion_tag, value_to_tag<T> tag, value const& jv, Ctx const&) 588 + user_category, value_to_tag<T> tag, value const& jv, Ctx const&)
592   { 589   {
HITCBC 593   1 return tag_invoke(tag, jv); 590   1 return tag_invoke(tag, jv);
594   } 591   }
595   592  
596   template< 593   template<
597   class T, 594   class T,
598   class Ctx, 595   class Ctx,
599   class Sup = supported_context<Ctx, T, value_to_conversion> 596   class Sup = supported_context<Ctx, T, value_to_conversion>
600   > 597   >
601   mp11::mp_if< 598   mp11::mp_if<
602   mp11::mp_valid< has_context_conversion_to_impl, typename Sup::type, T>, T > 599   mp11::mp_valid< has_context_conversion_to_impl, typename Sup::type, T>, T >
HITCBC 603   1 value_to_impl( 600   1 value_to_impl(
604 - context_conversion_tag, 601 + user_context_category,
605   value_to_tag<T> tag, 602   value_to_tag<T> tag,
606   value const& jv, 603   value const& jv,
607   Ctx const& ctx ) 604   Ctx const& ctx )
608   { 605   {
HITCBC 609   1 return tag_invoke( tag, jv, Sup::get(ctx) ); 606   1 return tag_invoke( tag, jv, Sup::get(ctx) );
610   } 607   }
611   608  
612   template< 609   template<
613   class T, 610   class T,
614   class Ctx, 611   class Ctx,
615   class Sup = supported_context<Ctx, T, value_to_conversion> 612   class Sup = supported_context<Ctx, T, value_to_conversion>
616   > 613   >
617   mp11::mp_if< 614   mp11::mp_if<
618   mp11::mp_valid< 615   mp11::mp_valid<
619   has_full_context_conversion_to_impl, typename Sup::type, T>, 616   has_full_context_conversion_to_impl, typename Sup::type, T>,
620   T> 617   T>
621   value_to_impl( 618   value_to_impl(
622 - full_context_conversion_tag, 619 + user_full_context_category,
623   value_to_tag<T> tag, 620   value_to_tag<T> tag,
624   value const& jv, 621   value const& jv,
625   Ctx const& ctx ) 622   Ctx const& ctx )
626   { 623   {
627   return tag_invoke( tag, jv, Sup::get(ctx), ctx ); 624   return tag_invoke( tag, jv, Sup::get(ctx), ctx );
628   } 625   }
629   626  
630   //---------------------------------------------------------- 627   //----------------------------------------------------------
631   // User-provided conversions; throwing -> nonthrowing 628   // User-provided conversions; throwing -> nonthrowing
632   template< class T, class Ctx > 629   template< class T, class Ctx >
633   mp11::mp_if_c< !mp11::mp_valid<has_user_conversion_to_impl, T>::value, T> 630   mp11::mp_if_c< !mp11::mp_valid<has_user_conversion_to_impl, T>::value, T>
HITCBC 634   60 value_to_impl( 631   60 value_to_impl(
635 - user_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& ) 632 + user_category, value_to_tag<T>, value const& jv, Ctx const& )
636   { 633   {
HITCBC 637   60 auto res = tag_invoke(try_value_to_tag<T>(), jv); 634   60 auto res = tag_invoke(try_value_to_tag<T>(), jv);
HITCBC 638   60 if( res.has_error() ) 635   60 if( res.has_error() )
HITCBC 639   12 throw_system_error( res.error() ); 636   12 throw_system_error( res.error() );
HITCBC 640   96 return std::move(*res); 637   96 return std::move(*res);
HITCBC 641   32 } 638   32 }
642   639  
643   template< 640   template<
644   class T, 641   class T,
645   class Ctx, 642   class Ctx,
646   class Sup = supported_context<Ctx, T, value_to_conversion> 643   class Sup = supported_context<Ctx, T, value_to_conversion>
647   > 644   >
648   mp11::mp_if_c< 645   mp11::mp_if_c<
649   !mp11::mp_valid< 646   !mp11::mp_valid<
650   has_context_conversion_to_impl, typename Sup::type, T>::value, 647   has_context_conversion_to_impl, typename Sup::type, T>::value,
651   T> 648   T>
HITCBC 652   3 value_to_impl( 649   3 value_to_impl(
653 - context_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& ctx ) 650 + user_context_category, value_to_tag<T>, value const& jv, Ctx const& ctx )
654   { 651   {
HITCBC 655   3 auto res = tag_invoke( try_value_to_tag<T>(), jv, Sup::get(ctx) ); 652   3 auto res = tag_invoke( try_value_to_tag<T>(), jv, Sup::get(ctx) );
HITCBC 656   3 if( res.has_error() ) 653   3 if( res.has_error() )
HITCBC 657   1 throw_system_error( res.error() ); 654   1 throw_system_error( res.error() );
HITCBC 658   4 return std::move(*res); 655   4 return std::move(*res);
659   } 656   }
660   657  
661   template< 658   template<
662   class T, 659   class T,
663   class Ctx, 660   class Ctx,
664   class Sup = supported_context<Ctx, T, value_to_conversion> 661   class Sup = supported_context<Ctx, T, value_to_conversion>
665   > 662   >
666   mp11::mp_if_c< 663   mp11::mp_if_c<
667   !mp11::mp_valid< 664   !mp11::mp_valid<
668   has_full_context_conversion_to_impl, typename Sup::type, T>::value, 665   has_full_context_conversion_to_impl, typename Sup::type, T>::value,
669   T> 666   T>
670   value_to_impl( 667   value_to_impl(
671 - full_context_conversion_tag, 668 + user_full_context_category,
672   value_to_tag<T>, 669   value_to_tag<T>,
673   value const& jv, 670   value const& jv,
674   Ctx const& ctx ) 671   Ctx const& ctx )
675   { 672   {
676   auto res = tag_invoke(try_value_to_tag<T>(), jv, Sup::get(ctx), ctx); 673   auto res = tag_invoke(try_value_to_tag<T>(), jv, Sup::get(ctx), ctx);
677   if( res.has_error() ) 674   if( res.has_error() )
678   throw_system_error( res.error() ); 675   throw_system_error( res.error() );
679   return std::move(*res); 676   return std::move(*res);
680   } 677   }
681   678  
682   //---------------------------------------------------------- 679   //----------------------------------------------------------
683   // User-provided conversions; nonthrowing -> nonthrowing 680   // User-provided conversions; nonthrowing -> nonthrowing
684   template< class T, class Ctx > 681   template< class T, class Ctx >
685   mp11::mp_if< 682   mp11::mp_if<
686   mp11::mp_valid< 683   mp11::mp_valid<
687   has_nonthrowing_user_conversion_to_impl, T>, system::result<T> > 684   has_nonthrowing_user_conversion_to_impl, T>, system::result<T> >
HITCBC 688   124 value_to_impl( 685   124 value_to_impl(
689 - user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& ) 686 + user_category, try_value_to_tag<T>, value const& jv, Ctx const& )
690   { 687   {
HITCBC 691   132 return tag_invoke(try_value_to_tag<T>(), jv); 688   132 return tag_invoke(try_value_to_tag<T>(), jv);
692   } 689   }
693   690  
694   template< 691   template<
695   class T, 692   class T,
696   class Ctx, 693   class Ctx,
697   class Sup = supported_context<Ctx, T, value_to_conversion> 694   class Sup = supported_context<Ctx, T, value_to_conversion>
698   > 695   >
699   mp11::mp_if< 696   mp11::mp_if<
700   mp11::mp_valid< 697   mp11::mp_valid<
701   has_nonthrowing_context_conversion_to_impl, typename Sup::type, T>, 698   has_nonthrowing_context_conversion_to_impl, typename Sup::type, T>,
702   system::result<T> > 699   system::result<T> >
703   value_to_impl( 700   value_to_impl(
704 - context_conversion_tag, 701 + user_context_category,
705   try_value_to_tag<T> tag, 702   try_value_to_tag<T> tag,
706   value const& jv, 703   value const& jv,
707   Ctx const& ctx ) 704   Ctx const& ctx )
708   { 705   {
709   return tag_invoke( tag, jv, Sup::get(ctx) ); 706   return tag_invoke( tag, jv, Sup::get(ctx) );
710   } 707   }
711   708  
712   template< 709   template<
713   class T, 710   class T,
714   class Ctx, 711   class Ctx,
715   class Sup = supported_context<Ctx, T, value_to_conversion> 712   class Sup = supported_context<Ctx, T, value_to_conversion>
716   > 713   >
717   mp11::mp_if< 714   mp11::mp_if<
718   mp11::mp_valid< 715   mp11::mp_valid<
719   has_nonthrowing_full_context_conversion_to_impl, 716   has_nonthrowing_full_context_conversion_to_impl,
720   typename Sup::type, 717   typename Sup::type,
721   T>, 718   T>,
722   system::result<T> > 719   system::result<T> >
723   value_to_impl( 720   value_to_impl(
724 - full_context_conversion_tag, 721 + user_full_context_category,
725   try_value_to_tag<T> tag, 722   try_value_to_tag<T> tag,
726   value const& jv, 723   value const& jv,
727   Ctx const& ctx ) 724   Ctx const& ctx )
728   { 725   {
729   return tag_invoke( tag, jv, Sup::get(ctx), ctx ); 726   return tag_invoke( tag, jv, Sup::get(ctx), ctx );
730   } 727   }
731   728  
732   //---------------------------------------------------------- 729   //----------------------------------------------------------
733   // User-provided conversions; nonthrowing -> throwing 730   // User-provided conversions; nonthrowing -> throwing
734   731  
735   template< class T, class... Args > 732   template< class T, class... Args >
736   system::result<T> 733   system::result<T>
HITCBC 737   54 wrap_conversion_exceptions( value_to_tag<T>, Args&& ... args ) 734   54 wrap_conversion_exceptions( value_to_tag<T>, Args&& ... args )
738   { 735   {
739   #ifndef BOOST_NO_EXCEPTIONS 736   #ifndef BOOST_NO_EXCEPTIONS
740   try 737   try
741   { 738   {
742   #endif 739   #endif
743   return { 740   return {
744   boost::system::in_place_value, 741   boost::system::in_place_value,
HITCBC 745   54 tag_invoke( value_to_tag<T>(), static_cast<Args&&>(args)... )}; 742   54 tag_invoke( value_to_tag<T>(), static_cast<Args&&>(args)... )};
746   #ifndef BOOST_NO_EXCEPTIONS 743   #ifndef BOOST_NO_EXCEPTIONS
747   } 744   }
HITCBC 748   30 catch( std::bad_alloc const&) 745   30 catch( std::bad_alloc const&)
749   { 746   {
HITCBC 750   6 throw; 747   6 throw;
751   } 748   }
HITCBC 752   12 catch( system::system_error const& e) 749   12 catch( system::system_error const& e)
753   { 750   {
HITCBC 754   12 return {boost::system::in_place_error, e.code()}; 751   12 return {boost::system::in_place_error, e.code()};
755   } 752   }
HITCBC 756   12 catch( ... ) 753   12 catch( ... )
757   { 754   {
HITCBC 758   6 system::error_code ec; 755   6 system::error_code ec;
HITCBC 759   6 BOOST_JSON_FAIL(ec, error::exception); 756   6 BOOST_JSON_FAIL(ec, error::exception);
HITCBC 760   6 return {boost::system::in_place_error, ec}; 757   6 return {boost::system::in_place_error, ec};
761   } 758   }
762   #endif 759   #endif
763   } 760   }
764   761  
765   template< class T, class Ctx > 762   template< class T, class Ctx >
766   mp11::mp_if_c< 763   mp11::mp_if_c<
767   !mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>::value, 764   !mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>::value,
768   system::result<T> > 765   system::result<T> >
HITCBC 769   54 value_to_impl( 766   54 value_to_impl(
770 - user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& ) 767 + user_category, try_value_to_tag<T>, value const& jv, Ctx const& )
771   { 768   {
HITCBC 772   54 return wrap_conversion_exceptions(value_to_tag<T>(), jv); 769   54 return wrap_conversion_exceptions(value_to_tag<T>(), jv);
773   } 770   }
774   771  
775   template< 772   template<
776   class T, 773   class T,
777   class Ctx, 774   class Ctx,
778   class Sup = supported_context<Ctx, T, value_to_conversion> 775   class Sup = supported_context<Ctx, T, value_to_conversion>
779   > 776   >
780   mp11::mp_if_c< 777   mp11::mp_if_c<
781   !mp11::mp_valid< 778   !mp11::mp_valid<
782   has_nonthrowing_context_conversion_to_impl, 779   has_nonthrowing_context_conversion_to_impl,
783   typename Sup::type, 780   typename Sup::type,
784   T>::value, 781   T>::value,
785   system::result<T> > 782   system::result<T> >
786   value_to_impl( 783   value_to_impl(
787 - context_conversion_tag, 784 + user_context_category,
788   try_value_to_tag<T>, 785   try_value_to_tag<T>,
789   value const& jv, 786   value const& jv,
790   Ctx const& ctx ) 787   Ctx const& ctx )
791   { 788   {
792   return wrap_conversion_exceptions( value_to_tag<T>(), jv, Sup::get(ctx) ); 789   return wrap_conversion_exceptions( value_to_tag<T>(), jv, Sup::get(ctx) );
793   } 790   }
794   791  
795   template< 792   template<
796   class T, 793   class T,
797   class Ctx, 794   class Ctx,
798   class Sup = supported_context<Ctx, T, value_to_conversion> 795   class Sup = supported_context<Ctx, T, value_to_conversion>
799   > 796   >
800   mp11::mp_if_c< 797   mp11::mp_if_c<
801   !mp11::mp_valid< 798   !mp11::mp_valid<
802   has_nonthrowing_full_context_conversion_to_impl, 799   has_nonthrowing_full_context_conversion_to_impl,
803   typename Sup::type, 800   typename Sup::type,
804   T>::value, 801   T>::value,
805   system::result<T> > 802   system::result<T> >
806   value_to_impl( 803   value_to_impl(
807 - full_context_conversion_tag, 804 + user_full_context_category,
808   try_value_to_tag<T>, 805   try_value_to_tag<T>,
809   value const& jv, 806   value const& jv,
810   Ctx const& ctx ) 807   Ctx const& ctx )
811   { 808   {
812   return wrap_conversion_exceptions( 809   return wrap_conversion_exceptions(
813   value_to_tag<T>(), jv, Sup::get(ctx), ctx); 810   value_to_tag<T>(), jv, Sup::get(ctx), ctx);
814   } 811   }
815   812  
816   // no suitable conversion implementation 813   // no suitable conversion implementation
817   template< class T, class Ctx > 814   template< class T, class Ctx >
818   T 815   T
819 - value_to_impl( no_conversion_tag, value_to_tag<T>, value const&, Ctx const& ) 816 + value_to_impl( unknown_category, value_to_tag<T>, value const&, Ctx const& )
820   { 817   {
821   static_assert( 818   static_assert(
822   !std::is_same<T, T>::value, 819   !std::is_same<T, T>::value,
823   "No suitable tag_invoke overload found for the type"); 820   "No suitable tag_invoke overload found for the type");
824   } 821   }
825   822  
826   // generic wrapper over non-throwing implementations 823   // generic wrapper over non-throwing implementations
827   template< class Impl, class T, class Ctx > 824   template< class Impl, class T, class Ctx >
828   T 825   T
HITCBC 829   345 value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx ) 826   345 value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx )
830   { 827   {
HITCBC 831   345 return value_to_impl(impl, try_value_to_tag<T>(), jv, ctx).value(); 828   345 return value_to_impl(impl, try_value_to_tag<T>(), jv, ctx).value();
832   } 829   }
833   830  
834   template< class Ctx, class T > 831   template< class Ctx, class T >
835 - using value_to_category = conversion_category< 832 + using value_to_category = extended_conversion_category<
836   Ctx, T, value_to_conversion >; 833   Ctx, T, value_to_conversion >;
837   834  
838   } // detail 835   } // detail
839   836  
840   #ifndef BOOST_NO_CXX17_HDR_OPTIONAL 837   #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
841   inline 838   inline
842   system::result<std::nullopt_t> 839   system::result<std::nullopt_t>
843   tag_invoke( 840   tag_invoke(
844   try_value_to_tag<std::nullopt_t>, 841   try_value_to_tag<std::nullopt_t>,
845   value const& jv) 842   value const& jv)
846   { 843   {
847   if( jv.is_null() ) 844   if( jv.is_null() )
848   return std::nullopt; 845   return std::nullopt;
849   system::error_code ec; 846   system::error_code ec;
850   BOOST_JSON_FAIL(ec, error::not_null); 847   BOOST_JSON_FAIL(ec, error::not_null);
851   return ec; 848   return ec;
852   } 849   }
853   #endif 850   #endif
854   851  
855   } // namespace json 852   } // namespace json
856   } // namespace boost 853   } // namespace boost
857   854  
858   #endif 855   #endif