• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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