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