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