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 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)};
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);
280 : }
281 76 : return result;
282 79 : }
283 :
284 : // tuple-like types
285 : template< class T, class Ctx >
286 : system::result<T>
287 230 : try_make_tuple_elem(value const& jv, Ctx const& ctx, system::error_code& ec)
288 : {
289 230 : if( ec.failed() )
290 38 : return {boost::system::in_place_error, ec};
291 :
292 192 : auto result = try_value_to<T>( jv, ctx );
293 192 : ec = result.error();
294 192 : return result;
295 57 : }
296 :
297 : template <class T, class Ctx, std::size_t... Is>
298 : system::result<T>
299 91 : try_make_tuple_like(
300 : array const& arr, Ctx const& ctx, boost::mp11::index_sequence<Is...>)
301 : {
302 91 : system::error_code ec;
303 109 : auto items = std::make_tuple(
304 : try_make_tuple_elem<
305 111 : 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 91 : 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 : return {
319 78 : boost::system::in_place_value, T(std::move(*std::get<Is>(items))...)};
320 54 : }
321 :
322 : template< class T, class Ctx >
323 : system::result<T>
324 115 : value_to_impl(
325 : tuple_conversion_tag,
326 : try_value_to_tag<T>,
327 : value const& jv,
328 : Ctx const& ctx )
329 : {
330 115 : system::error_code ec;
331 :
332 115 : array const* arr = jv.if_array();
333 115 : if( !arr )
334 : {
335 12 : BOOST_JSON_FAIL(ec, error::not_array);
336 12 : return {boost::system::in_place_error, ec};
337 : }
338 :
339 103 : constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
340 103 : if( N != arr->size() )
341 : {
342 12 : BOOST_JSON_FAIL(ec, error::size_mismatch);
343 12 : return {boost::system::in_place_error, ec};
344 : }
345 :
346 31 : return try_make_tuple_like<T>(
347 91 : *arr, ctx, boost::mp11::make_index_sequence<N>());
348 : }
349 :
350 : template< class Ctx, class T >
351 : struct to_described_member
352 : {
353 : static_assert(
354 : uniquely_named_members<T>::value,
355 : "The type has several described members with the same name.");
356 :
357 : using Ds = described_members<T>;
358 :
359 : system::result<T>& res;
360 : object const& obj;
361 : Ctx const& ctx;
362 :
363 : template< class I >
364 : void
365 : operator()(I)
366 : {
367 : if( !res )
368 : return;
369 :
370 : using D = mp11::mp_at<Ds, I>;
371 : using M = described_member_t<T, D>;
372 :
373 : auto const found = obj.find(D::name);
374 : if( found == obj.end() )
375 : {
376 : BOOST_IF_CONSTEXPR( !is_optional_like<M>::value )
377 : {
378 : system::error_code ec;
379 : BOOST_JSON_FAIL(ec, error::size_mismatch);
380 : res = {boost::system::in_place_error, ec};
381 : }
382 : return;
383 : }
384 :
385 : #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
386 : # pragma GCC diagnostic push
387 : # pragma GCC diagnostic ignored "-Wunused"
388 : # pragma GCC diagnostic ignored "-Wunused-variable"
389 : #endif
390 : auto member_res = try_value_to<M>( found->value(), ctx );
391 : #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
392 : # pragma GCC diagnostic pop
393 : #endif
394 : if( member_res )
395 : (*res).* D::pointer = std::move(*member_res);
396 : else
397 : res = {boost::system::in_place_error, member_res.error()};
398 : }
399 : };
400 :
401 : // described classes
402 : template< class T, class Ctx >
403 : system::result<T>
404 : value_to_impl(
405 : described_class_conversion_tag,
406 : try_value_to_tag<T>,
407 : value const& jv,
408 : Ctx const& ctx )
409 : {
410 : BOOST_CORE_STATIC_ASSERT( std::is_default_constructible<T>::value );
411 : system::result<T> res;
412 :
413 : auto* obj = jv.if_object();
414 : if( !obj )
415 : {
416 : system::error_code ec;
417 : BOOST_JSON_FAIL(ec, error::not_object);
418 : res = {boost::system::in_place_error, ec};
419 : return res;
420 : }
421 :
422 : to_described_member<Ctx, T> member_converter{res, *obj, ctx};
423 :
424 : using Ds = typename decltype(member_converter)::Ds;
425 : constexpr std::size_t N = mp11::mp_size<Ds>::value;
426 : mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
427 :
428 : if( !res )
429 : return res;
430 :
431 : return res;
432 : }
433 :
434 : // described enums
435 : template< class T, class Ctx >
436 : system::result<T>
437 : value_to_impl(
438 : described_enum_conversion_tag,
439 : try_value_to_tag<T>,
440 : value const& jv,
441 : Ctx const& )
442 : {
443 : T val = {};
444 : (void)jv;
445 : #ifdef BOOST_DESCRIBE_CXX14
446 : system::error_code ec;
447 :
448 : auto str = jv.if_string();
449 : if( !str )
450 : {
451 : BOOST_JSON_FAIL(ec, error::not_string);
452 : return {system::in_place_error, ec};
453 : }
454 :
455 : if( !describe::enum_from_string(str->data(), val) )
456 : {
457 : BOOST_JSON_FAIL(ec, error::unknown_name);
458 : return {system::in_place_error, ec};
459 : }
460 : #endif
461 :
462 : return {system::in_place_value, val};
463 : }
464 :
465 : // optionals
466 : template< class T, class Ctx >
467 : system::result<T>
468 : value_to_impl(
469 : optional_conversion_tag,
470 : try_value_to_tag<T>,
471 : value const& jv,
472 : Ctx const& ctx)
473 : {
474 : using Inner = value_result_type<T>;
475 : if( jv.is_null() )
476 : return {};
477 : else
478 : return try_value_to<Inner>(jv, ctx);
479 : }
480 :
481 : // variants
482 : template< class T, class V, class I >
483 : using variant_construction_category = mp11::mp_cond<
484 : std::is_constructible< T, variant2::in_place_index_t<I::value>, V >,
485 : mp11::mp_int<2>,
486 : #ifndef BOOST_NO_CXX17_HDR_VARIANT
487 : std::is_constructible< T, std::in_place_index_t<I::value>, V >,
488 : mp11::mp_int<1>,
489 : #endif // BOOST_NO_CXX17_HDR_VARIANT
490 : mp11::mp_true,
491 : mp11::mp_int<0> >;
492 :
493 : template< class T, class I, class V >
494 : T
495 : initialize_variant( V&& v, mp11::mp_int<0> )
496 : {
497 : T t;
498 : t.template emplace<I::value>( std::move(v) );
499 : return t;
500 : }
501 :
502 : template< class T, class I, class V >
503 : T
504 : initialize_variant( V&& v, mp11::mp_int<2> )
505 : {
506 : return T( variant2::in_place_index_t<I::value>(), std::move(v) );
507 : }
508 :
509 : #ifndef BOOST_NO_CXX17_HDR_VARIANT
510 : template< class T, class I, class V >
511 : T
512 : initialize_variant( V&& v, mp11::mp_int<1> )
513 : {
514 : return T( std::in_place_index_t<I::value>(), std::move(v) );
515 : }
516 : #endif // BOOST_NO_CXX17_HDR_VARIANT
517 :
518 :
519 : template< class T, class Ctx >
520 : struct alternative_converter
521 : {
522 : system::result<T>& res;
523 : value const& jv;
524 : Ctx const& ctx;
525 :
526 : template< class I >
527 : void operator()( I ) const
528 : {
529 : if( res )
530 : return;
531 :
532 : using V = mp11::mp_at<T, I>;
533 : auto attempt = try_value_to<V>(jv, ctx);
534 : if( attempt )
535 : {
536 : using cat = variant_construction_category<T, V, I>;
537 : res = initialize_variant<T, I>( std::move(*attempt), cat() );
538 : }
539 : }
540 : };
541 :
542 : template< class T, class Ctx >
543 : system::result<T>
544 : value_to_impl(
545 : variant_conversion_tag,
546 : try_value_to_tag<T>,
547 : value const& jv,
548 : Ctx const& ctx)
549 : {
550 : system::error_code ec;
551 : BOOST_JSON_FAIL(ec, error::exhausted_variants);
552 :
553 : using Is = mp11::mp_iota< mp11::mp_size<T> >;
554 :
555 : system::result<T> res = {system::in_place_error, ec};
556 : mp11::mp_for_each<Is>( alternative_converter<T, Ctx>{res, jv, ctx} );
557 : return res;
558 : }
559 :
560 : template< class T, class Ctx >
561 : system::result<T>
562 : value_to_impl(
563 : path_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
564 : {
565 : auto str = jv.if_string();
566 : if( !str )
567 : {
568 : system::error_code ec;
569 : BOOST_JSON_FAIL(ec, error::not_string);
570 : return {boost::system::in_place_error, ec};
571 : }
572 :
573 : string_view sv = str->subview();
574 : return {boost::system::in_place_value, T( sv.begin(), sv.end() )};
575 : }
576 :
577 : //----------------------------------------------------------
578 : // User-provided conversions; throwing -> throwing
579 : template< class T, class Ctx >
580 : mp11::mp_if< mp11::mp_valid<has_user_conversion_to_impl, T>, T >
581 1 : value_to_impl(
582 : user_conversion_tag, value_to_tag<T> tag, value const& jv, Ctx const&)
583 : {
584 1 : return tag_invoke(tag, jv);
585 : }
586 :
587 : template<
588 : class T,
589 : class Ctx,
590 : class Sup = supported_context<Ctx, T, value_to_conversion>
591 : >
592 : mp11::mp_if<
593 : mp11::mp_valid< has_context_conversion_to_impl, typename Sup::type, T>, T >
594 1 : value_to_impl(
595 : context_conversion_tag,
596 : value_to_tag<T> tag,
597 : value const& jv,
598 : Ctx const& ctx )
599 : {
600 1 : return tag_invoke( tag, jv, Sup::get(ctx) );
601 : }
602 :
603 : template<
604 : class T,
605 : class Ctx,
606 : class Sup = supported_context<Ctx, T, value_to_conversion>
607 : >
608 : mp11::mp_if<
609 : mp11::mp_valid<
610 : has_full_context_conversion_to_impl, typename Sup::type, T>,
611 : T>
612 : value_to_impl(
613 : full_context_conversion_tag,
614 : value_to_tag<T> tag,
615 : value const& jv,
616 : Ctx const& ctx )
617 : {
618 : return tag_invoke( tag, jv, Sup::get(ctx), ctx );
619 : }
620 :
621 : //----------------------------------------------------------
622 : // User-provided conversions; throwing -> nonthrowing
623 : template< class T, class Ctx >
624 : mp11::mp_if_c< !mp11::mp_valid<has_user_conversion_to_impl, T>::value, T>
625 60 : value_to_impl(
626 : user_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& )
627 : {
628 60 : auto res = tag_invoke(try_value_to_tag<T>(), jv);
629 60 : if( res.has_error() )
630 12 : throw_system_error( res.error() );
631 96 : return std::move(*res);
632 32 : }
633 :
634 : template<
635 : class T,
636 : class Ctx,
637 : class Sup = supported_context<Ctx, T, value_to_conversion>
638 : >
639 : mp11::mp_if_c<
640 : !mp11::mp_valid<
641 : has_context_conversion_to_impl, typename Sup::type, T>::value,
642 : T>
643 3 : value_to_impl(
644 : context_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& ctx )
645 : {
646 3 : auto res = tag_invoke( try_value_to_tag<T>(), jv, Sup::get(ctx) );
647 3 : if( res.has_error() )
648 1 : throw_system_error( res.error() );
649 4 : return std::move(*res);
650 : }
651 :
652 : template<
653 : class T,
654 : class Ctx,
655 : class Sup = supported_context<Ctx, T, value_to_conversion>
656 : >
657 : mp11::mp_if_c<
658 : !mp11::mp_valid<
659 : has_full_context_conversion_to_impl, typename Sup::type, T>::value,
660 : T>
661 : value_to_impl(
662 : full_context_conversion_tag,
663 : value_to_tag<T>,
664 : value const& jv,
665 : Ctx const& ctx )
666 : {
667 : auto res = tag_invoke(try_value_to_tag<T>(), jv, Sup::get(ctx), ctx);
668 : if( res.has_error() )
669 : throw_system_error( res.error() );
670 : return std::move(*res);
671 : }
672 :
673 : //----------------------------------------------------------
674 : // User-provided conversions; nonthrowing -> nonthrowing
675 : template< class T, class Ctx >
676 : mp11::mp_if<
677 : mp11::mp_valid<
678 : has_nonthrowing_user_conversion_to_impl, T>, system::result<T> >
679 124 : value_to_impl(
680 : user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
681 : {
682 132 : return tag_invoke(try_value_to_tag<T>(), jv);
683 : }
684 :
685 : template<
686 : class T,
687 : class Ctx,
688 : class Sup = supported_context<Ctx, T, value_to_conversion>
689 : >
690 : mp11::mp_if<
691 : mp11::mp_valid<
692 : has_nonthrowing_context_conversion_to_impl, typename Sup::type, T>,
693 : system::result<T> >
694 : value_to_impl(
695 : context_conversion_tag,
696 : try_value_to_tag<T> tag,
697 : value const& jv,
698 : Ctx const& ctx )
699 : {
700 : return tag_invoke( tag, jv, Sup::get(ctx) );
701 : }
702 :
703 : template<
704 : class T,
705 : class Ctx,
706 : class Sup = supported_context<Ctx, T, value_to_conversion>
707 : >
708 : mp11::mp_if<
709 : mp11::mp_valid<
710 : has_nonthrowing_full_context_conversion_to_impl,
711 : typename Sup::type,
712 : T>,
713 : system::result<T> >
714 : value_to_impl(
715 : full_context_conversion_tag,
716 : try_value_to_tag<T> tag,
717 : value const& jv,
718 : Ctx const& ctx )
719 : {
720 : return tag_invoke( tag, jv, Sup::get(ctx), ctx );
721 : }
722 :
723 : //----------------------------------------------------------
724 : // User-provided conversions; nonthrowing -> throwing
725 :
726 : template< class T, class... Args >
727 : system::result<T>
728 36 : wrap_conversion_exceptions( value_to_tag<T>, Args&& ... args )
729 : {
730 : #ifndef BOOST_NO_EXCEPTIONS
731 : try
732 : {
733 : #endif
734 : return {
735 : boost::system::in_place_value,
736 36 : tag_invoke( value_to_tag<T>(), static_cast<Args&&>(args)... )};
737 : #ifndef BOOST_NO_EXCEPTIONS
738 : }
739 30 : catch( std::bad_alloc const&)
740 : {
741 6 : throw;
742 : }
743 12 : catch( system::system_error const& e)
744 : {
745 12 : return {boost::system::in_place_error, e.code()};
746 : }
747 12 : catch( ... )
748 : {
749 6 : system::error_code ec;
750 6 : BOOST_JSON_FAIL(ec, error::exception);
751 6 : return {boost::system::in_place_error, ec};
752 : }
753 : #endif
754 : }
755 :
756 : template< class T, class Ctx >
757 : mp11::mp_if_c<
758 : !mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>::value,
759 : system::result<T> >
760 36 : value_to_impl(
761 : user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
762 : {
763 36 : return wrap_conversion_exceptions(value_to_tag<T>(), jv);
764 : }
765 :
766 : template<
767 : class T,
768 : class Ctx,
769 : class Sup = supported_context<Ctx, T, value_to_conversion>
770 : >
771 : mp11::mp_if_c<
772 : !mp11::mp_valid<
773 : has_nonthrowing_context_conversion_to_impl,
774 : typename Sup::type,
775 : T>::value,
776 : system::result<T> >
777 : value_to_impl(
778 : context_conversion_tag,
779 : try_value_to_tag<T>,
780 : value const& jv,
781 : Ctx const& ctx )
782 : {
783 : return wrap_conversion_exceptions( value_to_tag<T>(), jv, Sup::get(ctx) );
784 : }
785 :
786 : template<
787 : class T,
788 : class Ctx,
789 : class Sup = supported_context<Ctx, T, value_to_conversion>
790 : >
791 : mp11::mp_if_c<
792 : !mp11::mp_valid<
793 : has_nonthrowing_full_context_conversion_to_impl,
794 : typename Sup::type,
795 : T>::value,
796 : system::result<T> >
797 : value_to_impl(
798 : full_context_conversion_tag,
799 : try_value_to_tag<T>,
800 : value const& jv,
801 : Ctx const& ctx )
802 : {
803 : return wrap_conversion_exceptions(
804 : value_to_tag<T>(), jv, Sup::get(ctx), ctx);
805 : }
806 :
807 : // no suitable conversion implementation
808 : template< class T, class Ctx >
809 : T
810 : value_to_impl( no_conversion_tag, value_to_tag<T>, value const&, Ctx const& )
811 : {
812 : static_assert(
813 : !std::is_same<T, T>::value,
814 : "No suitable tag_invoke overload found for the type");
815 : }
816 :
817 : // generic wrapper over non-throwing implementations
818 : template< class Impl, class T, class Ctx >
819 : T
820 339 : value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx )
821 : {
822 339 : return value_to_impl(impl, try_value_to_tag<T>(), jv, ctx).value();
823 : }
824 :
825 : template< class Ctx, class T >
826 : using value_to_category = conversion_category<
827 : Ctx, T, value_to_conversion >;
828 :
829 : } // detail
830 :
831 : #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
832 : inline
833 : system::result<std::nullopt_t>
834 : tag_invoke(
835 : try_value_to_tag<std::nullopt_t>,
836 : value const& jv)
837 : {
838 : if( jv.is_null() )
839 : return std::nullopt;
840 : system::error_code ec;
841 : BOOST_JSON_FAIL(ec, error::not_null);
842 : return ec;
843 : }
844 : #endif
845 :
846 : } // namespace json
847 : } // namespace boost
848 :
849 : #endif
|