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