#include "value.h"
#include "config.h"
#include <library/cpp/string_utils/relaxed_escaper/relaxed_escaper.h>
#include <util/generic/algorithm.h>
#include <util/system/type_name.h>
#include <util/generic/singleton.h>
#include <util/string/cast.h>
#include <util/string/strip.h>
#include <util/string/type.h>
using namespace NConfig;
namespace {
template <class T>
class TValue: public IValue {
public:
inline TValue(const T& t)
: T_(t)
{
}
bool IsA(const std::type_info& info) const override {
return info == typeid(T);
}
TString TypeName() const override {
return ::TypeName<T>();
}
void* Ptr() const override {
return (void*)&T_;
}
void ToJson(IOutputStream& out) const override {
out << AsString();
}
bool AsBool() const override {
return (bool)AsDouble();
}
protected:
T T_;
};
class TNullValue: public TValue<TNull> {
public:
inline TNullValue()
: TValue<TNull>(TNull())
{
Ref();
}
double AsDouble() const override {
return 0;
}
ui64 AsUInt() const override {
return 0;
}
i64 AsInt() const override {
return 0;
}
TString AsString() const override {
return TString();
}
void ToJson(IOutputStream& out) const override {
out << "null";
}
TString TypeName() const override {
return "null";
}
};
template <class T>
class TNumericValue: public TValue<T> {
public:
inline TNumericValue(const T& t)
: TValue<T>(t)
{
}
double AsDouble() const override {
return this->T_;
}
ui64 AsUInt() const override {
return this->T_;
}
i64 AsInt() const override {
return this->T_;
}
};
class TBoolValue: public TNumericValue<bool> {
public:
inline TBoolValue(bool v)
: TNumericValue<bool>(v)
{
}
TString AsString() const override {
return T_ ? "true" : "false";
}
};
template <class T>
class TArithmeticValue: public TNumericValue<T> {
public:
inline TArithmeticValue(T v)
: TNumericValue<T>(v)
{
}
TString AsString() const override {
return ToString(this->T_);
}
};
class TStringValue: public TValue<TString> {
public:
inline TStringValue(const TString& v)
: TValue<TString>(v)
{
}
template <class T>
inline T AsT() const {
const TStringBuf s = StripString(TStringBuf(T_));
if (IsTrue(s)) {
return true;
}
if (IsFalse(s)) {
return false;
}
return FromString<T>(s);
}
double AsDouble() const override {
return AsT<double>();
}
ui64 AsUInt() const override {
return AsT<ui64>();
}
i64 AsInt() const override {
return AsT<i64>();
}
TString AsString() const override {
return T_;
}
void ToJson(IOutputStream& out) const override {
NEscJ::EscapeJ<true, true>(T_, out);
}
TString TypeName() const override {
return "string";
}
};
template <class T>
class TContainer: public TValue<T> {
public:
inline TContainer(const T& t)
: TValue<T>(t)
{
}
double AsDouble() const override {
NCfgPrivate::ReportTypeMismatch(this->TypeName(), "double");
}
ui64 AsUInt() const override {
NCfgPrivate::ReportTypeMismatch(this->TypeName(), "uint");
}
i64 AsInt() const override {
NCfgPrivate::ReportTypeMismatch(this->TypeName(), "int");
}
bool AsBool() const override {
NCfgPrivate::ReportTypeMismatch(this->TypeName(), "bool");
}
TString AsString() const override {
NCfgPrivate::ReportTypeMismatch(this->TypeName(), "string");
}
};
class TArrayValue: public TContainer<TArray> {
public:
inline TArrayValue(const TArray& v)
: TContainer<TArray>(v)
{
}
void ToJson(IOutputStream& s) const override {
s << "[";
for (TArray::const_iterator it = T_.begin(); it != T_.end(); ++it) {
if (it != T_.begin()) {
s << ",";
}
it->ToJson(s);
}
s << "]";
}
TString TypeName() const override {
return "array";
}
};
class TDictValue: public TContainer<TDict> {
public:
inline TDictValue(const TDict& v)
: TContainer<TDict>(v)
{
}
void ToJson(IOutputStream& s) const override {
s << "{";
TVector<TStringBuf> buf;
buf.reserve(T_.size());
for (const auto& t : T_) {
buf.push_back(t.first);
}
Sort(buf.begin(), buf.end());
for (TVector<TStringBuf>::const_iterator kit = buf.begin(); kit != buf.end(); ++kit) {
TStringBuf key = *kit;
TDict::const_iterator it = T_.find(key);
if (kit != buf.begin()) {
s << ",";
}
NEscJ::EscapeJ<true, true>(key, s);
s << ":";
it->second.ToJson(s);
}
s << "}";
}
TString TypeName() const override {
return "dict";
}
};
}
#define DECLARE(type1, type2) \
IValue* ConstructValueImpl(const type2& t) { \
return new type1(t); \
}
namespace NConfig {
namespace NCfgPrivate {
DECLARE(TBoolValue, bool)
DECLARE(TArithmeticValue<double>, double)
DECLARE(TArithmeticValue<i64>, i64)
DECLARE(TArithmeticValue<ui64>, ui64)
DECLARE(TStringValue, TString)
DECLARE(TArrayValue, TArray)
DECLARE(TDictValue, TDict)
}
IValue* Null() {
return Singleton<TNullValue>();
}
[[noreturn]] void NCfgPrivate::ReportTypeMismatch(TStringBuf realType, TStringBuf expectedType) {
ythrow TTypeMismatch() << "type mismatch (real: " << realType << ", expected: " << expectedType << ')';
}
}