#pragma once
#include <util/generic/set.h>
#include <util/generic/vector.h>
#include <util/generic/map.h>
#include <util/generic/hash.h>
#include <util/generic/hash_set.h>
#include <util/string/cast.h>
#include <util/generic/yexception.h>
#include "scheme.h"
namespace NJsonConverters {
class IJsonSerializable {
public:
virtual NSc::TValue ToTValue() const = 0;
virtual void FromTValue(const NSc::TValue&, const bool validate) = 0;
const TString ToJson(const bool sort = false) const {
return ToTValue().ToJson(sort);
};
void FromJson(const TStringBuf& json, const bool validate = false) {
NSc::TValue v = NSc::TValue::FromJson(json);
FromTValue(v, validate);
}
virtual ~IJsonSerializable(){};
};
//////////////////////////////////////////////////////////////////////
// fwd declarations
//////////////////////////////////////////////////////////////////////
//TVector
template <typename T, typename A>
NSc::TValue ToTValue(const TVector<T, A>& x);
template <typename T, typename A>
void FromTValue(const NSc::TValue& x, TVector<T, A>& out, const bool validate);
//THashMap
template <class Key, class T, class HashFcn, class EqualKey, class Alloc>
NSc::TValue ToTValue(const THashMap<Key, T, HashFcn, EqualKey, Alloc>& x);
template <class Key, class T, class HashFcn, class EqualKey, class Alloc>
void FromTValue(const NSc::TValue& x, THashMap<Key, T, HashFcn, EqualKey, Alloc>& out, const bool validate);
//TMap
template <class K, class V, class Less, class A>
NSc::TValue ToTValue(const TMap<K, V, Less, A>& x);
template <class K, class V, class Less, class A>
void FromTValue(const NSc::TValue& x, TMap<K, V, Less, A>& out, const bool validate);
//THashSet
template <class V, class H, class E, class A>
NSc::TValue ToTValue(const THashSet<V, H, E, A>& x);
template <class V, class H, class E, class A>
void FromTValue(const NSc::TValue& x, THashSet<V, H, E, A>& out, const bool validate);
//TSet
template <class K, class L, class A>
NSc::TValue ToTValue(const TSet<K, L, A>& x);
template <class K, class L, class A>
void FromTValue(const NSc::TValue& x, TSet<K, L, A>& out, const bool validate);
//std::pair
template <class T1, class T2>
NSc::TValue ToTValue(const std::pair<T1, T2>& x);
template <class T1, class T2>
void FromTValue(const NSc::TValue& x, std::pair<T1, T2>& out, const bool validate);
//////////////////////////////////////////////////////////////////////
// simple From, To helpers
//////////////////////////////////////////////////////////////////////
template <typename T, bool HasSerializer>
struct TValueAndStrokaConv {};
template <typename T>
struct TValueAndStrokaConv<T, 0> {
static NSc::TValue ToTValue(const T& x) {
return NSc::TValue(x);
}
static void FromTValue(const NSc::TValue& x, T& out, const bool) {
out = x;
}
static TString ToString(const T& x) {
return ::ToString(x);
}
static void FromString(const TStringBuf& str, T& res, const bool) {
res = ::FromString<T>(str);
}
};
template <typename T>
struct TValueAndStrokaConv<T, 1> {
static NSc::TValue ToTValue(const T& x) {
return x.ToTValue();
}
static void FromTValue(const NSc::TValue& x, T& out, const bool validate) {
out.FromTValue(x, validate);
}
static TString ToString(const T& x) {
return x.ToJson();
}
static void FromString(const TStringBuf& str, T& res, const bool validate) {
res.FromJson(str, validate);
}
};
template <typename T>
NSc::TValue ToTValue(const T& x) {
return TValueAndStrokaConv<T, std::is_base_of<IJsonSerializable, T>::value>::ToTValue(x);
}
template <typename T>
void FromTValue(const NSc::TValue& x, T& out, const bool validate) {
return TValueAndStrokaConv<T, std::is_base_of<IJsonSerializable, T>::value>::FromTValue(x, out, validate);
}
template <typename T>
T FromTValue(const NSc::TValue& x, const bool validate) {
T ret;
FromTValue(x, ret, validate);
return ret;
}
template <typename T>
TString ToString(const T& x) {
return TValueAndStrokaConv<T, std::is_base_of<IJsonSerializable, T>::value>::ToString(x);
}
template <typename T>
void FromString(const TStringBuf& str, T& res, const bool validate) {
return TValueAndStrokaConv<T, std::is_base_of<IJsonSerializable, T>::value>::FromString(str, res, validate);
}
template <typename T>
T FromString(const TStringBuf& str, bool validate) {
T ret;
FromString(str, ret, validate);
return ret;
}
namespace NPrivate {
template <typename T>
NSc::TValue ToTValueDict(const T& dict) {
NSc::TValue out;
out.SetDict();
for (typename T::const_iterator it = dict.begin(); it != dict.end(); ++it) {
out[ToString(it->first)] = NJsonConverters::ToTValue(it->second);
}
return out;
}
template <typename T>
void FromTValueDict(const NSc::TValue& x, T& out, bool validate) {
typedef typename T::key_type TKey;
typedef typename T::mapped_type TMapped;
if (validate)
Y_ENSURE(x.IsDict() || x.IsNull(), "not valid input scheme");
out.clear();
if (x.IsDict()) {
const NSc::TDict& dict = x.GetDict();
for (const auto& it : dict) {
TKey key = NJsonConverters::FromString<TKey>(it.first, validate);
TMapped val = NJsonConverters::FromTValue<TMapped>(it.second, validate);
out.insert(std::pair<TKey, TMapped>(key, val));
}
}
}
template <typename T>
NSc::TValue ToTValueSet(const T& set) {
NSc::TValue out;
out.SetDict();
for (typename T::const_iterator it = set.begin(); it != set.end(); ++it) {
out[ToString(*it)] = NSc::Null();
}
return out;
}
template <typename T>
void FromTValueSet(const NSc::TValue& x, T& out, const bool validate) {
typedef typename T::key_type TKey;
if (validate)
Y_ENSURE(x.IsDict() || x.IsNull(), "not valid input scheme");
out.clear();
if (x.IsDict()) {
const NSc::TDict& dict = x.GetDict();
for (const auto& it : dict) {
TKey key;
NJsonConverters::FromString<TKey>(it.first, key, validate);
out.insert(key);
}
}
}
}
//////////////////////////////////////////////////////////////////////
// TVector
//////////////////////////////////////////////////////////////////////
template <typename T, typename A>
NSc::TValue ToTValue(const TVector<T, A>& x) {
NSc::TValue out;
out.SetArray();
for (typename TVector<T, A>::const_iterator it = x.begin(); it != x.end(); ++it)
out.Push(NJsonConverters::ToTValue(*it));
return out;
}
template <typename T, typename A>
void FromTValue(const NSc::TValue& x, TVector<T, A>& out, const bool validate) {
if (validate)
Y_ENSURE(x.IsArray() || x.IsNull(), "not valid input scheme");
out.clear();
if (x.IsArray()) {
const NSc::TArray& arr = x.GetArray();
out.reserve(arr.size());
for (const auto& it : arr) {
T val;
NJsonConverters::FromTValue(it, val, validate);
out.push_back(val);
}
}
}
//////////////////////////////////////////////////////////////////////
// THashMap & TMap
//////////////////////////////////////////////////////////////////////
template <class Key, class T, class HashFcn, class EqualKey, class Alloc>
NSc::TValue ToTValue(const THashMap<Key, T, HashFcn, EqualKey, Alloc>& x) {
return NPrivate::ToTValueDict(x);
}
template <class Key, class T, class HashFcn, class EqualKey, class Alloc>
void FromTValue(const NSc::TValue& x, THashMap<Key, T, HashFcn, EqualKey, Alloc>& out, const bool validate) {
NPrivate::FromTValueDict(x, out, validate);
}
template <class K, class V, class Less, class A>
NSc::TValue ToTValue(const TMap<K, V, Less, A>& x) {
return NPrivate::ToTValueDict(x);
}
template <class K, class V, class Less, class A>
void FromTValue(const NSc::TValue& x, TMap<K, V, Less, A>& out, const bool validate) {
NPrivate::FromTValueDict(x, out, validate);
}
//////////////////////////////////////////////////////////////////////
// THashSet & TSet
//////////////////////////////////////////////////////////////////////
template <class V, class H, class E, class A>
NSc::TValue ToTValue(const THashSet<V, H, E, A>& x) {
return NPrivate::ToTValueSet(x);
}
template <class V, class H, class E, class A>
void FromTValue(const NSc::TValue& x, THashSet<V, H, E, A>& out, const bool validate) {
NPrivate::FromTValueSet(x, out, validate);
}
template <class K, class L, class A>
NSc::TValue ToTValue(const TSet<K, L, A>& x) {
return NPrivate::ToTValueSet(x);
}
template <class K, class L, class A>
void FromTValue(const NSc::TValue& x, TSet<K, L, A>& out, const bool validate) {
NPrivate::FromTValueSet(x, out, validate);
}
//////////////////////////////////////////////////////////////////////
// std::pair
//////////////////////////////////////////////////////////////////////
template <class T1, class T2>
NSc::TValue ToTValue(const std::pair<T1, T2>& x) {
NSc::TValue out;
out.SetArray();
out.Push(NJsonConverters::ToTValue(x.first));
out.Push(NJsonConverters::ToTValue(x.second));
return out;
}
template <class T1, class T2>
void FromTValue(const NSc::TValue& x, std::pair<T1, T2>& out, const bool validate) {
if (validate)
Y_ENSURE(x.IsArray() || x.IsNull(), "not valid input scheme");
if (x.IsArray()) {
const NSc::TArray& arr = x.GetArray();
if (arr.size() == 2) {
T1 val0;
T2 val1;
NJsonConverters::FromTValue(arr[0], val0, validate);
NJsonConverters::FromTValue(arr[1], val1, validate);
out.first = val0;
out.second = val1;
}
}
}
//////////////////////////////////////////////////////////////////////
// global user functions
//////////////////////////////////////////////////////////////////////
template <typename T>
TString ToJson(const T& val, const bool sort = false) {
return NJsonConverters::ToTValue(val).ToJson(sort);
}
template <typename T>
T FromJson(const TStringBuf& json, bool validate = false) {
NSc::TValue v = NSc::TValue::FromJson(json);
T ret;
NJsonConverters::FromTValue(v, ret, validate);
return ret;
}
}