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