#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> {
};
}