diff options
Diffstat (limited to 'liblfvm/vm_config.cc')
| -rw-r--r-- | liblfvm/vm_config.cc | 135 |
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 |
