value_to.hpp 23 KB

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