aboutsummaryrefslogtreecommitdiffstats
path: root/nihil.config
diff options
context:
space:
mode:
authorLexi Winter <lexi@le-fay.org>2025-07-01 17:07:04 +0100
committerLexi Winter <lexi@le-fay.org>2025-07-01 17:07:04 +0100
commit2e2d1bd3b6c7776b77c33b94f30ead89367a71e6 (patch)
tree54d37ffadf8e677938d9b7a28e4e9b71be1e75c1 /nihil.config
parent36427c0966faa7aecd586b397ed9b845f18172f5 (diff)
downloadnihil-2e2d1bd3b6c7776b77c33b94f30ead89367a71e6.tar.gz
nihil-2e2d1bd3b6c7776b77c33b94f30ead89367a71e6.tar.bz2
add nihil.std
Diffstat (limited to 'nihil.config')
-rw-r--r--nihil.config/CMakeLists.txt17
-rw-r--r--nihil.config/nihil.config.ccm7
-rw-r--r--nihil.config/option.cc20
-rw-r--r--nihil.config/option.ccm37
-rw-r--r--nihil.config/read.cc50
-rw-r--r--nihil.config/read.ccm47
-rw-r--r--nihil.config/store.cc14
-rw-r--r--nihil.config/store.ccm27
-rw-r--r--nihil.config/string.cc62
-rw-r--r--nihil.config/string.ccm95
-rw-r--r--nihil.config/string.test.cc32
-rw-r--r--nihil.config/tests/CMakeLists.txt13
-rw-r--r--nihil.config/tests/string.cc36
-rw-r--r--nihil.config/write.cc41
-rw-r--r--nihil.config/write.ccm42
15 files changed, 191 insertions, 349 deletions
diff --git a/nihil.config/CMakeLists.txt b/nihil.config/CMakeLists.txt
index 8a52d3c..6ed3651 100644
--- a/nihil.config/CMakeLists.txt
+++ b/nihil.config/CMakeLists.txt
@@ -2,6 +2,7 @@
add_library(nihil.config STATIC)
target_link_libraries(nihil.config PRIVATE
+ nihil.std
nihil.error
nihil.generator
nihil.posix
@@ -19,13 +20,21 @@ target_sources(nihil.config
PRIVATE
option.cc
- read.cc
store.cc
- string.cc
- write.cc
)
if(NIHIL_TESTS)
- add_subdirectory(tests)
+ add_executable(nihil.config.test
+ string.test.cc
+ )
+
+ target_link_libraries(nihil.config.test PRIVATE
+ nihil.config
+ Catch2::Catch2WithMain)
+
+ include(CTest)
+ include(Catch)
+ catch_discover_tests(nihil.config.test)
+
enable_testing()
endif()
diff --git a/nihil.config/nihil.config.ccm b/nihil.config/nihil.config.ccm
index 8957305..8eedf22 100644
--- a/nihil.config/nihil.config.ccm
+++ b/nihil.config/nihil.config.ccm
@@ -1,9 +1,4 @@
-/*
- * This source code is released into the public domain.
- */
-
-module;
-
+// This source code is released into the public domain.
export module nihil.config;
export import :option;
diff --git a/nihil.config/option.cc b/nihil.config/option.cc
index 886f4b6..e09842e 100644
--- a/nihil.config/option.cc
+++ b/nihil.config/option.cc
@@ -1,16 +1,7 @@
-/*
- * This source code is released into the public domain.
- */
-
-module;
-
-#include <coroutine>
-#include <expected>
-#include <iostream>
-#include <string>
-
+// This source code is released into the public domain.
module nihil.config;
+import nihil.std;
import nihil.error;
import nihil.monad;
import nihil.ucl;
@@ -18,7 +9,7 @@ import nihil.ucl;
namespace nihil::config {
//NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
-option::option(std::string_view name, std::string_view description)
+option::option(std::string_view const name, std::string_view const description)
: m_name(name)
, m_description(description)
{
@@ -26,16 +17,15 @@ option::option(std::string_view name, std::string_view description)
if (okay)
return;
- std::print(std::cerr,
+ std::println(std::cerr,
"INTERNAL ERROR: failed to register "
"configuration option '{}': {}",
m_name, okay.error());
- std::exit(1);
+ std::exit(1); // NOLINT
}
option::~option()
{
- std::ignore = store::get().unregister_option(this);
}
auto option::name(this option const &self) noexcept
diff --git a/nihil.config/option.ccm b/nihil.config/option.ccm
index 4b95793..0758c1a 100644
--- a/nihil.config/option.ccm
+++ b/nihil.config/option.ccm
@@ -1,32 +1,22 @@
-/*
- * This source code is released into the public domain.
- */
-
-module;
-
-#include <expected>
-#include <iosfwd>
-#include <string>
-
+// This source code is released into the public domain.
export module nihil.config:option;
+import nihil.std;
import nihil.error;
import nihil.ucl;
namespace nihil::config {
-/*
- * Base class for options; this is what config_store interacts with.
- *
- * Base classes should override the four protected functions:
- *
- * get_string()
- * set_string()
- * get_ucl()
- * set_ucl()
- *
- * Overriding any other members is not permitted.
- */
+// Base class for options; this is what config_store interacts with.
+//
+// Base classes should override the four protected functions:
+//
+// get_string()
+// set_string()
+// get_ucl()
+// set_ucl()
+//
+// Overriding any other members is not permitted.
export struct option
{
@@ -70,6 +60,9 @@ export struct option
option(option const &) = delete;
auto operator=(option const &) -> option& = delete;
+ option(option &&) = delete;
+ auto operator=(option &&) -> option& = delete;
+
protected:
option(std::string_view name, std::string_view description);
diff --git a/nihil.config/read.cc b/nihil.config/read.cc
deleted file mode 100644
index 48484fb..0000000
--- a/nihil.config/read.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * This source code is released into the public domain.
- */
-
-module;
-
-#include <coroutine>
-#include <expected>
-#include <filesystem>
-#include <format>
-#include <iterator>
-#include <string>
-
-module nihil.config;
-
-import nihil.error;
-import nihil.monad;
-import nihil.posix;
-import nihil.ucl;
-
-namespace nihil::config {
-
-auto read_from(std::filesystem::path const &filename)
- -> std::expected<void, error>
-{
- // TODO: nihil.ucl should have a way to load UCL from a filename.
-
- std::string config_text;
- auto err = read_file(filename, std::back_inserter(config_text));
- if (!err) {
- // Ignore ENOENT, it simply means we haven't created the
- // config file yet, so default values will be used.
- if (err.error().root_cause() == std::errc::no_such_file_or_directory)
- co_return {};
- auto errstr = std::format("cannot read {}", filename.string());
- co_return std::unexpected(error(errstr, err.error()));
- }
-
- // Parse the UCL.
- auto uclconfig = co_await ucl::parse(config_text);
-
- for (auto &&[key, value] : uclconfig) {
- auto opt = co_await store::get().fetch(key);
- co_await opt->ucl(value);
- }
-
- co_return {};
-}
-
-} // namespace nihil::config
diff --git a/nihil.config/read.ccm b/nihil.config/read.ccm
index 9cf28c9..7065492 100644
--- a/nihil.config/read.ccm
+++ b/nihil.config/read.ccm
@@ -1,22 +1,41 @@
-/*
- * This source code is released into the public domain.
- */
-
-module;
-
-#include <expected>
-#include <filesystem>
-
+// This source code is released into the public domain.
export module nihil.config:read;
+import nihil.std;
import nihil.error;
+import nihil.monad;
+import nihil.posix;
+import nihil.ucl;
+import :option;
+import :store;
namespace nihil::config {
-/*
- * Load the configuration from a file.
- */
-export [[nodiscard]] auto read_from(std::filesystem::path const &filename)
- -> std::expected<void, error>;
+// Load the configuration from a file.
+export [[nodiscard]] auto
+read_from(std::filesystem::path const &filename) -> std::expected<void, error>
+{
+ // TODO: nihil.ucl should have a way to load UCL from a filename.
+
+ auto config_text = std::string();
+ auto err = read_file(filename, std::back_inserter(config_text));
+ if (!err) {
+ // Ignore ENOENT, it simply means we haven't created the
+ // config file yet, so default values will be used.
+ if (err.error().root_cause() == std::errc::no_such_file_or_directory)
+ co_return {};
+ co_return std::unexpected(error(std::format("cannot read {}", filename.string()), err.error()));
+ }
+
+ // Parse the UCL.
+ auto uclconfig = co_await ucl::parse(config_text);
+
+ for (auto &&[key, value] : uclconfig) {
+ auto *opt = co_await store::get().fetch(key);
+ co_await opt->ucl(value);
+ }
+
+ co_return {};
+}
} // namespace nihil::config
diff --git a/nihil.config/store.cc b/nihil.config/store.cc
index 0fb8cc0..e1ca271 100644
--- a/nihil.config/store.cc
+++ b/nihil.config/store.cc
@@ -1,17 +1,7 @@
-/*
- * This source code is released into the public domain.
- */
-
-module;
-
-#include <coroutine>
-#include <expected>
-#include <filesystem>
-#include <format>
-#include <map>
-
+// This source code is released into the public domain.
module nihil.config;
+import nihil.std;
import nihil.error;
import nihil.generator;
import nihil.monad;
diff --git a/nihil.config/store.ccm b/nihil.config/store.ccm
index 4d37ce0..0a92ef0 100644
--- a/nihil.config/store.ccm
+++ b/nihil.config/store.ccm
@@ -1,25 +1,16 @@
-/*
- * This source code is released into the public domain.
- */
-
-module;
-
-/*
- * The configuration store. There should only be one of these.
- */
-
-#include <coroutine>
-#include <expected>
-#include <string>
-#include <map>
-
+// This source code is released into the public domain.
export module nihil.config:store;
+// The configuration store. There should only be one of these.
+
+import nihil.std;
+import nihil.error;
import nihil.generator;
-import :option;
namespace nihil::config {
+export struct option;
+
struct store final {
/*
* Get the global config store.
@@ -57,8 +48,8 @@ struct store final {
// Not movable or copyable.
store(store const &) = delete;
store(store &&) = delete;
- store& operator=(store const &) = delete;
- store& operator=(store &&) = delete;
+ auto operator=(store const &) -> store & = delete;
+ auto operator=(store &&) -> store & = delete;
private:
store();
diff --git a/nihil.config/string.cc b/nihil.config/string.cc
deleted file mode 100644
index 0ca4605..0000000
--- a/nihil.config/string.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * This source code is released into the public domain.
- */
-
-module;
-
-#include <coroutine>
-#include <expected>
-#include <format>
-#include <string>
-
-module nihil.config;
-
-import nihil.error;
-import nihil.monad;
-import nihil.ucl;
-
-namespace nihil::config {
-
-string::string(
- std::string &storage,
- std::string_view name,
- std::string_view description) noexcept
- : option(name, description)
- , m_storage(storage)
-{
-}
-
-string::~string() = default;
-
-auto string::get_string() const -> std::string
-{
- return m_storage;
-}
-
-auto string::set_string(std::string_view new_value)
- -> std::expected<void, error>
-{
- m_storage = new_value;
- return {};
-}
-
-auto string::get_ucl() const -> std::expected<ucl::object, error>
-{
- return ucl::string(m_storage);
-}
-
-auto string::set_ucl(ucl::object const &uclobj) -> std::expected<void, error>
-{
- auto obj = co_await object_cast<ucl::string>(uclobj)
- .transform_error([&] (ucl::type_mismatch const &m) {
- return error(std::format(
- "'{}': expected string, not {}",
- name(), str(m.actual_type())));
- });
-
- m_storage = obj.value();
- is_default(false);
- co_return {};
-}
-
-} // namespace nihil::config
diff --git a/nihil.config/string.ccm b/nihil.config/string.ccm
index 668bbc0..12ede7a 100644
--- a/nihil.config/string.ccm
+++ b/nihil.config/string.ccm
@@ -1,55 +1,68 @@
-/*
- * This source code is released into the public domain.
- */
-
-module;
-
-#include <expected>
-#include <format>
-#include <string>
-
+// This source code is released into the public domain.
export module nihil.config:string;
+import nihil.std;
+import nihil.monad;
import nihil.ucl;
import :option;
namespace nihil::config {
-/*
- * A string option. The backing type is std::string.
- */
+// A string option. The backing type is std::string.
export struct string final : option
{
- string(std::string &storage,
- std::string_view name,
- std::string_view description) noexcept;
-
- ~string();
-
- /*
- * Get this option as a string; simply returns the storage.
- */
- [[nodiscard]] auto get_string() const -> std::string override;
-
- /*
- * Set this option to a string value; assigns to the storage.
- */
- [[nodiscard]] auto set_string(std::string_view new_value)
- -> std::expected<void, error> override;
-
- /*
- * Convert this option to a UCL object.
- */
- [[nodiscard]] auto get_ucl() const
- -> std::expected<ucl::object, error> override;
-
- /*
- * Set this option from a UCL object.
- */
- [[nodiscard]] auto set_ucl(ucl::object const &uclobj)
- -> std::expected<void, error> override;
+ string(std::string &storage, std::string_view const name,
+ std::string_view const description) noexcept
+ : option(name, description)
+ , m_storage(storage)
+ {
+ }
+
+ ~string() override = default;
+
+ // Not copyable.
+ string(string const &) = delete;
+ auto operator=(string const &) -> string & = delete;
+
+ // Not movable.
+ string(string &&) = delete;
+ auto operator=(string &&) -> string & = delete;
private:
+ // Get this option as a string; simply returns the storage.
+ [[nodiscard]] auto get_string() const -> std::string override
+ {
+ return m_storage;
+ }
+
+ // Set this option to a string value; assigns to the storage.
+ [[nodiscard]] auto
+ set_string(std::string_view const new_value) -> std::expected<void, error> override
+ {
+ m_storage = new_value;
+ return {};
+ }
+
+ // Convert this option to a UCL object.
+ [[nodiscard]] auto get_ucl() const -> std::expected<ucl::object, error> override
+ {
+ return ucl::make_string(m_storage);
+ }
+
+ // Set this option from a UCL object.
+ [[nodiscard]] auto set_ucl(ucl::object const &uclobj) -> std::expected<void, error> override
+ {
+ auto obj = co_await object_cast<ucl::string>(uclobj).transform_error(
+ [&](ucl::type_mismatch const &m) {
+ return error(std::format("'{}': expected string, not {}", name(),
+ str(m.actual_type())));
+ });
+
+ m_storage = obj.value();
+ is_default(false);
+ co_return {};
+ }
+
std::string &m_storage;
};
diff --git a/nihil.config/string.test.cc b/nihil.config/string.test.cc
new file mode 100644
index 0000000..322eb79
--- /dev/null
+++ b/nihil.config/string.test.cc
@@ -0,0 +1,32 @@
+// This source code is released into the public domain.
+
+#include <catch2/catch_test_macros.hpp>
+
+import nihil.std;
+import nihil.config;
+
+namespace {
+TEST_CASE("nihil.config: string option", "[nihil][nihil.config]")
+{
+ auto storage = std::string();
+
+ REQUIRE(nihil::config::get_option("test_option").has_value() == false);
+
+ {
+ auto string_option = nihil::config::string(
+ storage, "test_option", "This is a test option");
+
+ auto *opt = nihil::config::get_option("test_option").value();
+
+ REQUIRE(opt->name() == "test_option");
+ REQUIRE(opt->description() == "This is a test option");
+ REQUIRE(opt->is_default() == true);
+ REQUIRE(opt->string() == "");
+
+ REQUIRE(opt->string("testing"));
+ REQUIRE(storage == "testing");
+ }
+
+ REQUIRE(nihil::config::get_option("test_option").has_value() == false);
+}
+} // anonymous namespace
diff --git a/nihil.config/tests/CMakeLists.txt b/nihil.config/tests/CMakeLists.txt
deleted file mode 100644
index ffa60c3..0000000
--- a/nihil.config/tests/CMakeLists.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-# This source code is released into the public domain.
-
-add_executable(nihil.config.test
- string.cc
-)
-
-target_link_libraries(nihil.config.test PRIVATE
- nihil.config
- Catch2::Catch2WithMain)
-
-include(CTest)
-include(Catch)
-catch_discover_tests(nihil.config.test)
diff --git a/nihil.config/tests/string.cc b/nihil.config/tests/string.cc
deleted file mode 100644
index aeb1ef8..0000000
--- a/nihil.config/tests/string.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * This source code is released into the public domain.
- */
-
-#include <string>
-
-#include <catch2/catch_test_macros.hpp>
-
-import nihil.config;
-
-TEST_CASE("nihil.config: string option", "[nihil][nihil.config]")
-{
- std::string storage;
-
- auto opt = nihil::config::get_option("test_option");
- REQUIRE(!opt);
-
- {
- auto string_option = nihil::config::string(
- storage, "test_option", "This is a test option");
-
- auto opt = nihil::config::get_option("test_option");
- REQUIRE(opt);
-
- REQUIRE((*opt)->name() == "test_option");
- REQUIRE((*opt)->description() == "This is a test option");
- REQUIRE((*opt)->is_default() == true);
- REQUIRE((*opt)->string() == "");
-
- REQUIRE((*opt)->string("testing"));
- REQUIRE(storage == "testing");
- }
-
- opt = nihil::config::get_option("test_option");
- REQUIRE(!opt);
-}
diff --git a/nihil.config/write.cc b/nihil.config/write.cc
deleted file mode 100644
index 80125a8..0000000
--- a/nihil.config/write.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * This source code is released into the public domain.
- */
-
-module;
-
-#include <coroutine>
-#include <expected>
-#include <filesystem>
-#include <format>
-#include <utility>
-
-module nihil.config;
-
-import nihil.error;
-import nihil.monad;
-import nihil.posix;
-import nihil.ucl;
-
-namespace nihil::config {
-
-auto write_to(std::filesystem::path const &filename)
- -> std::expected<void, error>
-{
- auto uclconfig = ucl::map<ucl::object>();
-
- // Add all the options to the UCL object.
- for (auto const &option : store::get().all()) {
- if (option->is_default())
- continue;
-
- auto uobj = co_await option->ucl();
- uclconfig.insert({option->name(), uobj});
- }
-
- auto ucl_text = std::format("{:c}", uclconfig);
- co_await safe_write_file(filename, ucl_text);
- co_return {};
-}
-
-};
diff --git a/nihil.config/write.ccm b/nihil.config/write.ccm
index 564bb20..a7eddd5 100644
--- a/nihil.config/write.ccm
+++ b/nihil.config/write.ccm
@@ -1,22 +1,34 @@
-/*
- * This source code is released into the public domain.
- */
-
-module;
-
-#include <expected>
-#include <filesystem>
-
+// This source code is released into the public domain.
export module nihil.config:write;
+import nihil.std;
import nihil.error;
+import nihil.monad;
+import nihil.posix;
+import nihil.ucl;
+import :option;
+import :store;
namespace nihil::config {
-/*
- * Write all config values (except defaults) to disk.
- */
-export [[nodiscard]] auto write_to(std::filesystem::path const &filename) ->
- std::expected<void, error>;
+// Write all config values (except defaults) to disk.
+export [[nodiscard]] auto
+write_to(std::filesystem::path const &filename) -> std::expected<void, error>
+{
+ auto uclconfig = ucl::map<ucl::object>();
+
+ // Add all the options to the UCL object.
+ for (auto const &option : store::get().all()) {
+ if (option->is_default())
+ continue;
+
+ auto uobj = co_await option->ucl();
+ uclconfig.insert({option->name(), uobj});
+ }
+
+ auto ucl_text = std::format("{:c}", uclconfig);
+ co_await safe_write_file(filename, ucl_text);
+ co_return {};
+}
-};
+}; // namespace nihil::config