]>
Commit | Line | Data |
---|---|---|
b32b8144 | 1 | // Copyright Louis Dionne 2013-2017 |
7c673cae FG |
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, | |
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, | |
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, | |
65 | T> from_json(std::istream& in) { | |
66 | T result; | |
67 | char brace; | |
68 | in >> brace; | |
69 | ||
b32b8144 FG |
70 | // CAREFUL: This only works if the input JSON contains the fields in the |
71 | // same order as the struct declares them. | |
7c673cae FG |
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, | |
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 | ||
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 | } |