#pragma once #include "library/cpp/json/writer/json_value.h" #include <limits> #include <util/generic/array_ref.h> #include <util/generic/deque.h> #include <util/generic/hash.h> #include <util/generic/list.h> #include <util/generic/map.h> #include <util/generic/maybe.h> namespace NJson { template<typename T> struct TConverter { }; namespace { template<typename T> struct TDefaultEncoder { static inline TJsonValue Encode(T value) { return TJsonValue(value); } }; template<typename T, typename E> struct TDefaultArrayEncoder { static TJsonValue Encode(const T& value) { TJsonValue result(NJson::JSON_ARRAY); auto& encodedArray = result.GetArraySafe(); for (const auto& element : value) { encodedArray.push_back(TConverter<E>::Encode(element)); } return result; } }; template<typename T, typename E> struct TDefaultArrayDecoder { static T Decode(const TJsonValue& value) { T result; for (const auto& element : value.GetArraySafe()) { result.push_back(TConverter<E>::Decode(element)); } return result; } }; template<typename T, typename E> struct TDefaultArrayConverter: public TDefaultArrayEncoder<T, E>, public TDefaultArrayDecoder<T, E> { }; template<typename T, typename E> struct TDefaultMapEncoder { static TJsonValue Encode(const T& value) { TJsonValue result(NJson::JSON_MAP); auto& encodedMap = result.GetMapSafe(); for (const auto& [key, element] : value) { encodedMap[key] = TConverter<E>::Encode(element); } return result; } }; template<typename T, typename E> struct TDefaultMapDecoder { static T Decode(const TJsonValue& value) { T result; for (const auto& [key, element] : value.GetMapSafe()) { result[key] = TConverter<E>::Decode(element); } return result; } }; template<typename T, typename E> struct TDefaultMapConverter: public TDefaultMapEncoder<T, E>, public TDefaultMapDecoder<T, E> { }; } template<> struct TConverter<TJsonValue> { static TJsonValue Encode(const TJsonValue& value) { return value; } static TJsonValue Decode(const TJsonValue& value) { return value; } }; template<> struct TConverter<bool>: public TDefaultEncoder<bool> { static inline bool Decode(const TJsonValue& value) { return value.GetBooleanSafe(); } }; template<typename T> requires std::is_integral_v<T> && (!std::is_same_v<T, bool>) struct TConverter<T>: public TDefaultEncoder<T> { static T Decode(const TJsonValue& value) { if constexpr (std::is_signed_v<T>) { const auto decodedValue = value.GetIntegerSafe(); if (decodedValue < std::numeric_limits<T>::min() || std::numeric_limits<T>::max() < decodedValue) { ythrow yexception() << "Out of range (got " << decodedValue << ")"; } return static_cast<T>(decodedValue); } else { const auto decodedValue = value.GetUIntegerSafe(); if (std::numeric_limits<T>::max() < decodedValue) { ythrow yexception() << "Out of range (got " << decodedValue << ")"; } return static_cast<T>(decodedValue); } } }; template<typename T> requires std::is_floating_point_v<T> struct TConverter<T>: public TDefaultEncoder<T> { static inline T Decode(const TJsonValue& value) { return static_cast<T>(value.GetDoubleSafe()); } }; template<> struct TConverter<TStringBuf>: public TDefaultEncoder<TStringBuf> { }; template<> struct TConverter<TString>: public TDefaultEncoder<TString> { static inline TString Decode(const TJsonValue& value) { return value.GetStringSafe(); } }; template<typename T> struct TConverter<TMaybe<T>> { static TJsonValue Encode(const TMaybe<T>& value) { if (value.Defined()) { return TConverter<T>::Encode(*value); } else { return TJsonValue(NJson::JSON_NULL); } } static TMaybe<T> Decode(const TJsonValue& value) { if (value.IsDefined()) { return TConverter<T>::Decode(value); } else { return Nothing(); } } }; template<typename T> struct TConverter<TArrayRef<T>>: public TDefaultArrayEncoder<TArrayRef<T>, T> { }; template<typename T> struct TConverter<TVector<T>>: public TDefaultArrayConverter<TVector<T>, T> { }; template<typename T> struct TConverter<TList<T>>: public TDefaultArrayConverter<TList<T>, T> { }; template<typename T> struct TConverter<TDeque<T>>: public TDefaultArrayConverter<TDeque<T>, T> { }; template<typename T> struct TConverter<THashMap<TStringBuf, T>>: public TDefaultMapEncoder<THashMap<TStringBuf, T>, T> { }; template<typename T> struct TConverter<THashMap<TString, T>>: public TDefaultMapConverter<THashMap<TString, T>, T> { }; template<typename T> struct TConverter<TMap<TStringBuf, T>>: public TDefaultMapEncoder<TMap<TStringBuf, T>, T> { }; template<typename T> struct TConverter<TMap<TString, T>>: public TDefaultMapConverter<TMap<TString, T>, T> { }; }