//! \~\file pijsonserialization.h //! \~\ingroup Serialization //! \~\brief //! \~english Generic JSON serialization helpers //! \~russian Вспомогательные шаблоны для сериализации JSON //! \details //! \~english //! This file provides template functions for serializing and deserializing various types to and from PIJSON format. //! \~russian //! Этот файл предоставляет шаблонные функции для сериализации и десериализации различных типов в формат PIJSON и из него. /* PIP - Platform Independent Primitives Generic JSON serialization helpers Ivan Pelipenko peri4ko@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef PIJSONSERIALIZATION_H #define PIJSONSERIALIZATION_H #include "pijson.h" // --- // serialize, PIJSON = piSerializeJSON(T) // --- // enum & arithmetic //! \~english Serializes enum values as JSON numbers. //! \~russian Сериализует значения перечислений как JSON-числа. template::value, int>::type = 0> inline PIJSON piSerializeJSON(const T & v) { return PIJSON() = (int)v; } //! \~english Serializes arithmetic values as JSON scalars. //! \~russian Сериализует арифметические значения как JSON-скаляры. template::value, int>::type = 0, typename std::enable_if::value, int>::type = 0> inline PIJSON piSerializeJSON(const T & v) { return PIJSON() = v; } //! \~english Fallback overload that intentionally fails for unsupported complex types. //! \~russian Резервная перегрузка, которая намеренно завершает компиляцию ошибкой для неподдерживаемых сложных типов. template::value, int>::type = 0, typename std::enable_if::value, int>::type = 0> inline PIJSON piSerializeJSON(const T & v) { static_assert(std::is_enum::value || std::is_arithmetic::value, "[piSerializeJSON] Error: using undeclared piSerializeJSON() for complex type!"); return {}; } // known types //! \~english Returns JSON node unchanged. //! \~russian Возвращает JSON-узел без изменений. inline PIJSON piSerializeJSON(const PIJSON & v) { return v; } template<> //! \~english Serializes %PIVariant as the matching scalar JSON node. //! \~russian Сериализует %PIVariant в соответствующий скалярный JSON-узел. inline PIJSON piSerializeJSON(const PIVariant & v) { return PIJSON() = v; } template //! \~english Serializes complex number as array [real, imag]. //! \~russian Сериализует комплексное число как массив [real, imag]. inline PIJSON piSerializeJSON(const complex & v) { PIJSON ret; ret << v.real() << v.imag(); return ret; } template //! \~english Serializes %PIFlags as an integer mask. //! \~russian Сериализует %PIFlags как целочисленную маску. inline PIJSON piSerializeJSON(const PIFlags & v) { return PIJSON() = (int)v; } template<> //! \~english Serializes %PIString as JSON string. //! \~russian Сериализует %PIString как JSON-строку. inline PIJSON piSerializeJSON(const PIString & v) { return PIJSON() = v; } template<> //! \~english Serializes %PIConstChars as JSON string. //! \~russian Сериализует %PIConstChars как JSON-строку. inline PIJSON piSerializeJSON(const PIConstChars & v) { return PIJSON() = v.toString(); } template<> //! \~english Serializes %PIByteArray as Base64 string. //! \~russian Сериализует %PIByteArray как строку Base64. inline PIJSON piSerializeJSON(const PIByteArray & v) { return PIJSON() = PIStringAscii(v.toBase64()); } template<> //! \~english Serializes %PISystemTime as object with fields \c s and \c ns. //! \~russian Сериализует %PISystemTime как объект с полями \c s и \c ns. inline PIJSON piSerializeJSON(const PISystemTime & v) { PIJSON ret; ret["s"] = v.seconds; ret["ns"] = v.nanoseconds; return ret; } template<> //! \~english Serializes %PITime as object with fields \c h, \c m, \c s and \c z. //! \~russian Сериализует %PITime как объект с полями \c h, \c m, \c s и \c z. inline PIJSON piSerializeJSON(const PITime & v) { PIJSON ret; ret["h"] = v.hours; ret["m"] = v.minutes; ret["s"] = v.seconds; ret["z"] = v.milliseconds; return ret; } template<> //! \~english Serializes %PIDate as object with fields \c y, \c M and \c d. //! \~russian Сериализует %PIDate как объект с полями \c y, \c M и \c d. inline PIJSON piSerializeJSON(const PIDate & v) { PIJSON ret; ret["y"] = v.year; ret["M"] = v.month; ret["d"] = v.day; return ret; } template<> //! \~english Serializes %PIDateTime as object with fields \c y, \c M, \c d, \c h, \c m, \c s and \c z. //! \~russian Сериализует %PIDateTime как объект с полями \c y, \c M, \c d, \c h, \c m, \c s и \c z. inline PIJSON piSerializeJSON(const PIDateTime & v) { PIJSON ret; ret["y"] = v.year; ret["M"] = v.month; ret["d"] = v.day; ret["h"] = v.hours; ret["m"] = v.minutes; ret["s"] = v.seconds; ret["z"] = v.milliseconds; return ret; } template<> //! \~english Serializes %PINetworkAddress as string. //! \~russian Сериализует %PINetworkAddress как строку. inline PIJSON piSerializeJSON(const PINetworkAddress & v) { return PIJSON() = v.toString(); } template //! \~english Serializes %PIPoint as object with fields \c x and \c y. //! \~russian Сериализует %PIPoint как объект с полями \c x и \c y. inline PIJSON piSerializeJSON(const PIPoint & v) { PIJSON ret; ret["x"] = piSerializeJSON(v.x); ret["y"] = piSerializeJSON(v.y); return ret; } template //! \~english Serializes %PILine as object with fields \c p0 and \c p1. //! \~russian Сериализует %PILine как объект с полями \c p0 и \c p1. inline PIJSON piSerializeJSON(const PILine & v) { PIJSON ret; ret["p0"] = piSerializeJSON(v.p0); ret["p1"] = piSerializeJSON(v.p1); return ret; } template //! \~english Serializes %PIRect as object with fields \c bl and \c tr. //! \~russian Сериализует %PIRect как объект с полями \c bl и \c tr. inline PIJSON piSerializeJSON(const PIRect & v) { PIJSON ret; ret["bl"] = piSerializeJSON(v.bottomLeft()); ret["tr"] = piSerializeJSON(v.topRigth()); return ret; } // containers //! \~english Serializes %PIPair as two-element array. //! \~russian Сериализует %PIPair как массив из двух элементов. template inline PIJSON piSerializeJSON(const PIPair & v) { PIJSON ret; ret << piSerializeJSON(v.first) << piSerializeJSON(v.second); return ret; } template //! \~english Serializes %PIVector as JSON array. //! \~russian Сериализует %PIVector как JSON-массив. inline PIJSON piSerializeJSON(const PIVector & v) { if (v.isEmpty()) return PIJSON::newArray(); PIJSON ret; for (const auto & i: v) ret << piSerializeJSON(i); return ret; } template //! \~english Serializes %PIDeque as JSON array. //! \~russian Сериализует %PIDeque как JSON-массив. inline PIJSON piSerializeJSON(const PIDeque & v) { if (v.isEmpty()) return PIJSON::newArray(); PIJSON ret; for (const auto & i: v) ret << piSerializeJSON(i); return ret; } template //! \~english Serializes %PIVector2D as object with \c rows, \c cols and flattened \c mat. //! \~russian Сериализует %PIVector2D как объект с \c rows, \c cols и плоским массивом \c mat. inline PIJSON piSerializeJSON(const PIVector2D & v) { PIJSON ret; ret["cols"] = static_cast(v.cols()); ret["rows"] = static_cast(v.rows()); ret["mat"] = piSerializeJSON(v.plainVector()); return ret; } template //! \~english Serializes %PISet as JSON array. //! \~russian Сериализует %PISet как JSON-массив. inline PIJSON piSerializeJSON(const PISet & v) { if (v.isEmpty()) return PIJSON::newArray(); PIJSON ret; for (const auto & i: v) ret << piSerializeJSON(i); return ret; } template //! \~english Serializes %PIMap as JSON object with stringified keys. //! \~russian Сериализует %PIMap как JSON-объект со строковыми ключами. inline PIJSON piSerializeJSON(const PIMap & v) { if (v.isEmpty()) return PIJSON::newObject(); PIJSON ret; auto it = v.makeIterator(); while (it.next()) ret[PIVariant(it.key()).toString()] = piSerializeJSON(it.value()); return ret; } template //! \~english Serializes %PIMathVector as JSON array. //! \~russian Сериализует %PIMathVector как JSON-массив. inline PIJSON piSerializeJSON(const PIMathVector & v) { PIJSON ret; for (uint i = 0; i < v.size(); ++i) ret << piSerializeJSON(v[i]); return ret; } template //! \~english Serializes fixed-size %PIMathVectorT as JSON array. //! \~russian Сериализует %PIMathVectorT фиксированного размера как JSON-массив. inline PIJSON piSerializeJSON(const PIMathVectorT & v) { PIJSON ret; for (uint i = 0; i < v.size(); ++i) ret << piSerializeJSON(v[i]); return ret; } // --- // deserialize, piDeserializeJSON(T, PIJSON) // --- // enum & arithmetic //! \~english Deserializes enum value from JSON number. //! \~russian Десериализует значение перечисления из JSON-числа. template::value, int>::type = 0> inline void piDeserializeJSON(T & v, const PIJSON & js) { v = (T)js.toInt(); } //! \~english Deserializes arithmetic value from JSON scalar. //! \~russian Десериализует арифметическое значение из JSON-скаляра. template::value, int>::type = 0, typename std::enable_if::value, int>::type = 0> inline void piDeserializeJSON(T & v, const PIJSON & js) { v = js.value().value(); } //! \~english Fallback overload that intentionally fails for unsupported complex types. //! \~russian Резервная перегрузка, которая намеренно завершает компиляцию ошибкой для неподдерживаемых сложных типов. template::value, int>::type = 0, typename std::enable_if::value, int>::type = 0> inline void piDeserializeJSON(T & v, const PIJSON & js) { static_assert(std::is_enum::value || std::is_arithmetic::value, "[piDeserializeJSON] Error: using undeclared piDeserializeJSON() for complex type!"); v = {}; } // known types //! \~english Copies JSON node as-is. //! \~russian Копирует JSON-узел без изменений. inline void piDeserializeJSON(PIJSON & v, const PIJSON & js) { v = js; } template<> //! \~english Extracts scalar value from JSON node into %PIVariant. //! \~russian Извлекает скалярное значение JSON-узла в %PIVariant. inline void piDeserializeJSON(PIVariant & v, const PIJSON & js) { v = js.value(); } template //! \~english Deserializes complex number from array [real, imag]. //! \~russian Десериализует комплексное число из массива [real, imag]. inline void piDeserializeJSON(complex & v, const PIJSON & js) { if (!js.isArray()) return; piDeserializeJSON(reinterpret_cast(v)[0], js[0]); piDeserializeJSON(reinterpret_cast(v)[1], js[1]); } template //! \~english Deserializes %PIFlags from integer mask. //! \~russian Десериализует %PIFlags из целочисленной маски. inline void piDeserializeJSON(PIFlags & v, const PIJSON & js) { v = js.toInt(); } template<> //! \~english Deserializes %PIString from JSON string representation. //! \~russian Десериализует %PIString из строкового представления JSON. inline void piDeserializeJSON(PIString & v, const PIJSON & js) { v = js.toString(); } template<> //! \~english Deserializes %PIByteArray from Base64 string. //! \~russian Десериализует %PIByteArray из строки Base64. inline void piDeserializeJSON(PIByteArray & v, const PIJSON & js) { v = PIByteArray::fromBase64(js.toString()); } template<> //! \~english Deserializes %PISystemTime from object with fields \c s and \c ns. //! \~russian Десериализует %PISystemTime из объекта с полями \c s и \c ns. inline void piDeserializeJSON(PISystemTime & v, const PIJSON & js) { piDeserializeJSON(v.seconds, js["s"]); piDeserializeJSON(v.nanoseconds, js["ns"]); } template<> //! \~english Deserializes %PITime from object with fields \c h, \c m, \c s and \c z. //! \~russian Десериализует %PITime из объекта с полями \c h, \c m, \c s и \c z. inline void piDeserializeJSON(PITime & v, const PIJSON & js) { v.hours = js["h"].toInt(); v.minutes = js["m"].toInt(); v.seconds = js["s"].toInt(); v.milliseconds = js["z"].toInt(); } template<> //! \~english Deserializes %PIDate from object with fields \c y, \c M and \c d. //! \~russian Десериализует %PIDate из объекта с полями \c y, \c M и \c d. inline void piDeserializeJSON(PIDate & v, const PIJSON & js) { v.year = js["y"].toInt(); v.month = js["M"].toInt(); v.day = js["d"].toInt(); } template<> //! \~english Deserializes %PIDateTime from object with fields \c y, \c M, \c d, \c h, \c m, \c s and \c z. //! \~russian Десериализует %PIDateTime из объекта с полями \c y, \c M, \c d, \c h, \c m, \c s и \c z. inline void piDeserializeJSON(PIDateTime & v, const PIJSON & js) { v.year = js["y"].toInt(); v.month = js["M"].toInt(); v.day = js["d"].toInt(); v.hours = js["h"].toInt(); v.minutes = js["m"].toInt(); v.seconds = js["s"].toInt(); v.milliseconds = js["z"].toInt(); } template<> //! \~english Deserializes %PINetworkAddress from string. //! \~russian Десериализует %PINetworkAddress из строки. inline void piDeserializeJSON(PINetworkAddress & v, const PIJSON & js) { v = PINetworkAddress(js.toString()); } template //! \~english Deserializes %PIPoint from object with fields \c x and \c y. //! \~russian Десериализует %PIPoint из объекта с полями \c x и \c y. inline void piDeserializeJSON(PIPoint & v, const PIJSON & js) { piDeserializeJSON(v.x, js["x"]); piDeserializeJSON(v.y, js["y"]); } template //! \~english Deserializes %PILine from object with fields \c p0 and \c p1. //! \~russian Десериализует %PILine из объекта с полями \c p0 и \c p1. inline void piDeserializeJSON(PILine & v, const PIJSON & js) { piDeserializeJSON(v.p0, js["p0"]); piDeserializeJSON(v.p1, js["p1"]); } template //! \~english Deserializes %PIRect from object with fields \c bl and \c tr. //! \~russian Десериализует %PIRect из объекта с полями \c bl и \c tr. inline void piDeserializeJSON(PIRect & v, const PIJSON & js) { PIPoint bl, tr; piDeserializeJSON(bl, js["bl"]); piDeserializeJSON(tr, js["tr"]); v = PIRect(bl, tr); } // containers //! \~english Deserializes %PIPair from two-element array. //! \~russian Десериализует %PIPair из массива из двух элементов. template inline void piDeserializeJSON(PIPair & v, const PIJSON & js) { v = {}; if (!js.isArray()) return; piDeserializeJSON(v.first, js[0]); piDeserializeJSON(v.second, js[1]); } template //! \~english Deserializes %PIVector from JSON array. //! \~russian Десериализует %PIVector из JSON-массива. inline void piDeserializeJSON(PIVector & v, const PIJSON & js) { v.clear(); if (!js.isArray()) return; v.resize(js.size()); for (int i = 0; i < js.size(); ++i) piDeserializeJSON(v[i], js[i]); } template //! \~english Deserializes %PIDeque from JSON array. //! \~russian Десериализует %PIDeque из JSON-массива. inline void piDeserializeJSON(PIDeque & v, const PIJSON & js) { v.clear(); if (!js.isArray()) return; v.resize(js.size()); for (int i = 0; i < js.size(); ++i) piDeserializeJSON(v[i], js[i]); } template //! \~english Deserializes %PIVector2D from object with \c rows, \c cols and flattened \c mat. //! \~russian Десериализует %PIVector2D из объекта с \c rows, \c cols и плоским массивом \c mat. inline void piDeserializeJSON(PIVector2D & v, const PIJSON & js) { v.clear(); if (!js.isObject()) return; const auto & mat(js["mat"]); if (!mat.isArray()) return; piDeserializeJSON(v.plainVector(), mat); v.resize(js["rows"].toInt(), js["cols"].toInt()); } template //! \~english Deserializes %PISet from JSON array. //! \~russian Десериализует %PISet из JSON-массива. inline void piDeserializeJSON(PISet & v, const PIJSON & js) { v.clear(); if (!js.isArray()) return; T _t; for (int i = 0; i < js.size(); ++i) { piDeserializeJSON(_t, js[i]); v << _t; } } template //! \~english Deserializes %PIMap from JSON object with stringified keys. //! \~russian Десериализует %PIMap из JSON-объекта со строковыми ключами. inline void piDeserializeJSON(PIMap & v, const PIJSON & js) { v.clear(); if (!js.isObject()) return; const auto & obj(js.object()); auto it = obj.makeIterator(); while (it.next()) piDeserializeJSON(v[PIVariant(it.key()).value()], it.value()); } template //! \~english Deserializes dynamic %PIMathVector from JSON array. //! \~russian Десериализует динамический %PIMathVector из JSON-массива. inline void piDeserializeJSON(PIMathVector & v, const PIJSON & js) { v = {}; if (!js.isArray()) return; v = PIMathVector(js.size()); for (int i = 0; i < js.size(); ++i) piDeserializeJSON(v[i], js[i]); } template //! \~english Deserializes fixed-size %PIMathVectorT from JSON array, truncating extra items. //! \~russian Десериализует %PIMathVectorT фиксированного размера из JSON-массива, отбрасывая лишние элементы. inline void piDeserializeJSON(PIMathVectorT & v, const PIJSON & js) { v = PIMathVectorT(); if (!js.isArray()) return; int cnt = piMini(js.size(), Size); for (int i = 0; i < cnt; ++i) piDeserializeJSON(v[i], js[i]); } // --- // PIJSON static wrapper // --- template //! \~english Convenience wrapper around \a piSerializeJSON(). //! \~russian Вспомогательная обертка над \a piSerializeJSON(). PIJSON PIJSON::serialize(const T & v) { return piSerializeJSON(v); } template //! \~english Convenience wrapper around \a piDeserializeJSON(). //! \~russian Вспомогательная обертка над \a piDeserializeJSON(). T PIJSON::deserialize(const PIJSON & json) { T ret; piDeserializeJSON(ret, json); return ret; } #endif // PIJSONSERIALIZATION_H