aboutsummaryrefslogtreecommitdiffstats
path: root/liblfvm/vm_config.cc
diff options
context:
space:
mode:
Diffstat (limited to 'liblfvm/vm_config.cc')
-rw-r--r--liblfvm/vm_config.cc135
1 files changed, 135 insertions, 0 deletions
diff --git a/liblfvm/vm_config.cc b/liblfvm/vm_config.cc
new file mode 100644
index 0000000..8acb797
--- /dev/null
+++ b/liblfvm/vm_config.cc
@@ -0,0 +1,135 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+#include <algorithm>
+#include <coroutine>
+#include <expected>
+#include <format>
+#include <functional>
+#include <ranges>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+module liblfvm;
+
+import nihil;
+
+namespace lfvm {
+
+/*
+ * Split an option into name and value.
+ */
+[[nodiscard]] auto parse_option(std::string_view str)
+ -> std::expected<std::pair<std::string_view, std::string_view>,
+ nihil::error>
+{
+ auto split = std::ranges::find(str, '=');
+ if (split == str.end())
+ return std::unexpected(nihil::error(
+ "missing '=' in option string"));
+
+ auto option = std::string_view(str.begin(), split);
+ if (option.empty())
+ return std::unexpected(nihil::error(
+ "invalid option name"));
+
+ auto value = std::string_view(std::next(split), str.end());
+ if (value.empty())
+ return std::unexpected(nihil::error(
+ "invalid option value"));
+
+ return std::make_pair(option, value);
+}
+
+/*
+ * Parse a boolean option (true/false).
+ */
+[[nodiscard]] auto parse_bool(std::string_view value)
+ -> std::expected<bool, nihil::error>
+{
+ using namespace std::literals;
+
+ static auto true_values = std::unordered_set{
+ "yes"sv, "true"sv, "enabled"sv, "on"sv
+ };
+
+ static auto false_values = std::unordered_set{
+ "no"sv, "false"sv, "disabled"sv, "off"sv
+ };
+
+ if (true_values.find(value) != true_values.end())
+ return true;
+
+ if (false_values.find(value) != false_values.end())
+ return false;
+
+ return std::unexpected(nihil::error("invalid value for boolean"));
+}
+
+auto set_vm_option(vm_config &vm, std::string_view option_string)
+ -> std::expected<void, nihil::error>
+{
+ using namespace std::literals;
+
+ // The table of options we know how to set.
+ static auto options = std::unordered_map<
+ std::string_view,
+ std::function<
+ std::expected<void, nihil::error>(
+ vm_config &, std::string_view)
+ >
+ > {
+
+std::make_pair("memory"sv,
+[](vm_config &vm, std::string_view str) -> std::expected<void, nihil::error> {
+ // Due to limitations in UCL, the memory size is limited to
+ // int64_t. In practice, this is not an issue.
+ auto new_size = co_await nihil::parse_size<std::int64_t>(str);
+ co_await vm.memory_size(new_size);
+ co_return {};
+}),
+
+std::make_pair("ncpus"sv,
+[](vm_config &vm, std::string_view str) -> std::expected<void, nihil::error> {
+ auto ncpus = co_await nihil::parse_size<unsigned>(str);
+ co_await vm.ncpus(ncpus);
+ co_return {};
+}),
+
+std::make_pair("wire_memory"sv,
+[](vm_config &vm, std::string_view str) -> std::expected<void, nihil::error> {
+ auto b = co_await parse_bool(str);
+ vm.wire_memory(b);
+ co_return {};
+}),
+
+std::make_pair("include_memory_in_core"sv,
+[](vm_config &vm, std::string_view str) -> std::expected<void, nihil::error> {
+ auto b = co_await parse_bool(str);
+ vm.include_memory_in_core(b);
+ co_return {};
+}),
+
+ };
+
+ auto [name, value] = co_await parse_option(option_string);
+
+ auto option = options.find(name);
+ if (option == options.end())
+ co_return std::unexpected(nihil::error(
+ std::format("unknown option '{}'", name)));
+
+ co_await option->second(vm, value).transform_error(
+ [&](nihil::error cause) {
+ return nihil::error(
+ std::format("failed to set {}", name),
+ std::move(cause));
+ });
+ co_return {};
+}
+
+} // namespace lfvm