100.00% Lines (143/143) 100.00% Functions (27/27)
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 + system::result<T&>
HITCBC 42 - 41 try_reserve( 42 + 41 try_reserve(T& cnt, std::size_t size, mp11::mp_int<2>)
43 - T&, 43 + noexcept
44 - std::size_t size,  
45 - mp11::mp_int<2>)  
46   { 44   {
HITCBC 47   41 constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value; 45   41 constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
HITCBC 48   41 if ( N != size ) 46   41 if ( N != size )
ECB 49 - 30 return error::size_mismatch; 47 + {
HITCBC 50 - 11 return error(); 48 + 30 system::error_code ec;
HITGNC   49 + 30 BOOST_JSON_FAIL(ec, error::size_mismatch);
HITGNC   50 + 30 return {boost::system::in_place_error, ec};
  51 + }
HITGNC   52 + 11 return cnt;
51   } 53   }
52   54  
53   template<typename T> 55   template<typename T>
54 - error 56 + system::result<T&>
HITCBC 55 - 74 try_reserve( 57 + 74 try_reserve(T& cnt, std::size_t size, mp11::mp_int<1>)
56 - T& cont,  
57 - std::size_t size,  
58 - mp11::mp_int<1>)  
59   { 58   {
HITCBC 60 - 74 cont.reserve(size); 59 + 74 cnt.reserve(size);
HITCBC 61 - 74 return error(); 60 + 74 return cnt;
62   } 61   }
63   62  
64   template<typename T> 63   template<typename T>
65 - error 64 + system::result<T&>
HITCBC 66 - 57 try_reserve( 65 + 57 try_reserve(T& cnt, std::size_t, mp11::mp_int<0>)
67 - T&, 66 + noexcept
68 - std::size_t,  
69 - mp11::mp_int<0>)  
70   { 67   {
HITCBC 71 - 57 return error(); 68 + 57 return cnt;
72   } 69   }
73   70  
74   71  
75   // identity conversion 72   // identity conversion
76   template< class Ctx > 73   template< class Ctx >
77   system::result<value> 74   system::result<value>
78   value_to_impl( 75   value_to_impl(
79   value_conversion_tag, 76   value_conversion_tag,
80   try_value_to_tag<value>, 77   try_value_to_tag<value>,
81   value const& jv, 78   value const& jv,
82   Ctx const& ) 79   Ctx const& )
83   { 80   {
84   return jv; 81   return jv;
85   } 82   }
86   83  
87   template< class Ctx > 84   template< class Ctx >
88   value 85   value
89   value_to_impl( 86   value_to_impl(
90   value_conversion_tag, value_to_tag<value>, value const& jv, Ctx const& ) 87   value_conversion_tag, value_to_tag<value>, value const& jv, Ctx const& )
91   { 88   {
92   return jv; 89   return jv;
93   } 90   }
94   91  
95   // object 92   // object
96   template< class Ctx > 93   template< class Ctx >
97   system::result<object> 94   system::result<object>
HITCBC 98   12 value_to_impl( 95   12 value_to_impl(
99   object_conversion_tag, 96   object_conversion_tag,
100   try_value_to_tag<object>, 97   try_value_to_tag<object>,
101   value const& jv, 98   value const& jv,
102   Ctx const& ) 99   Ctx const& )
103   { 100   {
HITCBC 104   12 object const* obj = jv.if_object(); 101   12 object const* obj = jv.if_object();
HITCBC 105   12 if( obj ) 102   12 if( obj )
HITCBC 106   6 return *obj; 103   6 return *obj;
HITCBC 107   6 system::error_code ec; 104   6 system::error_code ec;
HITCBC 108   6 BOOST_JSON_FAIL(ec, error::not_object); 105   6 BOOST_JSON_FAIL(ec, error::not_object);
HITCBC 109   6 return ec; 106   6 return ec;
110   } 107   }
111   108  
112   // array 109   // array
113   template< class Ctx > 110   template< class Ctx >
114   system::result<array> 111   system::result<array>
HITCBC 115   12 value_to_impl( 112   12 value_to_impl(
116   array_conversion_tag, 113   array_conversion_tag,
117   try_value_to_tag<array>, 114   try_value_to_tag<array>,
118   value const& jv, 115   value const& jv,
119   Ctx const& ) 116   Ctx const& )
120   { 117   {
HITCBC 121   12 array const* arr = jv.if_array(); 118   12 array const* arr = jv.if_array();
HITCBC 122   12 if( arr ) 119   12 if( arr )
HITCBC 123   6 return *arr; 120   6 return *arr;
HITCBC 124   6 system::error_code ec; 121   6 system::error_code ec;
HITCBC 125   6 BOOST_JSON_FAIL(ec, error::not_array); 122   6 BOOST_JSON_FAIL(ec, error::not_array);
HITCBC 126   6 return ec; 123   6 return ec;
127   } 124   }
128   125  
129   // string 126   // string
130   template< class Ctx > 127   template< class Ctx >
131   system::result<string> 128   system::result<string>
HITCBC 132   12 value_to_impl( 129   12 value_to_impl(
133   string_conversion_tag, 130   string_conversion_tag,
134   try_value_to_tag<string>, 131   try_value_to_tag<string>,
135   value const& jv, 132   value const& jv,
136   Ctx const& ) 133   Ctx const& )
137   { 134   {
HITCBC 138   12 string const* str = jv.if_string(); 135   12 string const* str = jv.if_string();
HITCBC 139   12 if( str ) 136   12 if( str )
HITCBC 140   6 return *str; 137   6 return *str;
HITCBC 141   6 system::error_code ec; 138   6 system::error_code ec;
HITCBC 142   6 BOOST_JSON_FAIL(ec, error::not_string); 139   6 BOOST_JSON_FAIL(ec, error::not_string);
HITCBC 143   6 return ec; 140   6 return ec;
144   } 141   }
145   142  
146   // bool 143   // bool
147   template< class Ctx > 144   template< class Ctx >
148   system::result<bool> 145   system::result<bool>
HITCBC 149   49 value_to_impl( 146   49 value_to_impl(
150   bool_conversion_tag, try_value_to_tag<bool>, value const& jv, Ctx const& ) 147   bool_conversion_tag, try_value_to_tag<bool>, value const& jv, Ctx const& )
151   { 148   {
HITCBC 152   49 auto b = jv.if_bool(); 149   49 auto b = jv.if_bool();
HITCBC 153   49 if( b ) 150   49 if( b )
HITCBC 154   42 return *b; 151   42 return *b;
HITCBC 155   7 system::error_code ec; 152   7 system::error_code ec;
HITCBC 156   7 BOOST_JSON_FAIL(ec, error::not_bool); 153   7 BOOST_JSON_FAIL(ec, error::not_bool);
HITCBC 157   7 return {boost::system::in_place_error, ec}; 154   7 return {boost::system::in_place_error, ec};
158   } 155   }
159   156  
160   // integral and floating point 157   // integral and floating point
161   template< class T, class Ctx > 158   template< class T, class Ctx >
162   system::result<T> 159   system::result<T>
HITCBC 163   3396 value_to_impl( 160   3396 value_to_impl(
164   number_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& ) 161   number_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
165   { 162   {
HITCBC 166   3396 system::error_code ec; 163   3396 system::error_code ec;
HITCBC 167   3396 auto const n = jv.to_number<T>(ec); 164   3396 auto const n = jv.to_number<T>(ec);
HITCBC 168   3396 if( ec.failed() ) 165   3396 if( ec.failed() )
HITCBC 169   55 return {boost::system::in_place_error, ec}; 166   55 return {boost::system::in_place_error, ec};
HITCBC 170   3341 return {boost::system::in_place_value, n}; 167   3341 return {boost::system::in_place_value, n};
171   } 168   }
172   169  
173   // null-like conversion 170   // null-like conversion
174   template< class T, class Ctx > 171   template< class T, class Ctx >
175   system::result<T> 172   system::result<T>
HITCBC 176   56 value_to_impl( 173   56 value_to_impl(
177   null_like_conversion_tag, 174   null_like_conversion_tag,
178   try_value_to_tag<T>, 175   try_value_to_tag<T>,
179   value const& jv, 176   value const& jv,
180   Ctx const& ) 177   Ctx const& )
181   { 178   {
HITCBC 182   56 if( jv.is_null() ) 179   56 if( jv.is_null() )
HITCBC 183   35 return {boost::system::in_place_value, T{}}; 180   35 return {boost::system::in_place_value, T{}};
HITCBC 184   21 system::error_code ec; 181   21 system::error_code ec;
HITCBC 185   21 BOOST_JSON_FAIL(ec, error::not_null); 182   21 BOOST_JSON_FAIL(ec, error::not_null);
HITCBC 186   21 return {boost::system::in_place_error, ec}; 183   21 return {boost::system::in_place_error, ec};
187   } 184   }
188   185  
189   // string-like types 186   // string-like types
190   template< class T, class Ctx > 187   template< class T, class Ctx >
191   system::result<T> 188   system::result<T>
HITCBC 192   79 value_to_impl( 189   79 value_to_impl(
193   string_like_conversion_tag, 190   string_like_conversion_tag,
194   try_value_to_tag<T>, 191   try_value_to_tag<T>,
195   value const& jv, 192   value const& jv,
196   Ctx const& ) 193   Ctx const& )
197   { 194   {
HITCBC 198   79 auto str = jv.if_string(); 195   79 auto str = jv.if_string();
HITCBC 199   79 if( str ) 196   79 if( str )
HITCBC 200   67 return {boost::system::in_place_value, T(str->subview())}; 197   67 return {boost::system::in_place_value, T(str->subview())};
HITCBC 201   12 system::error_code ec; 198   12 system::error_code ec;
HITCBC 202   12 BOOST_JSON_FAIL(ec, error::not_string); 199   12 BOOST_JSON_FAIL(ec, error::not_string);
HITCBC 203   12 return {boost::system::in_place_error, ec}; 200   12 return {boost::system::in_place_error, ec};
204   } 201   }
205   202  
206   // map-like containers 203   // map-like containers
207   template< class T, class Ctx > 204   template< class T, class Ctx >
208   system::result<T> 205   system::result<T>
HITCBC 209   74 value_to_impl( 206   74 value_to_impl(
210   map_like_conversion_tag, 207   map_like_conversion_tag,
211   try_value_to_tag<T>, 208   try_value_to_tag<T>,
212   value const& jv, 209   value const& jv,
213   Ctx const& ctx ) 210   Ctx const& ctx )
214 - object const* obj = jv.if_object();  
DCB 215 - 74 if( !obj )  
DCB 216 - 74 {  
217 - system::error_code ec;  
DCB 218 - 12 BOOST_JSON_FAIL(ec, error::not_object);  
DCB 219 - 12 return {boost::system::in_place_error, ec};  
DCB 220 - 12 }  
221 -  
222   { 211   {
HITCBC 223   62 T res; 212   74 T res;
HITCBC 224 - 62 error const e = detail::try_reserve( 213 + 136 return jv.try_as_object() & [&](object const& jo)
225 - res, obj->size(), reserve_implementation<T>());  
DCB 226 - 62 if( e != error() )  
227 - {  
DCB 228 - 12 system::error_code ec;  
DCB 229 - 12 BOOST_JSON_FAIL( ec, e );  
DCB 230 - 12 return {boost::system::in_place_error, ec};  
231 - }  
232 -  
DCB 233 - 50 auto ins = detail::inserter(res, inserter_implementation<T>());  
DCB 234 - 147 for( key_value_pair const& kv: *obj )  
235   { 214   {
HITCBC 236 - 104 auto elem_res = try_value_to<mapped_type<T>>( kv.value(), ctx ); 215 + 62 return detail::try_reserve(
ECB 237 - 104 if( elem_res.has_error() ) 216 + res, jo.size(), reserve_implementation<T>())
HITCBC 238 - 13 return {boost::system::in_place_error, elem_res.error()}; 217 + 174 & [&](T& res) -> system::result<T>
ECB 239 - 91 *ins++ = value_type<T>{ 218 + {
HITCBC 240 - 182 key_type<T>(kv.key()), 219 + 50 auto ins = detail::inserter(res, inserter_implementation<T>());
HITCBC 241 - 91 std::move(elem_res.unsafe_value())}; 220 + 147 for(key_value_pair const& kv: jo)
242 - } 221 + {
HITCBC 243 - 37 return res; 222 + 104 auto elem_res = try_value_to<mapped_type<T>>(
  223 + kv.value(), ctx);
HITGNC   224 + 104 if( elem_res.has_error() )
  225 + return {
HITGNC   226 + 13 boost::system::in_place_error, elem_res.error()};
HITGNC   227 + 91 *ins++ = value_type<T>{
HITGNC   228 + 182 key_type<T>(kv.key()),
HITGNC   229 + 91 std::move( elem_res.unsafe_value() )};
  230 + }
HITGNC   231 + 37 return std::move(res);
HITGNC   232 + 124 };
HITGNC   233 + 148 };
HITCBC 244   62 } 234   74 }
245   235  
246   // all other containers 236   // all other containers
247   template< class T, class Ctx > 237   template< class T, class Ctx >
248   system::result<T> 238   system::result<T>
HITCBC 249   119 value_to_impl( 239   119 value_to_impl(
250   sequence_conversion_tag, 240   sequence_conversion_tag,
251   try_value_to_tag<T>, 241   try_value_to_tag<T>,
252   value const& jv, 242   value const& jv,
253   Ctx const& ctx ) 243   Ctx const& ctx )
254   { 244   {
HITCBC 255 - 119 array const* arr = jv.if_array(); 245 + 91 T res;
HITCBC 256 - 119 if( !arr ) 246 + 253 return jv.try_as_array() & [&](array const& ja)
257 - {  
DCB 258 - 12 system::error_code ec;  
DCB 259 - 12 BOOST_JSON_FAIL(ec, error::not_array);  
DCB 260 - 12 return {boost::system::in_place_error, ec};  
261 - }  
262 -  
DCB 263 - 79 T result;  
DCB 264 - 107 error const e = detail::try_reserve(  
265 - result, arr->size(), reserve_implementation<T>());  
DCB 266 - 107 if( e != error() )  
267 - {  
DCB 268 - 18 system::error_code ec;  
DCB 269 - 18 BOOST_JSON_FAIL( ec, e );  
DCB 270 - 18 return {boost::system::in_place_error, ec};  
271 - }  
272 -  
DCB 273 - 89 auto ins = detail::inserter(result, inserter_implementation<T>());  
DCB 274 - 3344 for( value const& val: *arr )  
275   { 247   {
HITCBC 276 - 3229 auto elem_res = try_value_to<value_type<T>>( val, ctx ); 248 + 107 return detail::try_reserve(
ECB 277 - 3229 if( elem_res.has_error() ) 249 + res, ja.size(), reserve_implementation<T>())
HITCBC 278 - 13 return {boost::system::in_place_error, elem_res.error()}; 250 + 330 & [&](T& res) -> system::result<T>
ECB 279 - 3216 *ins++ = std::move(elem_res.unsafe_value()); 251 + {
HITGIC 280 - } 252 + 89 auto ins = detail::inserter(res, inserter_implementation<T>());
HITCBC 281 - 76 return result; 253 + 3344 for(value const& val: ja)
  254 + {
HITGNC   255 + 3229 auto elem_res = try_value_to<value_type<T>>(val, ctx);
HITGNC   256 + 3229 if( elem_res.has_error() )
  257 + return {
HITGNC   258 + 13 boost::system::in_place_error, elem_res.error()};
HITGNC   259 + 3216 *ins++ = std::move( elem_res.unsafe_value() );
  260 + }
HITGNC   261 + 76 return std::move(res);
HITGNC   262 + 214 };
HITGNC   263 + 238 };
HITCBC 282   79 } 264   91 }
283   265  
284   // tuple-like types 266   // tuple-like types
285   template< class T, class Ctx > 267   template< class T, class Ctx >
286   system::result<T> 268   system::result<T>
HITCBC 287   248 try_make_tuple_elem(value const& jv, Ctx const& ctx, system::error_code& ec) 269   248 try_make_tuple_elem(value const& jv, Ctx const& ctx, system::error_code& ec)
288   { 270   {
HITCBC 289   248 if( ec.failed() ) 271   248 if( ec.failed() )
HITCBC 290   38 return {boost::system::in_place_error, ec}; 272   38 return {boost::system::in_place_error, ec};
291   273  
HITCBC 292   210 auto result = try_value_to<T>( jv, ctx ); 274   210 auto result = try_value_to<T>( jv, ctx );
HITCBC 293   210 ec = result.error(); 275   210 ec = result.error();
HITCBC 294   210 return result; 276   210 return result;
HITCBC 295   57 } 277   57 }
296   278  
297   template <class T, class Ctx, std::size_t... Is> 279   template <class T, class Ctx, std::size_t... Is>
298   system::result<T> 280   system::result<T>
HITCBC 299   97 try_make_tuple_like( 281   97 try_make_tuple_like(
300   array const& arr, Ctx const& ctx, boost::mp11::index_sequence<Is...>) 282   array const& arr, Ctx const& ctx, boost::mp11::index_sequence<Is...>)
301   { 283   {
HITCBC 302   97 system::error_code ec; 284   97 system::error_code ec;
HITCBC 303   115 auto items = std::make_tuple( 285   115 auto items = std::make_tuple(
304   try_make_tuple_elem< 286   try_make_tuple_elem<
HITCBC 305   117 typename std::decay<tuple_element_t<Is, T>>::type >( 287   117 typename std::decay<tuple_element_t<Is, T>>::type >(
306   arr[Is], ctx, ec) 288   arr[Is], ctx, ec)
307   ...); 289   ...);
308   #if defined(BOOST_GCC) 290   #if defined(BOOST_GCC)
309   # pragma GCC diagnostic push 291   # pragma GCC diagnostic push
310   # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" 292   # pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
311   #endif 293   #endif
HITCBC 312   97 if( ec.failed() ) 294   97 if( ec.failed() )
HITCBC 313   13 return {boost::system::in_place_error, ec}; 295   13 return {boost::system::in_place_error, ec};
314   #if defined(BOOST_GCC) 296   #if defined(BOOST_GCC)
315   # pragma GCC diagnostic pop 297   # pragma GCC diagnostic pop
316   #endif 298   #endif
317   299  
318   #if defined(BOOST_CLANG) 300   #if defined(BOOST_CLANG)
319   # pragma clang diagnostic push 301   # pragma clang diagnostic push
320   # pragma clang diagnostic ignored "-Wmissing-braces" 302   # pragma clang diagnostic ignored "-Wmissing-braces"
321   #endif 303   #endif
322   return { 304   return {
323   boost::system::in_place_value, 305   boost::system::in_place_value,
HITCBC 324   87 T{ (std::move(*std::get<Is>(items)))... } 306   87 T{ (std::move(*std::get<Is>(items)))... }
HITCBC 325   87 }; 307   87 };
326   #if defined(BOOST_CLANG) 308   #if defined(BOOST_CLANG)
327   # pragma clang diagnostic pop 309   # pragma clang diagnostic pop
328   #endif 310   #endif
HITCBC 329   54 } 311   54 }
330   312  
331   template< class T, class Ctx > 313   template< class T, class Ctx >
332   system::result<T> 314   system::result<T>
HITCBC 333   121 value_to_impl( 315   121 value_to_impl(
334   tuple_conversion_tag, 316   tuple_conversion_tag,
335   try_value_to_tag<T>, 317   try_value_to_tag<T>,
336   value const& jv, 318   value const& jv,
337   Ctx const& ctx ) 319   Ctx const& ctx )
338   { 320   {
HITCBC 339   121 system::error_code ec; 321   121 system::error_code ec;
340   322  
HITCBC 341   121 array const* arr = jv.if_array(); 323   121 array const* arr = jv.if_array();
HITCBC 342   121 if( !arr ) 324   121 if( !arr )
343   { 325   {
HITCBC 344   12 BOOST_JSON_FAIL(ec, error::not_array); 326   12 BOOST_JSON_FAIL(ec, error::not_array);
HITCBC 345   12 return {boost::system::in_place_error, ec}; 327   12 return {boost::system::in_place_error, ec};
346   } 328   }
347   329  
HITCBC 348   109 constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value; 330   109 constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
HITCBC 349   109 if( N != arr->size() ) 331   109 if( N != arr->size() )
350   { 332   {
HITCBC 351   12 BOOST_JSON_FAIL(ec, error::size_mismatch); 333   12 BOOST_JSON_FAIL(ec, error::size_mismatch);
HITCBC 352   12 return {boost::system::in_place_error, ec}; 334   12 return {boost::system::in_place_error, ec};
353   } 335   }
354   336  
HITCBC 355   37 return try_make_tuple_like<T>( 337   37 return try_make_tuple_like<T>(
HITCBC 356   97 *arr, ctx, boost::mp11::make_index_sequence<N>()); 338   97 *arr, ctx, boost::mp11::make_index_sequence<N>());
357   } 339   }
358   340  
359   template< class Ctx, class T > 341   template< class Ctx, class T >
360   struct to_described_member 342   struct to_described_member
361   { 343   {
362   static_assert( 344   static_assert(
363   uniquely_named_members<T>::value, 345   uniquely_named_members<T>::value,
364   "The type has several described members with the same name."); 346   "The type has several described members with the same name.");
365   347  
366   using Ds = described_members<T>; 348   using Ds = described_members<T>;
367   349  
368   system::result<T>& res; 350   system::result<T>& res;
369   object const& obj; 351   object const& obj;
370   Ctx const& ctx; 352   Ctx const& ctx;
371   353  
372   template< class I > 354   template< class I >
373   void 355   void
374   operator()(I) 356   operator()(I)
375   { 357   {
376   if( !res ) 358   if( !res )
377   return; 359   return;
378   360  
379   using D = mp11::mp_at<Ds, I>; 361   using D = mp11::mp_at<Ds, I>;
380   using M = described_member_t<T, D>; 362   using M = described_member_t<T, D>;
381   363  
382   auto const found = obj.find(D::name); 364   auto const found = obj.find(D::name);
383   if( found == obj.end() ) 365   if( found == obj.end() )
384   { 366   {
385   BOOST_IF_CONSTEXPR( !is_optional_like<M>::value ) 367   BOOST_IF_CONSTEXPR( !is_optional_like<M>::value )
386   { 368   {
387   system::error_code ec; 369   system::error_code ec;
388   BOOST_JSON_FAIL(ec, error::size_mismatch); 370   BOOST_JSON_FAIL(ec, error::size_mismatch);
389   res = {boost::system::in_place_error, ec}; 371   res = {boost::system::in_place_error, ec};
390   } 372   }
391   return; 373   return;
392   } 374   }
393   375  
394   #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000 376   #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
395   # pragma GCC diagnostic push 377   # pragma GCC diagnostic push
396   # pragma GCC diagnostic ignored "-Wunused" 378   # pragma GCC diagnostic ignored "-Wunused"
397   # pragma GCC diagnostic ignored "-Wunused-variable" 379   # pragma GCC diagnostic ignored "-Wunused-variable"
398   #endif 380   #endif
399   auto member_res = try_value_to<M>( found->value(), ctx ); 381   auto member_res = try_value_to<M>( found->value(), ctx );
400   #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000 382   #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
401   # pragma GCC diagnostic pop 383   # pragma GCC diagnostic pop
402   #endif 384   #endif
403   if( member_res ) 385   if( member_res )
404   (*res).* D::pointer = std::move(member_res.unsafe_value()); 386   (*res).* D::pointer = std::move(member_res.unsafe_value());
405   else 387   else
406   res = {boost::system::in_place_error, member_res.error()}; 388   res = {boost::system::in_place_error, member_res.error()};
407   } 389   }
408   }; 390   };
409   391  
410   // described classes 392   // described classes
411   template< class T, class Ctx > 393   template< class T, class Ctx >
412   system::result<T> 394   system::result<T>
413   value_to_impl( 395   value_to_impl(
414   described_class_conversion_tag, 396   described_class_conversion_tag,
415   try_value_to_tag<T>, 397   try_value_to_tag<T>,
416   value const& jv, 398   value const& jv,
417   Ctx const& ctx ) 399   Ctx const& ctx )
418   { 400   {
419   BOOST_CORE_STATIC_ASSERT( std::is_default_constructible<T>::value ); 401   BOOST_CORE_STATIC_ASSERT( std::is_default_constructible<T>::value );
420   system::result<T> res; 402   system::result<T> res;
421   403  
422   auto* obj = jv.if_object(); 404   auto* obj = jv.if_object();
423   if( !obj ) 405   if( !obj )
424   { 406   {
425   system::error_code ec; 407   system::error_code ec;
426   BOOST_JSON_FAIL(ec, error::not_object); 408   BOOST_JSON_FAIL(ec, error::not_object);
427   res = {boost::system::in_place_error, ec}; 409   res = {boost::system::in_place_error, ec};
428   return res; 410   return res;
429   } 411   }
430   412  
431   to_described_member<Ctx, T> member_converter{res, *obj, ctx}; 413   to_described_member<Ctx, T> member_converter{res, *obj, ctx};
432   414  
433   using Ds = typename decltype(member_converter)::Ds; 415   using Ds = typename decltype(member_converter)::Ds;
434   constexpr std::size_t N = mp11::mp_size<Ds>::value; 416   constexpr std::size_t N = mp11::mp_size<Ds>::value;
435   mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter); 417   mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
436   418  
437   if( !res ) 419   if( !res )
438   return res; 420   return res;
439   421  
440   return res; 422   return res;
441   } 423   }
442   424  
443   // described enums 425   // described enums
444   template< class T, class Ctx > 426   template< class T, class Ctx >
445   system::result<T> 427   system::result<T>
446   value_to_impl( 428   value_to_impl(
447   described_enum_conversion_tag, 429   described_enum_conversion_tag,
448   try_value_to_tag<T>, 430   try_value_to_tag<T>,
449   value const& jv, 431   value const& jv,
450   Ctx const& ) 432   Ctx const& )
451   { 433   {
452   T val = {}; 434   T val = {};
453   (void)jv; 435   (void)jv;
454   #ifdef BOOST_DESCRIBE_CXX14 436   #ifdef BOOST_DESCRIBE_CXX14
455   system::error_code ec; 437   system::error_code ec;
456   438  
457   auto str = jv.if_string(); 439   auto str = jv.if_string();
458   if( !str ) 440   if( !str )
459   { 441   {
460   BOOST_JSON_FAIL(ec, error::not_string); 442   BOOST_JSON_FAIL(ec, error::not_string);
461   return {system::in_place_error, ec}; 443   return {system::in_place_error, ec};
462   } 444   }
463   445  
464   if( !describe::enum_from_string(str->data(), val) ) 446   if( !describe::enum_from_string(str->data(), val) )
465   { 447   {
466   BOOST_JSON_FAIL(ec, error::unknown_name); 448   BOOST_JSON_FAIL(ec, error::unknown_name);
467   return {system::in_place_error, ec}; 449   return {system::in_place_error, ec};
468   } 450   }
469   #endif 451   #endif
470   452  
471   return {system::in_place_value, val}; 453   return {system::in_place_value, val};
472   } 454   }
473   455  
474   // optionals 456   // optionals
475   template< class T, class Ctx > 457   template< class T, class Ctx >
476   system::result<T> 458   system::result<T>
477   value_to_impl( 459   value_to_impl(
478   optional_conversion_tag, 460   optional_conversion_tag,
479   try_value_to_tag<T>, 461   try_value_to_tag<T>,
480   value const& jv, 462   value const& jv,
481   Ctx const& ctx) 463   Ctx const& ctx)
482   { 464   {
483   using Inner = value_result_type<T>; 465   using Inner = value_result_type<T>;
484   if( jv.is_null() ) 466   if( jv.is_null() )
485   return {}; 467   return {};
486   else 468   else
487   return try_value_to<Inner>(jv, ctx); 469   return try_value_to<Inner>(jv, ctx);
488   } 470   }
489   471  
490   // variants 472   // variants
491   template< class T, class V, class I > 473   template< class T, class V, class I >
492   using variant_construction_category = mp11::mp_cond< 474   using variant_construction_category = mp11::mp_cond<
493   std::is_constructible< T, variant2::in_place_index_t<I::value>, V >, 475   std::is_constructible< T, variant2::in_place_index_t<I::value>, V >,
494   mp11::mp_int<2>, 476   mp11::mp_int<2>,
495   #ifndef BOOST_NO_CXX17_HDR_VARIANT 477   #ifndef BOOST_NO_CXX17_HDR_VARIANT
496   std::is_constructible< T, std::in_place_index_t<I::value>, V >, 478   std::is_constructible< T, std::in_place_index_t<I::value>, V >,
497   mp11::mp_int<1>, 479   mp11::mp_int<1>,
498   #endif // BOOST_NO_CXX17_HDR_VARIANT 480   #endif // BOOST_NO_CXX17_HDR_VARIANT
499   mp11::mp_true, 481   mp11::mp_true,
500   mp11::mp_int<0> >; 482   mp11::mp_int<0> >;
501   483  
502   template< class T, class I, class V > 484   template< class T, class I, class V >
503   T 485   T
504   initialize_variant( V&& v, mp11::mp_int<0> ) 486   initialize_variant( V&& v, mp11::mp_int<0> )
505   { 487   {
506   T t; 488   T t;
507   t.template emplace<I::value>( std::move(v) ); 489   t.template emplace<I::value>( std::move(v) );
508   return t; 490   return t;
509   } 491   }
510   492  
511   template< class T, class I, class V > 493   template< class T, class I, class V >
512   T 494   T
513   initialize_variant( V&& v, mp11::mp_int<2> ) 495   initialize_variant( V&& v, mp11::mp_int<2> )
514   { 496   {
515   return T( variant2::in_place_index_t<I::value>(), std::move(v) ); 497   return T( variant2::in_place_index_t<I::value>(), std::move(v) );
516   } 498   }
517   499  
518   #ifndef BOOST_NO_CXX17_HDR_VARIANT 500   #ifndef BOOST_NO_CXX17_HDR_VARIANT
519   template< class T, class I, class V > 501   template< class T, class I, class V >
520   T 502   T
521   initialize_variant( V&& v, mp11::mp_int<1> ) 503   initialize_variant( V&& v, mp11::mp_int<1> )
522   { 504   {
523   return T( std::in_place_index_t<I::value>(), std::move(v) ); 505   return T( std::in_place_index_t<I::value>(), std::move(v) );
524   } 506   }
525   #endif // BOOST_NO_CXX17_HDR_VARIANT 507   #endif // BOOST_NO_CXX17_HDR_VARIANT
526   508  
527   509  
528   template< class T, class Ctx > 510   template< class T, class Ctx >
529   struct alternative_converter 511   struct alternative_converter
530   { 512   {
531   system::result<T>& res; 513   system::result<T>& res;
532   value const& jv; 514   value const& jv;
533   Ctx const& ctx; 515   Ctx const& ctx;
534   516  
535   template< class I > 517   template< class I >
536   void operator()( I ) const 518   void operator()( I ) const
537   { 519   {
538   if( res ) 520   if( res )
539   return; 521   return;
540   522  
541   using V = mp11::mp_at<T, I>; 523   using V = mp11::mp_at<T, I>;
542   auto attempt = try_value_to<V>(jv, ctx); 524   auto attempt = try_value_to<V>(jv, ctx);
543   if( attempt ) 525   if( attempt )
544   { 526   {
545   using cat = variant_construction_category<T, V, I>; 527   using cat = variant_construction_category<T, V, I>;
546   res = initialize_variant<T, I>( 528   res = initialize_variant<T, I>(
547   std::move(attempt.unsafe_value()), cat() ); 529   std::move(attempt.unsafe_value()), cat() );
548   } 530   }
549   } 531   }
550   }; 532   };
551   533  
552   template< class T, class Ctx > 534   template< class T, class Ctx >
553   system::result<T> 535   system::result<T>
554   value_to_impl( 536   value_to_impl(
555   variant_conversion_tag, 537   variant_conversion_tag,
556   try_value_to_tag<T>, 538   try_value_to_tag<T>,
557   value const& jv, 539   value const& jv,
558   Ctx const& ctx) 540   Ctx const& ctx)
559   { 541   {
560   system::error_code ec; 542   system::error_code ec;
561   BOOST_JSON_FAIL(ec, error::exhausted_variants); 543   BOOST_JSON_FAIL(ec, error::exhausted_variants);
562   544  
563   using Is = mp11::mp_iota< mp11::mp_size<T> >; 545   using Is = mp11::mp_iota< mp11::mp_size<T> >;
564   546  
565   system::result<T> res = {system::in_place_error, ec}; 547   system::result<T> res = {system::in_place_error, ec};
566   mp11::mp_for_each<Is>( alternative_converter<T, Ctx>{res, jv, ctx} ); 548   mp11::mp_for_each<Is>( alternative_converter<T, Ctx>{res, jv, ctx} );
567   return res; 549   return res;
568   } 550   }
569   551  
570   template< class T, class Ctx > 552   template< class T, class Ctx >
571   system::result<T> 553   system::result<T>
572   value_to_impl( 554   value_to_impl(
573   path_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& ) 555   path_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
574   { 556   {
575   auto str = jv.if_string(); 557   auto str = jv.if_string();
576   if( !str ) 558   if( !str )
577   { 559   {
578   system::error_code ec; 560   system::error_code ec;
579   BOOST_JSON_FAIL(ec, error::not_string); 561   BOOST_JSON_FAIL(ec, error::not_string);
580   return {boost::system::in_place_error, ec}; 562   return {boost::system::in_place_error, ec};
581   } 563   }
582   564  
583   string_view sv = str->subview(); 565   string_view sv = str->subview();
584   return {boost::system::in_place_value, T( sv.begin(), sv.end() )}; 566   return {boost::system::in_place_value, T( sv.begin(), sv.end() )};
585   } 567   }
586   568  
587   //---------------------------------------------------------- 569   //----------------------------------------------------------
588   // User-provided conversions; throwing -> throwing 570   // User-provided conversions; throwing -> throwing
589   template< class T, class Ctx > 571   template< class T, class Ctx >
590   mp11::mp_if< mp11::mp_valid<has_user_conversion_to_impl, T>, T > 572   mp11::mp_if< mp11::mp_valid<has_user_conversion_to_impl, T>, T >
HITCBC 591   1 value_to_impl( 573   1 value_to_impl(
592   user_conversion_tag, value_to_tag<T> tag, value const& jv, Ctx const&) 574   user_conversion_tag, value_to_tag<T> tag, value const& jv, Ctx const&)
593   { 575   {
HITCBC 594   1 return tag_invoke(tag, jv); 576   1 return tag_invoke(tag, jv);
595   } 577   }
596   578  
597   template< 579   template<
598   class T, 580   class T,
599   class Ctx, 581   class Ctx,
600   class Sup = supported_context<Ctx, T, value_to_conversion> 582   class Sup = supported_context<Ctx, T, value_to_conversion>
601   > 583   >
602   mp11::mp_if< 584   mp11::mp_if<
603   mp11::mp_valid< has_context_conversion_to_impl, typename Sup::type, T>, T > 585   mp11::mp_valid< has_context_conversion_to_impl, typename Sup::type, T>, T >
HITCBC 604   1 value_to_impl( 586   1 value_to_impl(
605   context_conversion_tag, 587   context_conversion_tag,
606   value_to_tag<T> tag, 588   value_to_tag<T> tag,
607   value const& jv, 589   value const& jv,
608   Ctx const& ctx ) 590   Ctx const& ctx )
609   { 591   {
HITCBC 610   1 return tag_invoke( tag, jv, Sup::get(ctx) ); 592   1 return tag_invoke( tag, jv, Sup::get(ctx) );
611   } 593   }
612   594  
613   template< 595   template<
614   class T, 596   class T,
615   class Ctx, 597   class Ctx,
616   class Sup = supported_context<Ctx, T, value_to_conversion> 598   class Sup = supported_context<Ctx, T, value_to_conversion>
617   > 599   >
618   mp11::mp_if< 600   mp11::mp_if<
619   mp11::mp_valid< 601   mp11::mp_valid<
620   has_full_context_conversion_to_impl, typename Sup::type, T>, 602   has_full_context_conversion_to_impl, typename Sup::type, T>,
621   T> 603   T>
622   value_to_impl( 604   value_to_impl(
623   full_context_conversion_tag, 605   full_context_conversion_tag,
624   value_to_tag<T> tag, 606   value_to_tag<T> tag,
625   value const& jv, 607   value const& jv,
626   Ctx const& ctx ) 608   Ctx const& ctx )
627   { 609   {
628   return tag_invoke( tag, jv, Sup::get(ctx), ctx ); 610   return tag_invoke( tag, jv, Sup::get(ctx), ctx );
629   } 611   }
630   612  
631   //---------------------------------------------------------- 613   //----------------------------------------------------------
632   // User-provided conversions; throwing -> nonthrowing 614   // User-provided conversions; throwing -> nonthrowing
633   template< class T, class Ctx > 615   template< class T, class Ctx >
634   mp11::mp_if_c< !mp11::mp_valid<has_user_conversion_to_impl, T>::value, T> 616   mp11::mp_if_c< !mp11::mp_valid<has_user_conversion_to_impl, T>::value, T>
HITCBC 635   60 value_to_impl( 617   60 value_to_impl(
636   user_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& ) 618   user_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& )
637   { 619   {
HITCBC 638   66 return tag_invoke(try_value_to_tag<T>(), jv).value(); 620   66 return tag_invoke(try_value_to_tag<T>(), jv).value();
639   } 621   }
640   622  
641   template< 623   template<
642   class T, 624   class T,
643   class Ctx, 625   class Ctx,
644   class Sup = supported_context<Ctx, T, value_to_conversion> 626   class Sup = supported_context<Ctx, T, value_to_conversion>
645   > 627   >
646   mp11::mp_if_c< 628   mp11::mp_if_c<
647   !mp11::mp_valid< 629   !mp11::mp_valid<
648   has_context_conversion_to_impl, typename Sup::type, T>::value, 630   has_context_conversion_to_impl, typename Sup::type, T>::value,
649   T> 631   T>
HITCBC 650   3 value_to_impl( 632   3 value_to_impl(
651   context_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& ctx ) 633   context_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& ctx )
652   { 634   {
HITCBC 653   3 return tag_invoke( try_value_to_tag<T>(), jv, Sup::get(ctx) ).value(); 635   3 return tag_invoke( try_value_to_tag<T>(), jv, Sup::get(ctx) ).value();
654   } 636   }
655   637  
656   template< 638   template<
657   class T, 639   class T,
658   class Ctx, 640   class Ctx,
659   class Sup = supported_context<Ctx, T, value_to_conversion> 641   class Sup = supported_context<Ctx, T, value_to_conversion>
660   > 642   >
661   mp11::mp_if_c< 643   mp11::mp_if_c<
662   !mp11::mp_valid< 644   !mp11::mp_valid<
663   has_full_context_conversion_to_impl, typename Sup::type, T>::value, 645   has_full_context_conversion_to_impl, typename Sup::type, T>::value,
664   T> 646   T>
665   value_to_impl( 647   value_to_impl(
666   full_context_conversion_tag, 648   full_context_conversion_tag,
667   value_to_tag<T>, 649   value_to_tag<T>,
668   value const& jv, 650   value const& jv,
669   Ctx const& ctx ) 651   Ctx const& ctx )
670   { 652   {
671   return tag_invoke(try_value_to_tag<T>(), jv, Sup::get(ctx), ctx).value(); 653   return tag_invoke(try_value_to_tag<T>(), jv, Sup::get(ctx), ctx).value();
672   } 654   }
673   655  
674   //---------------------------------------------------------- 656   //----------------------------------------------------------
675   // User-provided conversions; nonthrowing -> nonthrowing 657   // User-provided conversions; nonthrowing -> nonthrowing
676   template< class T, class Ctx > 658   template< class T, class Ctx >
677   mp11::mp_if< 659   mp11::mp_if<
678   mp11::mp_valid< 660   mp11::mp_valid<
679   has_nonthrowing_user_conversion_to_impl, T>, system::result<T> > 661   has_nonthrowing_user_conversion_to_impl, T>, system::result<T> >
HITCBC 680   124 value_to_impl( 662   124 value_to_impl(
681   user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& ) 663   user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
682   { 664   {
HITCBC 683   132 return tag_invoke(try_value_to_tag<T>(), jv); 665   132 return tag_invoke(try_value_to_tag<T>(), jv);
684   } 666   }
685   667  
686   template< 668   template<
687   class T, 669   class T,
688   class Ctx, 670   class Ctx,
689   class Sup = supported_context<Ctx, T, value_to_conversion> 671   class Sup = supported_context<Ctx, T, value_to_conversion>
690   > 672   >
691   mp11::mp_if< 673   mp11::mp_if<
692   mp11::mp_valid< 674   mp11::mp_valid<
693   has_nonthrowing_context_conversion_to_impl, typename Sup::type, T>, 675   has_nonthrowing_context_conversion_to_impl, typename Sup::type, T>,
694   system::result<T> > 676   system::result<T> >
695   value_to_impl( 677   value_to_impl(
696   context_conversion_tag, 678   context_conversion_tag,
697   try_value_to_tag<T> tag, 679   try_value_to_tag<T> tag,
698   value const& jv, 680   value const& jv,
699   Ctx const& ctx ) 681   Ctx const& ctx )
700   { 682   {
701   return tag_invoke( tag, jv, Sup::get(ctx) ); 683   return tag_invoke( tag, jv, Sup::get(ctx) );
702   } 684   }
703   685  
704   template< 686   template<
705   class T, 687   class T,
706   class Ctx, 688   class Ctx,
707   class Sup = supported_context<Ctx, T, value_to_conversion> 689   class Sup = supported_context<Ctx, T, value_to_conversion>
708   > 690   >
709   mp11::mp_if< 691   mp11::mp_if<
710   mp11::mp_valid< 692   mp11::mp_valid<
711   has_nonthrowing_full_context_conversion_to_impl, 693   has_nonthrowing_full_context_conversion_to_impl,
712   typename Sup::type, 694   typename Sup::type,
713   T>, 695   T>,
714   system::result<T> > 696   system::result<T> >
715   value_to_impl( 697   value_to_impl(
716   full_context_conversion_tag, 698   full_context_conversion_tag,
717   try_value_to_tag<T> tag, 699   try_value_to_tag<T> tag,
718   value const& jv, 700   value const& jv,
719   Ctx const& ctx ) 701   Ctx const& ctx )
720   { 702   {
721   return tag_invoke( tag, jv, Sup::get(ctx), ctx ); 703   return tag_invoke( tag, jv, Sup::get(ctx), ctx );
722   } 704   }
723   705  
724   //---------------------------------------------------------- 706   //----------------------------------------------------------
725   // User-provided conversions; nonthrowing -> throwing 707   // User-provided conversions; nonthrowing -> throwing
726   708  
727   template< class T, class... Args > 709   template< class T, class... Args >
728   system::result<T> 710   system::result<T>
HITCBC 729   54 wrap_conversion_exceptions( value_to_tag<T>, Args&& ... args ) 711   54 wrap_conversion_exceptions( value_to_tag<T>, Args&& ... args )
730   { 712   {
731   #ifndef BOOST_NO_EXCEPTIONS 713   #ifndef BOOST_NO_EXCEPTIONS
732   try 714   try
733   { 715   {
734   #endif 716   #endif
735   return { 717   return {
736   boost::system::in_place_value, 718   boost::system::in_place_value,
HITCBC 737   54 tag_invoke( value_to_tag<T>(), static_cast<Args&&>(args)... )}; 719   54 tag_invoke( value_to_tag<T>(), static_cast<Args&&>(args)... )};
738   #ifndef BOOST_NO_EXCEPTIONS 720   #ifndef BOOST_NO_EXCEPTIONS
739   } 721   }
HITCBC 740   30 catch( std::bad_alloc const&) 722   30 catch( std::bad_alloc const&)
741   { 723   {
HITCBC 742   6 throw; 724   6 throw;
743   } 725   }
HITCBC 744   12 catch( system::system_error const& e) 726   12 catch( system::system_error const& e)
745   { 727   {
HITCBC 746   12 return {boost::system::in_place_error, e.code()}; 728   12 return {boost::system::in_place_error, e.code()};
747   } 729   }
HITCBC 748   12 catch( ... ) 730   12 catch( ... )
749   { 731   {
HITCBC 750   6 system::error_code ec; 732   6 system::error_code ec;
HITCBC 751   6 BOOST_JSON_FAIL(ec, error::exception); 733   6 BOOST_JSON_FAIL(ec, error::exception);
HITCBC 752   6 return {boost::system::in_place_error, ec}; 734   6 return {boost::system::in_place_error, ec};
753   } 735   }
754   #endif 736   #endif
755   } 737   }
756   738  
757   template< class T, class Ctx > 739   template< class T, class Ctx >
758   mp11::mp_if_c< 740   mp11::mp_if_c<
759   !mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>::value, 741   !mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>::value,
760   system::result<T> > 742   system::result<T> >
HITCBC 761   54 value_to_impl( 743   54 value_to_impl(
762   user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& ) 744   user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
763   { 745   {
HITCBC 764   54 return wrap_conversion_exceptions(value_to_tag<T>(), jv); 746   54 return wrap_conversion_exceptions(value_to_tag<T>(), jv);
765   } 747   }
766   748  
767   template< 749   template<
768   class T, 750   class T,
769   class Ctx, 751   class Ctx,
770   class Sup = supported_context<Ctx, T, value_to_conversion> 752   class Sup = supported_context<Ctx, T, value_to_conversion>
771   > 753   >
772   mp11::mp_if_c< 754   mp11::mp_if_c<
773   !mp11::mp_valid< 755   !mp11::mp_valid<
774   has_nonthrowing_context_conversion_to_impl, 756   has_nonthrowing_context_conversion_to_impl,
775   typename Sup::type, 757   typename Sup::type,
776   T>::value, 758   T>::value,
777   system::result<T> > 759   system::result<T> >
778   value_to_impl( 760   value_to_impl(
779   context_conversion_tag, 761   context_conversion_tag,
780   try_value_to_tag<T>, 762   try_value_to_tag<T>,
781   value const& jv, 763   value const& jv,
782   Ctx const& ctx ) 764   Ctx const& ctx )
783   { 765   {
784   return wrap_conversion_exceptions( value_to_tag<T>(), jv, Sup::get(ctx) ); 766   return wrap_conversion_exceptions( value_to_tag<T>(), jv, Sup::get(ctx) );
785   } 767   }
786   768  
787   template< 769   template<
788   class T, 770   class T,
789   class Ctx, 771   class Ctx,
790   class Sup = supported_context<Ctx, T, value_to_conversion> 772   class Sup = supported_context<Ctx, T, value_to_conversion>
791   > 773   >
792   mp11::mp_if_c< 774   mp11::mp_if_c<
793   !mp11::mp_valid< 775   !mp11::mp_valid<
794   has_nonthrowing_full_context_conversion_to_impl, 776   has_nonthrowing_full_context_conversion_to_impl,
795   typename Sup::type, 777   typename Sup::type,
796   T>::value, 778   T>::value,
797   system::result<T> > 779   system::result<T> >
798   value_to_impl( 780   value_to_impl(
799   full_context_conversion_tag, 781   full_context_conversion_tag,
800   try_value_to_tag<T>, 782   try_value_to_tag<T>,
801   value const& jv, 783   value const& jv,
802   Ctx const& ctx ) 784   Ctx const& ctx )
803   { 785   {
804   return wrap_conversion_exceptions( 786   return wrap_conversion_exceptions(
805   value_to_tag<T>(), jv, Sup::get(ctx), ctx); 787   value_to_tag<T>(), jv, Sup::get(ctx), ctx);
806   } 788   }
807   789  
808   // no suitable conversion implementation 790   // no suitable conversion implementation
809   template< class T, class Ctx > 791   template< class T, class Ctx >
810   T 792   T
811   value_to_impl( no_conversion_tag, value_to_tag<T>, value const&, Ctx const& ) 793   value_to_impl( no_conversion_tag, value_to_tag<T>, value const&, Ctx const& )
812   { 794   {
813   static_assert( 795   static_assert(
814   !std::is_same<T, T>::value, 796   !std::is_same<T, T>::value,
815   "No suitable tag_invoke overload found for the type"); 797   "No suitable tag_invoke overload found for the type");
816   } 798   }
817   799  
818   // generic wrapper over non-throwing implementations 800   // generic wrapper over non-throwing implementations
819   template< class Impl, class T, class Ctx > 801   template< class Impl, class T, class Ctx >
820   T 802   T
HITCBC 821   345 value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx ) 803   345 value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx )
822   { 804   {
HITCBC 823   345 return value_to_impl(impl, try_value_to_tag<T>(), jv, ctx).value(); 805   345 return value_to_impl(impl, try_value_to_tag<T>(), jv, ctx).value();
824   } 806   }
825   807  
826   template< class Ctx, class T > 808   template< class Ctx, class T >
827   using value_to_category = conversion_category< 809   using value_to_category = conversion_category<
828   Ctx, T, value_to_conversion >; 810   Ctx, T, value_to_conversion >;
829   811  
830   } // detail 812   } // detail
831   813  
832   #ifndef BOOST_NO_CXX17_HDR_OPTIONAL 814   #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
833   inline 815   inline
834   system::result<std::nullopt_t> 816   system::result<std::nullopt_t>
835   tag_invoke( 817   tag_invoke(
836   try_value_to_tag<std::nullopt_t>, 818   try_value_to_tag<std::nullopt_t>,
837   value const& jv) 819   value const& jv)
838   { 820   {
839   if( jv.is_null() ) 821   if( jv.is_null() )
840   return std::nullopt; 822   return std::nullopt;
841   system::error_code ec; 823   system::error_code ec;
842   BOOST_JSON_FAIL(ec, error::not_null); 824   BOOST_JSON_FAIL(ec, error::not_null);
843   return ec; 825   return ec;
844   } 826   }
845   #endif 827   #endif
846   828  
847   } // namespace json 829   } // namespace json
848   } // namespace boost 830   } // namespace boost
849   831  
850   #endif 832   #endif