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/json/value.hpp>
16 : #include <boost/json/conversion.hpp>
17 : #include <boost/json/result_for.hpp>
18 : #include <boost/describe/enum_from_string.hpp>
19 :
20 : #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
21 : # include <optional>
22 : #endif
23 :
24 : namespace boost {
25 : namespace json {
26 :
27 : namespace detail {
28 :
29 : template< class Ctx, class T >
30 : using value_to_attrs = conversion_attrs<
31 : Ctx, remove_cvref<T>, value_to_conversion>;
32 :
33 : template<class T>
34 : using has_reserve_member_helper = decltype(std::declval<T&>().reserve(0));
35 : template<class T>
36 : using has_reserve_member = mp11::mp_valid<has_reserve_member_helper, T>;
37 : template<class T>
38 : using reserve_implementation = mp11::mp_cond<
39 : is_tuple_like<T>, mp11::mp_int<2>,
40 : has_reserve_member<T>, mp11::mp_int<1>,
41 : mp11::mp_true, mp11::mp_int<0>>;
42 :
43 : template<class T>
44 : error
45 41 : try_reserve(
46 : T&,
47 : std::size_t size,
48 : mp11::mp_int<2>)
49 : {
50 41 : constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
51 41 : if ( N != size )
52 30 : return error::size_mismatch;
53 11 : return error();
54 : }
55 :
56 : template<typename T>
57 : error
58 81 : try_reserve(
59 : T& cont,
60 : std::size_t size,
61 : mp11::mp_int<1>)
62 : {
63 81 : cont.reserve(size);
64 81 : return error();
65 : }
66 :
67 : template<typename T>
68 : error
69 67 : try_reserve(
70 : T&,
71 : std::size_t,
72 : mp11::mp_int<0>)
73 : {
74 67 : return error();
75 : }
76 :
77 :
78 : // identity conversion
79 : template< class Ctx >
80 : system::result<value>
81 : value_to_impl(
82 : value_conversion_tag,
83 : try_value_to_tag<value>,
84 : value const& jv,
85 : Ctx const& )
86 : {
87 : return jv;
88 : }
89 :
90 : template< class Ctx >
91 : value
92 : value_to_impl(
93 : value_conversion_tag, value_to_tag<value>, value const& jv, Ctx const& )
94 : {
95 : return jv;
96 : }
97 :
98 : // object
99 : template< class Ctx >
100 : system::result<object>
101 12 : value_to_impl(
102 : object_conversion_tag,
103 : try_value_to_tag<object>,
104 : value const& jv,
105 : Ctx const& )
106 : {
107 12 : object const* obj = jv.if_object();
108 12 : if( obj )
109 6 : return *obj;
110 6 : system::error_code ec;
111 6 : BOOST_JSON_FAIL(ec, error::not_object);
112 6 : return ec;
113 : }
114 :
115 : // array
116 : template< class Ctx >
117 : system::result<array>
118 12 : value_to_impl(
119 : array_conversion_tag,
120 : try_value_to_tag<array>,
121 : value const& jv,
122 : Ctx const& )
123 : {
124 12 : array const* arr = jv.if_array();
125 12 : if( arr )
126 6 : return *arr;
127 6 : system::error_code ec;
128 6 : BOOST_JSON_FAIL(ec, error::not_array);
129 6 : return ec;
130 : }
131 :
132 : // string
133 : template< class Ctx >
134 : system::result<string>
135 12 : value_to_impl(
136 : string_conversion_tag,
137 : try_value_to_tag<string>,
138 : value const& jv,
139 : Ctx const& )
140 : {
141 12 : string const* str = jv.if_string();
142 12 : if( str )
143 6 : return *str;
144 6 : system::error_code ec;
145 6 : BOOST_JSON_FAIL(ec, error::not_string);
146 6 : return ec;
147 : }
148 :
149 : // bool
150 : template< class Ctx >
151 : system::result<bool>
152 49 : value_to_impl(
153 : bool_conversion_tag, try_value_to_tag<bool>, value const& jv, Ctx const& )
154 : {
155 49 : auto b = jv.if_bool();
156 49 : if( b )
157 42 : return *b;
158 7 : system::error_code ec;
159 7 : BOOST_JSON_FAIL(ec, error::not_bool);
160 7 : return {boost::system::in_place_error, ec};
161 : }
162 :
163 : // integral and floating point
164 : template< class T, class Ctx >
165 : system::result<T>
166 3415 : value_to_impl(
167 : number_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
168 : {
169 3415 : system::error_code ec;
170 3415 : auto const n = jv.to_number<T>(ec);
171 3415 : if( ec.failed() )
172 55 : return {boost::system::in_place_error, ec};
173 3360 : return {boost::system::in_place_value, n};
174 : }
175 :
176 : // null-like conversion
177 : template< class T, class Ctx >
178 : system::result<T>
179 56 : value_to_impl(
180 : null_like_conversion_tag,
181 : try_value_to_tag<T>,
182 : value const& jv,
183 : Ctx const& )
184 : {
185 56 : if( jv.is_null() )
186 35 : return {boost::system::in_place_value, T{}};
187 21 : system::error_code ec;
188 21 : BOOST_JSON_FAIL(ec, error::not_null);
189 21 : return {boost::system::in_place_error, ec};
190 : }
191 :
192 : // string-like types
193 : template< class T, class Ctx >
194 : system::result<T>
195 145 : value_to_impl(
196 : string_like_conversion_tag,
197 : try_value_to_tag<T>,
198 : value const& jv,
199 : Ctx const& )
200 : {
201 145 : auto str = jv.if_string();
202 145 : if( str )
203 133 : 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 84 : value_to_impl(
213 : map_like_conversion_tag,
214 : try_value_to_tag<T>,
215 : value const& jv,
216 : Ctx const& ctx )
217 : {
218 84 : object const* obj = jv.if_object();
219 84 : 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 72 : T res;
227 72 : error const e = detail::try_reserve(
228 : res, obj->size(), reserve_implementation<T>());
229 72 : 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 60 : auto ins = detail::inserter(res, inserter_implementation<T>());
237 181 : for( key_value_pair const& kv: *obj )
238 : {
239 : using A = value_to_attrs< Ctx, key_type<T> >;
240 : using K = typename A::representation;
241 128 : auto elem_res = try_value_to<mapped_type<T>>( kv.value(), ctx );
242 128 : if( elem_res.has_error() )
243 13 : return {boost::system::in_place_error, elem_res.error()};
244 115 : *ins++ = value_type<T>{
245 230 : K(kv.key()),
246 115 : std::move(*elem_res)};
247 : }
248 47 : return res;
249 72 : }
250 :
251 : // all other containers
252 : template< class T, class Ctx >
253 : system::result<T>
254 126 : value_to_impl(
255 : sequence_conversion_tag,
256 : try_value_to_tag<T>,
257 : value const& jv,
258 : Ctx const& ctx )
259 : {
260 126 : array const* arr = jv.if_array();
261 126 : if( !arr )
262 : {
263 12 : system::error_code ec;
264 12 : BOOST_JSON_FAIL(ec, error::not_array);
265 12 : return {boost::system::in_place_error, ec};
266 : }
267 :
268 86 : T result;
269 114 : error const e = detail::try_reserve(
270 : result, arr->size(), reserve_implementation<T>());
271 114 : if( e != error() )
272 : {
273 18 : system::error_code ec;
274 18 : BOOST_JSON_FAIL( ec, e );
275 18 : return {boost::system::in_place_error, ec};
276 : }
277 :
278 96 : auto ins = detail::inserter(result, inserter_implementation<T>());
279 3379 : for( value const& val: *arr )
280 : {
281 3257 : auto elem_res = try_value_to<value_type<T>>( val, ctx );
282 3257 : if( elem_res.has_error() )
283 13 : return {boost::system::in_place_error, elem_res.error()};
284 3244 : *ins++ = std::move(*elem_res);
285 : }
286 83 : return result;
287 86 : }
288 :
289 : // tuple-like types
290 : template< class T, class Ctx >
291 : system::result<T>
292 244 : try_make_tuple_elem(value const& jv, Ctx const& ctx, system::error_code& ec)
293 : {
294 244 : if( ec.failed() )
295 38 : return {boost::system::in_place_error, ec};
296 :
297 206 : auto result = try_value_to<T>( jv, ctx );
298 206 : ec = result.error();
299 206 : return result;
300 57 : }
301 :
302 : template <class T, class Ctx, std::size_t... Is>
303 : system::result<T>
304 98 : try_make_tuple_like(
305 : array const& arr, Ctx const& ctx, boost::mp11::index_sequence<Is...>)
306 : {
307 98 : system::error_code ec;
308 116 : auto items = std::make_tuple(
309 : try_make_tuple_elem<
310 118 : typename std::decay<tuple_element_t<Is, T>>::type >(
311 : arr[Is], ctx, ec)
312 : ...);
313 : #if defined(BOOST_GCC)
314 : # pragma GCC diagnostic push
315 : # pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
316 : #endif
317 98 : if( ec.failed() )
318 13 : return {boost::system::in_place_error, ec};
319 : #if defined(BOOST_GCC)
320 : # pragma GCC diagnostic pop
321 : #endif
322 :
323 : return {
324 85 : boost::system::in_place_value, T(std::move(*std::get<Is>(items))...)};
325 54 : }
326 :
327 : template< class T, class Ctx >
328 : system::result<T>
329 122 : value_to_impl(
330 : tuple_conversion_tag,
331 : try_value_to_tag<T>,
332 : value const& jv,
333 : Ctx const& ctx )
334 : {
335 122 : system::error_code ec;
336 :
337 122 : array const* arr = jv.if_array();
338 122 : if( !arr )
339 : {
340 12 : BOOST_JSON_FAIL(ec, error::not_array);
341 12 : return {boost::system::in_place_error, ec};
342 : }
343 :
344 110 : constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
345 110 : if( N != arr->size() )
346 : {
347 12 : BOOST_JSON_FAIL(ec, error::size_mismatch);
348 12 : return {boost::system::in_place_error, ec};
349 : }
350 :
351 31 : return try_make_tuple_like<T>(
352 98 : *arr, ctx, boost::mp11::make_index_sequence<N>());
353 : }
354 :
355 : template< class Ctx, class T >
356 : struct to_described_member
357 : {
358 : using Ds = described_members<T>;
359 :
360 : system::result<T>& res;
361 : object const& obj;
362 : Ctx const& ctx;
363 :
364 : template< class I >
365 : void
366 : operator()(I)
367 : {
368 : if( !res )
369 : return;
370 :
371 : using D = mp11::mp_at<Ds, I>;
372 : using M = described_member_t<T, D>;
373 :
374 : auto const found = obj.find(D::name);
375 : if( found == obj.end() )
376 : {
377 : BOOST_IF_CONSTEXPR( !is_optional_like<M>::value )
378 : {
379 : system::error_code ec;
380 : BOOST_JSON_FAIL(ec, error::size_mismatch);
381 : res = {boost::system::in_place_error, ec};
382 : }
383 : return;
384 : }
385 :
386 : #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
387 : # pragma GCC diagnostic push
388 : # pragma GCC diagnostic ignored "-Wunused"
389 : # pragma GCC diagnostic ignored "-Wunused-variable"
390 : #endif
391 : auto member_res = try_value_to<M>( found->value(), ctx );
392 : #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
393 : # pragma GCC diagnostic pop
394 : #endif
395 : if( member_res )
396 : (*res).* D::pointer = std::move(*member_res);
397 : else
398 : res = {boost::system::in_place_error, member_res.error()};
399 : }
400 : };
401 :
402 : // described classes
403 : template< class T, class Ctx >
404 : system::result<T>
405 : value_to_impl(
406 : described_class_conversion_tag,
407 : try_value_to_tag<T>,
408 : value const& jv,
409 : Ctx const& ctx )
410 : {
411 : BOOST_STATIC_ASSERT( std::is_default_constructible<T>::value );
412 : system::result<T> res;
413 :
414 : auto* obj = jv.if_object();
415 : if( !obj )
416 : {
417 : system::error_code ec;
418 : BOOST_JSON_FAIL(ec, error::not_object);
419 : res = {boost::system::in_place_error, ec};
420 : return res;
421 : }
422 :
423 : to_described_member<Ctx, T> member_converter{res, *obj, ctx};
424 :
425 : using Ds = typename decltype(member_converter)::Ds;
426 : constexpr std::size_t N = mp11::mp_size<Ds>::value;
427 : mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
428 :
429 : if( !res )
430 : return res;
431 :
432 : return res;
433 : }
434 :
435 : // described enums
436 : template< class T, class Ctx >
437 : system::result<T>
438 : value_to_impl(
439 : described_enum_conversion_tag,
440 : try_value_to_tag<T>,
441 : value const& jv,
442 : Ctx const& )
443 : {
444 : T val = {};
445 : (void)jv;
446 : #ifdef BOOST_DESCRIBE_CXX14
447 : system::error_code ec;
448 :
449 : auto str = jv.if_string();
450 : if( !str )
451 : {
452 : BOOST_JSON_FAIL(ec, error::not_string);
453 : return {system::in_place_error, ec};
454 : }
455 :
456 : if( !describe::enum_from_string(str->data(), val) )
457 : {
458 : BOOST_JSON_FAIL(ec, error::unknown_name);
459 : return {system::in_place_error, ec};
460 : }
461 : #endif
462 :
463 : return {system::in_place_value, val};
464 : }
465 :
466 : // optionals
467 : template< class T, class Ctx >
468 : system::result<T>
469 : value_to_impl(
470 : optional_conversion_tag,
471 : try_value_to_tag<T>,
472 : value const& jv,
473 : Ctx const& ctx)
474 : {
475 : using Inner = value_result_type<T>;
476 : if( jv.is_null() )
477 : return {};
478 : else
479 : return try_value_to<Inner>(jv, ctx);
480 : }
481 :
482 : // variants
483 : template< class T, class V, class I >
484 : using variant_construction_category = mp11::mp_cond<
485 : std::is_constructible< T, variant2::in_place_index_t<I::value>, V >,
486 : mp11::mp_int<2>,
487 : #ifndef BOOST_NO_CXX17_HDR_VARIANT
488 : std::is_constructible< T, std::in_place_index_t<I::value>, V >,
489 : mp11::mp_int<1>,
490 : #endif // BOOST_NO_CXX17_HDR_VARIANT
491 : mp11::mp_true,
492 : mp11::mp_int<0> >;
493 :
494 : template< class T, class I, class V >
495 : T
496 : initialize_variant( V&& v, mp11::mp_int<0> )
497 : {
498 : T t;
499 : t.template emplace<I::value>( std::move(v) );
500 : return t;
501 : }
502 :
503 : template< class T, class I, class V >
504 : T
505 : initialize_variant( V&& v, mp11::mp_int<2> )
506 : {
507 : return T( variant2::in_place_index_t<I::value>(), std::move(v) );
508 : }
509 :
510 : #ifndef BOOST_NO_CXX17_HDR_VARIANT
511 : template< class T, class I, class V >
512 : T
513 : initialize_variant( V&& v, mp11::mp_int<1> )
514 : {
515 : return T( std::in_place_index_t<I::value>(), std::move(v) );
516 : }
517 : #endif // BOOST_NO_CXX17_HDR_VARIANT
518 :
519 :
520 : template< class T, class Ctx >
521 : struct alternative_converter
522 : {
523 : system::result<T>& res;
524 : value const& jv;
525 : Ctx const& ctx;
526 :
527 : template< class I >
528 : void operator()( I ) const
529 : {
530 : if( res )
531 : return;
532 :
533 : using V = mp11::mp_at<T, I>;
534 : auto attempt = try_value_to<V>(jv, ctx);
535 : if( attempt )
536 : {
537 : using cat = variant_construction_category<T, V, I>;
538 : res = initialize_variant<T, I>( std::move(*attempt), cat() );
539 : }
540 : }
541 : };
542 :
543 : template< class T, class Ctx >
544 : system::result<T>
545 : value_to_impl(
546 : variant_conversion_tag,
547 : try_value_to_tag<T>,
548 : value const& jv,
549 : Ctx const& ctx)
550 : {
551 : system::error_code ec;
552 : BOOST_JSON_FAIL(ec, error::exhausted_variants);
553 :
554 : using Is = mp11::mp_iota< mp11::mp_size<T> >;
555 :
556 : system::result<T> res = {system::in_place_error, ec};
557 : mp11::mp_for_each<Is>( alternative_converter<T, Ctx>{res, jv, ctx} );
558 : return res;
559 : }
560 :
561 : template< class T, class Ctx >
562 : system::result<T>
563 : value_to_impl(
564 : path_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
565 : {
566 : auto str = jv.if_string();
567 : if( !str )
568 : {
569 : system::error_code ec;
570 : BOOST_JSON_FAIL(ec, error::not_string);
571 : return {boost::system::in_place_error, ec};
572 : }
573 :
574 : string_view sv = str->subview();
575 : return {boost::system::in_place_value, T( sv.begin(), sv.end() )};
576 : }
577 :
578 : //----------------------------------------------------------
579 : // User-provided conversions; throwing -> throwing
580 : template< class T, class Ctx >
581 : mp11::mp_if< mp11::mp_valid<has_user_conversion_to_impl, T>, T >
582 1 : value_to_impl(
583 : user_conversion_tag, value_to_tag<T> tag, value const& jv, Ctx const&)
584 : {
585 1 : return tag_invoke(tag, jv);
586 : }
587 :
588 : template<
589 : class T,
590 : class Ctx,
591 : class Sup = supported_context<Ctx, T, value_to_conversion>
592 : >
593 : mp11::mp_if<
594 : mp11::mp_valid< has_context_conversion_to_impl, typename Sup::type, T>, T >
595 1 : value_to_impl(
596 : context_conversion_tag,
597 : value_to_tag<T> tag,
598 : value const& jv,
599 : Ctx const& ctx )
600 : {
601 1 : return tag_invoke( tag, jv, Sup::get(ctx) );
602 : }
603 :
604 : template<
605 : class T,
606 : class Ctx,
607 : class Sup = supported_context<Ctx, T, value_to_conversion>
608 : >
609 : mp11::mp_if<
610 : mp11::mp_valid<
611 : has_full_context_conversion_to_impl, typename Sup::type, T>,
612 : T>
613 : value_to_impl(
614 : full_context_conversion_tag,
615 : value_to_tag<T> tag,
616 : value const& jv,
617 : Ctx const& ctx )
618 : {
619 : return tag_invoke( tag, jv, Sup::get(ctx), ctx );
620 : }
621 :
622 : //----------------------------------------------------------
623 : // User-provided conversions; throwing -> nonthrowing
624 : template< class T, class Ctx >
625 : mp11::mp_if_c< !mp11::mp_valid<has_user_conversion_to_impl, T>::value, T>
626 66 : value_to_impl(
627 : user_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& )
628 : {
629 66 : auto res = tag_invoke(try_value_to_tag<T>(), jv);
630 66 : if( res.has_error() )
631 12 : throw_system_error( res.error() );
632 108 : return std::move(*res);
633 32 : }
634 :
635 : template<
636 : class T,
637 : class Ctx,
638 : class Sup = supported_context<Ctx, T, value_to_conversion>
639 : >
640 : mp11::mp_if_c<
641 : !mp11::mp_valid<
642 : has_context_conversion_to_impl, typename Sup::type, T>::value,
643 : T>
644 3 : value_to_impl(
645 : context_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& ctx )
646 : {
647 3 : auto res = tag_invoke( try_value_to_tag<T>(), jv, Sup::get(ctx) );
648 3 : if( res.has_error() )
649 1 : throw_system_error( res.error() );
650 4 : return std::move(*res);
651 : }
652 :
653 : template<
654 : class T,
655 : class Ctx,
656 : class Sup = supported_context<Ctx, T, value_to_conversion>
657 : >
658 : mp11::mp_if_c<
659 : !mp11::mp_valid<
660 : has_full_context_conversion_to_impl, typename Sup::type, T>::value,
661 : T>
662 : value_to_impl(
663 : full_context_conversion_tag,
664 : value_to_tag<T>,
665 : value const& jv,
666 : Ctx const& ctx )
667 : {
668 : auto res = tag_invoke(try_value_to_tag<T>(), jv, Sup::get(ctx), ctx);
669 : if( res.has_error() )
670 : throw_system_error( res.error() );
671 : return std::move(*res);
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 36 : 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 36 : 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 36 : value_to_impl(
762 : user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
763 : {
764 36 : 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 376 : value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx )
822 : {
823 376 : return value_to_impl(impl, try_value_to_tag<T>(), jv, ctx).value();
824 : }
825 :
826 : } // detail
827 :
828 : #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
829 : inline
830 : system::result<std::nullopt_t>
831 : tag_invoke(
832 : try_value_to_tag<std::nullopt_t>,
833 : value const& jv)
834 : {
835 : if( jv.is_null() )
836 : return std::nullopt;
837 : system::error_code ec;
838 : BOOST_JSON_FAIL(ec, error::not_null);
839 : return ec;
840 : }
841 : #endif
842 :
843 : } // namespace json
844 : } // namespace boost
845 :
846 : #endif
|