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