#pragma once #include "base/exception.hpp" #include "base/macros.hpp" #define RAPIDJSON_SSE2 1 #define RAPIDJSON_HAS_STDSTRING 1 #define RAPIDJSON_HAS_CXX11_TYPETRAITS 1 #include "3party/rapidjson/document.h" #include "3party/rapidjson/rapidjson.h" #include "3party/rapidjson/writer.h" #include #include namespace coding { DECLARE_EXCEPTION(JsonException, RootException); using JsonValue = rapidjson::Value; using JsonDocument = rapidjson::Document; using JsonParseResult = rapidjson::ParseResult; inline void FromJson(JsonValue const & root, double & result) { if (!root.IsNumber()) MYTHROW(coding::JsonException, ("Object must contain a json number.")); result = root.GetDouble(); } inline void FromJson(JsonValue const & root, bool & result) { if (!root.IsBool()) MYTHROW(coding::JsonException, ("Object must contain a boolean value.")); result = root.GetBool(); } inline void FromJson(JsonValue const & root, std::string & result) { if (!root.IsString()) MYTHROW(coding::JsonException, ("The field must contain a json string.")); result = root.GetString(); } inline coding::JsonValue const * GetJsonOptionalField(coding::JsonValue const & root, std::string const & field) { if (!root.IsObject()) MYTHROW(coding::JsonException, ("Bad json object while parsing", field)); coding::JsonValue::ConstMemberIterator it = root.FindMember(field); if (it == root.MemberEnd()) return nullptr; return &it->value; } inline coding::JsonValue const & GetJsonObligatoryField(coding::JsonValue const & root, std::string const & field) { coding::JsonValue const * value = GetJsonOptionalField(root, field); if (!value) MYTHROW(coding::JsonException, ("Obligatory field", field, "is absent.")); return *value; } template void FromJsonObjectOptionalField(JsonValue const & root, std::string const & field, T & result) { coding::JsonValue const * value = GetJsonOptionalField(root, field); if (!value) { result = T{}; return; } FromJson(*value, result); } template inline coding::JsonValue const & GetJsonObligatoryFieldByPath(coding::JsonValue const & root, First && path) { return GetJsonObligatoryField(root, std::forward(path)); } template inline coding::JsonValue const & GetJsonObligatoryFieldByPath(coding::JsonValue const & root, First && path, Paths &&... paths) { coding::JsonValue const & newRoot = GetJsonObligatoryFieldByPath(root, std::forward(path)); return GetJsonObligatoryFieldByPath(newRoot, std::forward(paths)...); } template class JsonCustomPrecisionWriter : public rapidjson::Writer { public: // 6 digits after comma. Nautical mile is good approximation for one angle minute, so we can rely, // that final precision is 60 (minutes in degree) * 1852 (meters in one mile) // 1000000 = 0.111 = 111 millimeters. static uint32_t constexpr kDefaultPrecision = 6; JsonCustomPrecisionWriter(Stream & stream, size_t precision) : rapidjson::Writer(stream) , m_precision(precision) { } JsonCustomPrecisionWriter & Double(double d) { this->Prefix(rapidjson::kNumberType); std::stringstream ss; ss << std::fixed << std::setprecision(m_precision) << d; std::string number = ss.str(); for (char c : number) this->stream_.Put(c); return *this; } private: size_t m_precision = kDefaultPrecision; }; }