#pragma once #include "fwd.h" #include "value.h" #include <library/cpp/json/json_value.h> #include <util/generic/hash.h> #include <util/generic/ptr.h> #include <util/generic/deque.h> #include <util/system/type_name.h> #include <util/generic/vector.h> #include <util/generic/yexception.h> #include <util/generic/bt_exception.h> #include <util/ysaveload.h> class IInputStream; class IOutputStream; namespace NConfig { typedef THashMap<TString, NJson::TJsonValue> TGlobals; class TConfigError: public TWithBackTrace<yexception> { }; class TConfigParseError: public TConfigError { }; class TTypeMismatch: public TConfigError { }; struct TArray; struct TDict; class TConfig { public: inline TConfig() : V_(Null()) { } inline TConfig(IValue* v) : V_(v) { } TConfig(const TConfig& config) = default; TConfig& operator=(const TConfig& config) = default; template <class T> inline bool IsA() const { return V_->IsA(typeid(T)); } inline bool IsNumeric() const { return IsA<double>() || IsA<i64>() || IsA<ui64>(); } template <class T> inline const T& Get() const { return GetNonConstant<T>(); } template <class T> inline T& GetNonConstant() const { if (this->IsA<T>()) { return *(T*)V_->Ptr(); } if constexpr (std::is_same_v<T, ::NConfig::TArray>) { NCfgPrivate::ReportTypeMismatch(V_->TypeName(), "array"); } else if constexpr (std::is_same_v<T, ::NConfig::TDict>) { NCfgPrivate::ReportTypeMismatch(V_->TypeName(), "dict"); } else if constexpr (std::is_same_v<T, TString>) { NCfgPrivate::ReportTypeMismatch(V_->TypeName(), "string"); } else { NCfgPrivate::ReportTypeMismatch(V_->TypeName(), ::TypeName<T>()); } } template <class T> inline T As() const { return ValueAs<T>(V_.Get()); } template <class T> inline T As(T def) const { return IsNull() ? def : As<T>(); } inline bool IsNull() const noexcept { return V_.Get() == Null(); } const TConfig& Or(const TConfig& r) const { return IsNull() ? r : *this; } //assume value is dict bool Has(const TStringBuf& key) const; const TConfig& operator[](const TStringBuf& key) const; const TConfig& At(const TStringBuf& key) const; //assume value is array const TConfig& operator[](size_t index) const; size_t GetArraySize() const; static TConfig FromIni(IInputStream& in, const TGlobals& g = TGlobals()); static TConfig FromJson(IInputStream& in, const TGlobals& g = TGlobals()); static TConfig FromLua(IInputStream& in, const TGlobals& g = TGlobals()); //load yconf format. unsafe, but natural mapping static TConfig FromMarkup(IInputStream& in, const TGlobals& g = TGlobals()); static TConfig FromStream(IInputStream& in, const TGlobals& g = TGlobals()); inline void ToJson(IOutputStream& out) const { V_->ToJson(out); } void DumpJson(IOutputStream& out) const; void DumpLua(IOutputStream& out) const; static TConfig ReadJson(TStringBuf in, const TGlobals& g = TGlobals()); static TConfig ReadLua(TStringBuf in, const TGlobals& g = TGlobals()); static TConfig ReadMarkup(TStringBuf in, const TGlobals& g = TGlobals()); static TConfig ReadIni(TStringBuf in, const TGlobals& g = TGlobals()); void Load(IInputStream* stream); void Save(IOutputStream* stream) const; private: TIntrusivePtr<IValue> V_; }; struct TArray: public TDeque<TConfig> { const TConfig& Index(size_t index) const; const TConfig& At(size_t index) const; }; struct TDict: public THashMap<TString, TConfig> { const TConfig& Find(const TStringBuf& key) const; const TConfig& At(const TStringBuf& key) const; }; THolder<IInputStream> CreatePreprocessor(const TGlobals& g, IInputStream& in); }