#include #include #include "types.hh" #pragma once namespace nix { class Args; class AbstractSetting; /* A class to simplify providing configuration settings. The typical use is to inherit Config and add Setting members: class MyClass : private Config { Setting foo{this, 123, "foo", "the number of foos to use"}; Setting bar{this, "blabla", "bar", "the name of the bar"}; MyClass() : Config(readConfigFile("/etc/my-app.conf")) { std::cout << foo << "\n"; // will print 123 unless overriden } }; */ class Config { friend class AbstractSetting; struct SettingData { bool isAlias = false; AbstractSetting * setting; }; std::map _settings; StringMap initials; public: Config(const StringMap & initials) : initials(initials) { } void set(const std::string & name, const std::string & value); void add(AbstractSetting * setting); void warnUnused(); std::string dump(); }; class AbstractSetting { friend class Config; public: const std::string name; const std::string description; const std::set aliases; int created = 123; protected: AbstractSetting( const std::string & name, const std::string & description, const std::set & aliases); virtual ~AbstractSetting() { // Check against a gcc miscompilation causing our constructor // not to run. assert(created == 123); } virtual void set(const std::string & value) = 0; virtual std::string to_string() = 0; }; /* A setting of type T. */ template class Setting : public AbstractSetting { protected: T value; public: Setting(Config * options, const T & def, const std::string & name, const std::string & description, const std::set & aliases = {}) : AbstractSetting(name, description, aliases) , value(def) { options->add(this); } operator const T &() const { return value; } bool operator ==(const T & v2) const { return value == v2; } bool operator !=(const T & v2) const { return value != v2; } void operator =(const T & v) { value = v; } void set(const std::string & str) override; std::string to_string() override; }; template std::ostream & operator <<(std::ostream & str, const Setting & opt) { str << (const T &) opt; return str; } /* A special setting for Paths. These are automatically canonicalised (e.g. "/foo//bar/" becomes "/foo/bar"). */ class PathSetting : public Setting { bool allowEmpty; public: PathSetting(Config * options, bool allowEmpty, const Path & def, const std::string & name, const std::string & description, const std::set & aliases = {}) : Setting(options, def, name, description, aliases) , allowEmpty(allowEmpty) { set(value); } void set(const std::string & str) override; Path operator +(const char * p) const { return value + p; } }; }