100.00% Lines (151/151) 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.unsafe_value())}; 244   91 std::move(elem_res.unsafe_value())};
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.unsafe_value()); 279   3216 *ins++ = std::move(elem_res.unsafe_value());
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.unsafe_value()); 401   (*res).* D::pointer = std::move(member_res.unsafe_value());
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>( 543   res = initialize_variant<T, I>(
547   std::move(attempt.unsafe_value()), cat() ); 544   std::move(attempt.unsafe_value()), cat() );
548   } 545   }
549   } 546   }
550   }; 547   };
551   548  
552   template< class T, class Ctx > 549   template< class T, class Ctx >
553   system::result<T> 550   system::result<T>
554   value_to_impl( 551   value_to_impl(
555 - variant_conversion_tag, 552 + variant_category,
556   try_value_to_tag<T>, 553   try_value_to_tag<T>,
557   value const& jv, 554   value const& jv,
558   Ctx const& ctx) 555   Ctx const& ctx)
559   { 556   {
560   system::error_code ec; 557   system::error_code ec;
561   BOOST_JSON_FAIL(ec, error::exhausted_variants); 558   BOOST_JSON_FAIL(ec, error::exhausted_variants);
562   559  
563   using Is = mp11::mp_iota< mp11::mp_size<T> >; 560   using Is = mp11::mp_iota< mp11::mp_size<T> >;
564   561  
565   system::result<T> res = {system::in_place_error, ec}; 562   system::result<T> res = {system::in_place_error, ec};
566   mp11::mp_for_each<Is>( alternative_converter<T, Ctx>{res, jv, ctx} ); 563   mp11::mp_for_each<Is>( alternative_converter<T, Ctx>{res, jv, ctx} );
567   return res; 564   return res;
568   } 565   }
569   566  
570   template< class T, class Ctx > 567   template< class T, class Ctx >
571   system::result<T> 568   system::result<T>
572   value_to_impl( 569   value_to_impl(
573 - path_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& ) 570 + path_category, try_value_to_tag<T>, value const& jv, Ctx const& )
574   { 571   {
575   auto str = jv.if_string(); 572   auto str = jv.if_string();
576   if( !str ) 573   if( !str )
577   { 574   {
578   system::error_code ec; 575   system::error_code ec;
579   BOOST_JSON_FAIL(ec, error::not_string); 576   BOOST_JSON_FAIL(ec, error::not_string);
580   return {boost::system::in_place_error, ec}; 577   return {boost::system::in_place_error, ec};
581   } 578   }
582   579  
583   string_view sv = str->subview(); 580   string_view sv = str->subview();
584   return {boost::system::in_place_value, T( sv.begin(), sv.end() )}; 581   return {boost::system::in_place_value, T( sv.begin(), sv.end() )};
585   } 582   }
586   583  
587   //---------------------------------------------------------- 584   //----------------------------------------------------------
588   // User-provided conversions; throwing -> throwing 585   // User-provided conversions; throwing -> throwing
589   template< class T, class Ctx > 586   template< class T, class Ctx >
590   mp11::mp_if< mp11::mp_valid<has_user_conversion_to_impl, T>, T > 587   mp11::mp_if< mp11::mp_valid<has_user_conversion_to_impl, T>, T >
HITCBC 591   1 value_to_impl( 588   1 value_to_impl(
592 - user_conversion_tag, value_to_tag<T> tag, value const& jv, Ctx const&) 589 + user_category, value_to_tag<T> tag, value const& jv, Ctx const&)
593   { 590   {
HITCBC 594   1 return tag_invoke(tag, jv); 591   1 return tag_invoke(tag, jv);
595   } 592   }
596   593  
597   template< 594   template<
598   class T, 595   class T,
599   class Ctx, 596   class Ctx,
600   class Sup = supported_context<Ctx, T, value_to_conversion> 597   class Sup = supported_context<Ctx, T, value_to_conversion>
601   > 598   >
602   mp11::mp_if< 599   mp11::mp_if<
603   mp11::mp_valid< has_context_conversion_to_impl, typename Sup::type, T>, T > 600   mp11::mp_valid< has_context_conversion_to_impl, typename Sup::type, T>, T >
HITCBC 604   1 value_to_impl( 601   1 value_to_impl(
605 - context_conversion_tag, 602 + user_context_category,
606   value_to_tag<T> tag, 603   value_to_tag<T> tag,
607   value const& jv, 604   value const& jv,
608   Ctx const& ctx ) 605   Ctx const& ctx )
609   { 606   {
HITCBC 610   1 return tag_invoke( tag, jv, Sup::get(ctx) ); 607   1 return tag_invoke( tag, jv, Sup::get(ctx) );
611   } 608   }
612   609  
613   template< 610   template<
614   class T, 611   class T,
615   class Ctx, 612   class Ctx,
616   class Sup = supported_context<Ctx, T, value_to_conversion> 613   class Sup = supported_context<Ctx, T, value_to_conversion>
617   > 614   >
618   mp11::mp_if< 615   mp11::mp_if<
619   mp11::mp_valid< 616   mp11::mp_valid<
620   has_full_context_conversion_to_impl, typename Sup::type, T>, 617   has_full_context_conversion_to_impl, typename Sup::type, T>,
621   T> 618   T>
622   value_to_impl( 619   value_to_impl(
623 - full_context_conversion_tag, 620 + user_full_context_category,
624   value_to_tag<T> tag, 621   value_to_tag<T> tag,
625   value const& jv, 622   value const& jv,
626   Ctx const& ctx ) 623   Ctx const& ctx )
627   { 624   {
628   return tag_invoke( tag, jv, Sup::get(ctx), ctx ); 625   return tag_invoke( tag, jv, Sup::get(ctx), ctx );
629   } 626   }
630   627  
631   //---------------------------------------------------------- 628   //----------------------------------------------------------
632   // User-provided conversions; throwing -> nonthrowing 629   // User-provided conversions; throwing -> nonthrowing
633   template< class T, class Ctx > 630   template< class T, class Ctx >
634   mp11::mp_if_c< !mp11::mp_valid<has_user_conversion_to_impl, T>::value, T> 631   mp11::mp_if_c< !mp11::mp_valid<has_user_conversion_to_impl, T>::value, T>
HITCBC 635   60 value_to_impl( 632   60 value_to_impl(
636 - user_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& ) 633 + user_category, value_to_tag<T>, value const& jv, Ctx const& )
637   { 634   {
HITCBC 638   66 return tag_invoke(try_value_to_tag<T>(), jv).value(); 635   66 return tag_invoke(try_value_to_tag<T>(), jv).value();
639   } 636   }
640   637  
641   template< 638   template<
642   class T, 639   class T,
643   class Ctx, 640   class Ctx,
644   class Sup = supported_context<Ctx, T, value_to_conversion> 641   class Sup = supported_context<Ctx, T, value_to_conversion>
645   > 642   >
646   mp11::mp_if_c< 643   mp11::mp_if_c<
647   !mp11::mp_valid< 644   !mp11::mp_valid<
648   has_context_conversion_to_impl, typename Sup::type, T>::value, 645   has_context_conversion_to_impl, typename Sup::type, T>::value,
649   T> 646   T>
HITCBC 650   3 value_to_impl( 647   3 value_to_impl(
651 - context_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& ctx ) 648 + user_context_category, value_to_tag<T>, value const& jv, Ctx const& ctx )
652   { 649   {
HITCBC 653   3 return tag_invoke( try_value_to_tag<T>(), jv, Sup::get(ctx) ).value(); 650   3 return tag_invoke( try_value_to_tag<T>(), jv, Sup::get(ctx) ).value();
654   } 651   }
655   652  
656   template< 653   template<
657   class T, 654   class T,
658   class Ctx, 655   class Ctx,
659   class Sup = supported_context<Ctx, T, value_to_conversion> 656   class Sup = supported_context<Ctx, T, value_to_conversion>
660   > 657   >
661   mp11::mp_if_c< 658   mp11::mp_if_c<
662   !mp11::mp_valid< 659   !mp11::mp_valid<
663   has_full_context_conversion_to_impl, typename Sup::type, T>::value, 660   has_full_context_conversion_to_impl, typename Sup::type, T>::value,
664   T> 661   T>
665   value_to_impl( 662   value_to_impl(
666 - full_context_conversion_tag, 663 + user_full_context_category,
667   value_to_tag<T>, 664   value_to_tag<T>,
668   value const& jv, 665   value const& jv,
669   Ctx const& ctx ) 666   Ctx const& ctx )
670   { 667   {
671   return tag_invoke(try_value_to_tag<T>(), jv, Sup::get(ctx), ctx).value(); 668   return tag_invoke(try_value_to_tag<T>(), jv, Sup::get(ctx), ctx).value();
672   } 669   }
673   670  
674   //---------------------------------------------------------- 671   //----------------------------------------------------------
675   // User-provided conversions; nonthrowing -> nonthrowing 672   // User-provided conversions; nonthrowing -> nonthrowing
676   template< class T, class Ctx > 673   template< class T, class Ctx >
677   mp11::mp_if< 674   mp11::mp_if<
678   mp11::mp_valid< 675   mp11::mp_valid<
679   has_nonthrowing_user_conversion_to_impl, T>, system::result<T> > 676   has_nonthrowing_user_conversion_to_impl, T>, system::result<T> >
HITCBC 680   124 value_to_impl( 677   124 value_to_impl(
681 - user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& ) 678 + user_category, try_value_to_tag<T>, value const& jv, Ctx const& )
682   { 679   {
HITCBC 683   132 return tag_invoke(try_value_to_tag<T>(), jv); 680   132 return tag_invoke(try_value_to_tag<T>(), jv);
684   } 681   }
685   682  
686   template< 683   template<
687   class T, 684   class T,
688   class Ctx, 685   class Ctx,
689   class Sup = supported_context<Ctx, T, value_to_conversion> 686   class Sup = supported_context<Ctx, T, value_to_conversion>
690   > 687   >
691   mp11::mp_if< 688   mp11::mp_if<
692   mp11::mp_valid< 689   mp11::mp_valid<
693   has_nonthrowing_context_conversion_to_impl, typename Sup::type, T>, 690   has_nonthrowing_context_conversion_to_impl, typename Sup::type, T>,
694   system::result<T> > 691   system::result<T> >
695   value_to_impl( 692   value_to_impl(
696 - context_conversion_tag, 693 + user_context_category,
697   try_value_to_tag<T> tag, 694   try_value_to_tag<T> tag,
698   value const& jv, 695   value const& jv,
699   Ctx const& ctx ) 696   Ctx const& ctx )
700   { 697   {
701   return tag_invoke( tag, jv, Sup::get(ctx) ); 698   return tag_invoke( tag, jv, Sup::get(ctx) );
702   } 699   }
703   700  
704   template< 701   template<
705   class T, 702   class T,
706   class Ctx, 703   class Ctx,
707   class Sup = supported_context<Ctx, T, value_to_conversion> 704   class Sup = supported_context<Ctx, T, value_to_conversion>
708   > 705   >
709   mp11::mp_if< 706   mp11::mp_if<
710   mp11::mp_valid< 707   mp11::mp_valid<
711   has_nonthrowing_full_context_conversion_to_impl, 708   has_nonthrowing_full_context_conversion_to_impl,
712   typename Sup::type, 709   typename Sup::type,
713   T>, 710   T>,
714   system::result<T> > 711   system::result<T> >
715   value_to_impl( 712   value_to_impl(
716 - full_context_conversion_tag, 713 + user_full_context_category,
717   try_value_to_tag<T> tag, 714   try_value_to_tag<T> tag,
718   value const& jv, 715   value const& jv,
719   Ctx const& ctx ) 716   Ctx const& ctx )
720   { 717   {
721   return tag_invoke( tag, jv, Sup::get(ctx), ctx ); 718   return tag_invoke( tag, jv, Sup::get(ctx), ctx );
722   } 719   }
723   720  
724   //---------------------------------------------------------- 721   //----------------------------------------------------------
725   // User-provided conversions; nonthrowing -> throwing 722   // User-provided conversions; nonthrowing -> throwing
726   723  
727   template< class T, class... Args > 724   template< class T, class... Args >
728   system::result<T> 725   system::result<T>
HITCBC 729   54 wrap_conversion_exceptions( value_to_tag<T>, Args&& ... args ) 726   54 wrap_conversion_exceptions( value_to_tag<T>, Args&& ... args )
730   { 727   {
731   #ifndef BOOST_NO_EXCEPTIONS 728   #ifndef BOOST_NO_EXCEPTIONS
732   try 729   try
733   { 730   {
734   #endif 731   #endif
735   return { 732   return {
736   boost::system::in_place_value, 733   boost::system::in_place_value,
HITCBC 737   54 tag_invoke( value_to_tag<T>(), static_cast<Args&&>(args)... )}; 734   54 tag_invoke( value_to_tag<T>(), static_cast<Args&&>(args)... )};
738   #ifndef BOOST_NO_EXCEPTIONS 735   #ifndef BOOST_NO_EXCEPTIONS
739   } 736   }
HITCBC 740   30 catch( std::bad_alloc const&) 737   30 catch( std::bad_alloc const&)
741   { 738   {
HITCBC 742   6 throw; 739   6 throw;
743   } 740   }
HITCBC 744   12 catch( system::system_error const& e) 741   12 catch( system::system_error const& e)
745   { 742   {
HITCBC 746   12 return {boost::system::in_place_error, e.code()}; 743   12 return {boost::system::in_place_error, e.code()};
747   } 744   }
HITCBC 748   12 catch( ... ) 745   12 catch( ... )
749   { 746   {
HITCBC 750   6 system::error_code ec; 747   6 system::error_code ec;
HITCBC 751   6 BOOST_JSON_FAIL(ec, error::exception); 748   6 BOOST_JSON_FAIL(ec, error::exception);
HITCBC 752   6 return {boost::system::in_place_error, ec}; 749   6 return {boost::system::in_place_error, ec};
753   } 750   }
754   #endif 751   #endif
755   } 752   }
756   753  
757   template< class T, class Ctx > 754   template< class T, class Ctx >
758   mp11::mp_if_c< 755   mp11::mp_if_c<
759   !mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>::value, 756   !mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>::value,
760   system::result<T> > 757   system::result<T> >
HITCBC 761   54 value_to_impl( 758   54 value_to_impl(
762 - user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& ) 759 + user_category, try_value_to_tag<T>, value const& jv, Ctx const& )
763   { 760   {
HITCBC 764   54 return wrap_conversion_exceptions(value_to_tag<T>(), jv); 761   54 return wrap_conversion_exceptions(value_to_tag<T>(), jv);
765   } 762   }
766   763  
767   template< 764   template<
768   class T, 765   class T,
769   class Ctx, 766   class Ctx,
770   class Sup = supported_context<Ctx, T, value_to_conversion> 767   class Sup = supported_context<Ctx, T, value_to_conversion>
771   > 768   >
772   mp11::mp_if_c< 769   mp11::mp_if_c<
773   !mp11::mp_valid< 770   !mp11::mp_valid<
774   has_nonthrowing_context_conversion_to_impl, 771   has_nonthrowing_context_conversion_to_impl,
775   typename Sup::type, 772   typename Sup::type,
776   T>::value, 773   T>::value,
777   system::result<T> > 774   system::result<T> >
778   value_to_impl( 775   value_to_impl(
779 - context_conversion_tag, 776 + user_context_category,
780   try_value_to_tag<T>, 777   try_value_to_tag<T>,
781   value const& jv, 778   value const& jv,
782   Ctx const& ctx ) 779   Ctx const& ctx )
783   { 780   {
784   return wrap_conversion_exceptions( value_to_tag<T>(), jv, Sup::get(ctx) ); 781   return wrap_conversion_exceptions( value_to_tag<T>(), jv, Sup::get(ctx) );
785   } 782   }
786   783  
787   template< 784   template<
788   class T, 785   class T,
789   class Ctx, 786   class Ctx,
790   class Sup = supported_context<Ctx, T, value_to_conversion> 787   class Sup = supported_context<Ctx, T, value_to_conversion>
791   > 788   >
792   mp11::mp_if_c< 789   mp11::mp_if_c<
793   !mp11::mp_valid< 790   !mp11::mp_valid<
794   has_nonthrowing_full_context_conversion_to_impl, 791   has_nonthrowing_full_context_conversion_to_impl,
795   typename Sup::type, 792   typename Sup::type,
796   T>::value, 793   T>::value,
797   system::result<T> > 794   system::result<T> >
798   value_to_impl( 795   value_to_impl(
799 - full_context_conversion_tag, 796 + user_full_context_category,
800   try_value_to_tag<T>, 797   try_value_to_tag<T>,
801   value const& jv, 798   value const& jv,
802   Ctx const& ctx ) 799   Ctx const& ctx )
803   { 800   {
804   return wrap_conversion_exceptions( 801   return wrap_conversion_exceptions(
805   value_to_tag<T>(), jv, Sup::get(ctx), ctx); 802   value_to_tag<T>(), jv, Sup::get(ctx), ctx);
806   } 803   }
807   804  
808   // no suitable conversion implementation 805   // no suitable conversion implementation
809   template< class T, class Ctx > 806   template< class T, class Ctx >
810   T 807   T
811 - value_to_impl( no_conversion_tag, value_to_tag<T>, value const&, Ctx const& ) 808 + value_to_impl( unknown_category, value_to_tag<T>, value const&, Ctx const& )
812   { 809   {
813   static_assert( 810   static_assert(
814   !std::is_same<T, T>::value, 811   !std::is_same<T, T>::value,
815   "No suitable tag_invoke overload found for the type"); 812   "No suitable tag_invoke overload found for the type");
816   } 813   }
817   814  
818   // generic wrapper over non-throwing implementations 815   // generic wrapper over non-throwing implementations
819   template< class Impl, class T, class Ctx > 816   template< class Impl, class T, class Ctx >
820   T 817   T
HITCBC 821   345 value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx ) 818   345 value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx )
822   { 819   {
HITCBC 823   345 return value_to_impl(impl, try_value_to_tag<T>(), jv, ctx).value(); 820   345 return value_to_impl(impl, try_value_to_tag<T>(), jv, ctx).value();
824   } 821   }
825   822  
826   template< class Ctx, class T > 823   template< class Ctx, class T >
827 - using value_to_category = conversion_category< 824 + using value_to_category = get_conversion_category<
828 - Ctx, T, value_to_conversion >; 825 + T, Ctx, all_checks<value_to_conversion>::fn >;
829   826  
830   } // detail 827   } // detail
831   828  
832   #ifndef BOOST_NO_CXX17_HDR_OPTIONAL 829   #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
833   inline 830   inline
834   system::result<std::nullopt_t> 831   system::result<std::nullopt_t>
835   tag_invoke( 832   tag_invoke(
836   try_value_to_tag<std::nullopt_t>, 833   try_value_to_tag<std::nullopt_t>,
837   value const& jv) 834   value const& jv)
838   { 835   {
839   if( jv.is_null() ) 836   if( jv.is_null() )
840   return std::nullopt; 837   return std::nullopt;
841   system::error_code ec; 838   system::error_code ec;
842   BOOST_JSON_FAIL(ec, error::not_null); 839   BOOST_JSON_FAIL(ec, error::not_null);
843   return ec; 840   return ec;
844   } 841   }
845   #endif 842   #endif
846   843  
847   } // namespace json 844   } // namespace json
848   } // namespace boost 845   } // namespace boost
849   846  
850   #endif 847   #endif