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