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