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