1 #pragma once
2 
3 #include <rapidjson/document.h>
4 
5 #include <pajlada/serialize/common.hpp>
6 
7 #ifdef PAJLADA_BOOST_ANY_SUPPORT
8 #include <boost/any.hpp>
9 #endif
10 
11 #include <cassert>
12 #include <cmath>
13 #include <map>
14 #include <stdexcept>
15 #include <string>
16 #include <typeinfo>
17 #include <vector>
18 
19 namespace pajlada {
20 
21 // Deserialize is called when we load a json file into our library
22 
23 template <typename Type, typename RJValue = rapidjson::Value,
24           typename Enable = void>
25 struct Deserialize {
26     static Type
getpajlada::Deserialize27     get(const RJValue & /*value*/, bool *error = nullptr)
28     {
29         // static_assert(false, "Unimplemented deserialize type");
30 
31         PAJLADA_REPORT_ERROR(error)
32 
33         return Type{};
34     }
35 };
36 
37 template <typename Type, typename RJValue>
38 struct Deserialize<
39     Type, RJValue,
40     typename std::enable_if<std::is_integral<Type>::value>::type> {
41     static Type
getpajlada::Deserialize42     get(const RJValue &value, bool *error = nullptr)
43     {
44         if (!value.IsNumber()) {
45             PAJLADA_REPORT_ERROR(error)
46             return Type{};
47         }
48 
49         return detail::GetNumber<Type>(value);
50     }
51 };
52 
53 template <typename RJValue>
54 struct Deserialize<bool, RJValue> {
55     static bool
getpajlada::Deserialize56     get(const RJValue &value, bool *error = nullptr)
57     {
58         if (value.IsBool()) {
59             // No conversion needed
60             return value.GetBool();
61         }
62 
63         if (value.IsInt()) {
64             // Conversion from Int:
65             // 1 == true
66             // Anything else = false
67             return value.GetInt() == 1;
68         }
69 
70         PAJLADA_REPORT_ERROR(error)
71         return false;
72     }
73 };
74 
75 template <typename RJValue>
76 struct Deserialize<double, RJValue> {
77     static double
getpajlada::Deserialize78     get(const RJValue &value, bool *error = nullptr)
79     {
80         if (value.IsNull()) {
81             return std::numeric_limits<double>::quiet_NaN();
82         }
83 
84         if (!value.IsNumber()) {
85             PAJLADA_REPORT_ERROR(error)
86             return double{};
87         }
88 
89         return value.GetDouble();
90     }
91 };
92 
93 template <typename RJValue>
94 struct Deserialize<float, RJValue> {
95     static float
getpajlada::Deserialize96     get(const RJValue &value, bool *error = nullptr)
97     {
98         if (value.IsNull()) {
99             return std::numeric_limits<float>::quiet_NaN();
100         }
101 
102         if (!value.IsNumber()) {
103             PAJLADA_REPORT_ERROR(error)
104             return float{};
105         }
106 
107         return value.GetFloat();
108     }
109 };
110 
111 template <typename RJValue>
112 struct Deserialize<std::string, RJValue> {
113     static std::string
getpajlada::Deserialize114     get(const RJValue &value, bool *error = nullptr)
115     {
116         if (!value.IsString()) {
117             PAJLADA_REPORT_ERROR(error)
118             return std::string{};
119         }
120 
121         return value.GetString();
122     }
123 };
124 
125 template <typename ValueType, typename RJValue>
126 struct Deserialize<std::map<std::string, ValueType>, RJValue> {
127     static std::map<std::string, ValueType>
getpajlada::Deserialize128     get(const RJValue &value, bool *error = nullptr)
129     {
130         std::map<std::string, ValueType> ret;
131 
132         if (!value.IsObject()) {
133             PAJLADA_REPORT_ERROR(error)
134             return ret;
135         }
136 
137         for (typename RJValue::ConstMemberIterator it = value.MemberBegin();
138              it != value.MemberEnd(); ++it) {
139             ret.emplace(it->name.GetString(),
140                         Deserialize<ValueType, RJValue>::get(it->value, error));
141         }
142 
143         return ret;
144     }
145 };
146 
147 template <typename ValueType, typename RJValue>
148 struct Deserialize<std::vector<ValueType>, RJValue> {
149     static std::vector<ValueType>
getpajlada::Deserialize150     get(const RJValue &value, bool *error = nullptr)
151     {
152         std::vector<ValueType> ret;
153 
154         if (!value.IsArray()) {
155             PAJLADA_REPORT_ERROR(error)
156             return ret;
157         }
158 
159         for (const RJValue &innerValue : value.GetArray()) {
160             ret.emplace_back(
161                 Deserialize<ValueType, RJValue>::get(innerValue, error));
162         }
163 
164         return ret;
165     }
166 };
167 
168 template <typename ValueType, size_t Size, typename RJValue>
169 struct Deserialize<std::array<ValueType, Size>, RJValue> {
170     static std::array<ValueType, Size>
getpajlada::Deserialize171     get(const RJValue &value, bool *error = nullptr)
172     {
173         std::array<ValueType, Size> ret;
174 
175         if (!value.IsArray()) {
176             PAJLADA_REPORT_ERROR(error)
177             return ret;
178         }
179 
180         if (value.GetArray().Size() != Size) {
181             PAJLADA_REPORT_ERROR(error)
182             return ret;
183         }
184 
185         for (size_t i = 0; i < Size; ++i) {
186             ret[i] = Deserialize<ValueType, RJValue>::get(value[i], error);
187         }
188 
189         return ret;
190     }
191 };
192 
193 template <typename Arg1, typename Arg2, typename RJValue>
194 struct Deserialize<std::pair<Arg1, Arg2>, RJValue> {
195     static std::pair<Arg1, Arg2>
getpajlada::Deserialize196     get(const RJValue &value, bool *error = nullptr)
197     {
198         if (!value.IsArray()) {
199             PAJLADA_REPORT_ERROR(error)
200             return std::make_pair(Arg1(), Arg2());
201         }
202 
203         if (value.Size() != 2) {
204             PAJLADA_REPORT_ERROR(error)
205             return std::make_pair(Arg1(), Arg2());
206         }
207 
208         return std::make_pair(Deserialize<Arg1, RJValue>::get(value[0], error),
209                               Deserialize<Arg2, RJValue>::get(value[1], error));
210     }
211 };
212 
213 #ifdef PAJLADA_BOOST_ANY_SUPPORT
214 template <typename RJValue>
215 struct Deserialize<boost::any, RJValue> {
216     static boost::any
getpajlada::Deserialize217     get(const RJValue &value, bool *error = nullptr)
218     {
219         if (value.IsInt()) {
220             return value.GetInt();
221         } else if (value.IsFloat() || value.IsDouble()) {
222             return value.GetDouble();
223         } else if (value.IsString()) {
224             return std::string(value.GetString());
225         } else if (value.IsBool()) {
226             return value.GetBool();
227         } else if (value.IsObject()) {
228             return Deserialize<std::map<std::string, boost::any>, RJValue>::get(
229                 value, error);
230         } else if (value.IsArray()) {
231             return Deserialize<std::vector<boost::any>, RJValue>::get(value,
232                                                                       error);
233         }
234 
235         PAJLADA_REPORT_ERROR(error)
236         return boost::any();
237     }
238 };
239 #endif
240 
241 }  // namespace pajlada
242