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