from_json.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // Copyright Louis Dionne 2013-2017
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  4. #include <boost/hana/assert.hpp>
  5. #include <boost/hana/at.hpp>
  6. #include <boost/hana/at_key.hpp>
  7. #include <boost/hana/concept/sequence.hpp>
  8. #include <boost/hana/concept/struct.hpp>
  9. #include <boost/hana/define_struct.hpp>
  10. #include <boost/hana/for_each.hpp>
  11. #include <boost/hana/keys.hpp>
  12. #include <boost/hana/length.hpp>
  13. #include <boost/hana/not_equal.hpp>
  14. #include <boost/hana/tuple.hpp>
  15. #include <iostream>
  16. #include <limits>
  17. #include <sstream>
  18. #include <string>
  19. #include <type_traits>
  20. namespace hana = boost::hana;
  21. struct Car {
  22. BOOST_HANA_DEFINE_STRUCT(Car,
  23. (std::string, brand),
  24. (std::string, model)
  25. );
  26. };
  27. struct Person {
  28. BOOST_HANA_DEFINE_STRUCT(Person,
  29. (std::string, name),
  30. (std::string, last_name),
  31. (int, age)
  32. );
  33. };
  34. template <typename T>
  35. std::enable_if_t<std::is_same<T, int>::value,
  36. T> from_json(std::istream& in) {
  37. T result;
  38. in >> result;
  39. return result;
  40. }
  41. template <typename T>
  42. std::enable_if_t<std::is_same<T, std::string>::value,
  43. T> from_json(std::istream& in) {
  44. char quote;
  45. in >> quote;
  46. T result;
  47. char c;
  48. while (in.get(c) && c != '"') {
  49. result += c;
  50. }
  51. return result;
  52. }
  53. template <typename T>
  54. std::enable_if_t<hana::Struct<T>::value,
  55. T> from_json(std::istream& in) {
  56. T result;
  57. char brace;
  58. in >> brace;
  59. // CAREFUL: This only works if the input JSON contains the fields in the
  60. // same order as the struct declares them.
  61. hana::for_each(hana::keys(result), [&](auto key) {
  62. in.ignore(std::numeric_limits<std::streamsize>::max(), ':');
  63. auto& member = hana::at_key(result, key);
  64. using Member = std::remove_reference_t<decltype(member)>;
  65. member = from_json<Member>(in);
  66. });
  67. in >> brace;
  68. return result;
  69. }
  70. template <typename Xs>
  71. std::enable_if_t<hana::Sequence<Xs>::value,
  72. Xs> from_json(std::istream& in) {
  73. Xs result;
  74. char bracket;
  75. in >> bracket;
  76. hana::length(result).times.with_index([&](auto i) {
  77. if (i != 0u) {
  78. char comma;
  79. in >> comma;
  80. }
  81. auto& element = hana::at(result, i);
  82. using Element = std::remove_reference_t<decltype(element)>;
  83. element = from_json<Element>(in);
  84. });
  85. in >> bracket;
  86. return result;
  87. }
  88. int main() {
  89. std::istringstream json(R"EOS(
  90. [
  91. {
  92. "name": "John",
  93. "last_name": "Doe",
  94. "age": 30
  95. },
  96. {
  97. "brand": "BMW",
  98. "model": "Z3"
  99. },
  100. {
  101. "brand": "Audi",
  102. "model": "A4"
  103. }
  104. ]
  105. )EOS");
  106. auto actual = from_json<hana::tuple<Person, Car, Car>>(json);
  107. auto expected = hana::make_tuple(Person{"John", "Doe", 30},
  108. Car{"BMW", "Z3"},
  109. Car{"Audi", "A4"});
  110. BOOST_HANA_RUNTIME_CHECK(actual == expected);
  111. }