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