From 58b53a0f02633d4317117872cfec1b503d1a2adf Mon Sep 17 00:00:00 2001 From: maelstrom Date: Mon, 14 Apr 2025 22:38:49 +0200 Subject: [PATCH] refactor(error): added guards to result and misc refactorings to error --- core/src/error/error.cpp | 17 --------- core/src/error/error.h | 12 +++--- core/src/error/instance.h | 18 +++++++++ core/src/error/result.h | 59 +++++++++++++++++------------- core/src/objects/base/instance.cpp | 4 +- core/src/objects/base/instance.h | 7 +--- core/src/objects/datamodel.cpp | 2 +- core/src/objects/datamodel.h | 11 ------ 8 files changed, 63 insertions(+), 67 deletions(-) delete mode 100644 core/src/error/error.cpp create mode 100644 core/src/error/instance.h diff --git a/core/src/error/error.cpp b/core/src/error/error.cpp deleted file mode 100644 index 99bed01..0000000 --- a/core/src/error/error.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "error.h" -#include "logger.h" - -Error::Error(std::string message) : message(message) { -} - -std::string Error::getMessage() { - return this->message; -} - -void Error::logMessage(Logger::LogLevel logLevel) { - Logger::log(this->message, logLevel); -} - -void Error::logMessageFatal() { - Logger::fatalError(this->message); -} \ No newline at end of file diff --git a/core/src/error/error.h b/core/src/error/error.h index bb7275d..35f404d 100644 --- a/core/src/error/error.h +++ b/core/src/error/error.h @@ -5,13 +5,15 @@ // Base class for all errors class Error { - std::string message; + std::string _errorType; + std::string _message; protected: - Error(std::string message); + inline Error(std::string errorType, std::string message) : _errorType(errorType), _message(message) {} public: - std::string getMessage(); - void logMessage(Logger::LogLevel logLevel = Logger::LogLevel::ERROR); - void logMessageFatal(); + inline std::string errorType() { return this->_errorType; } + inline std::string message() { return this->_message; } + inline void logMessage(Logger::LogLevel logLevel = Logger::LogLevel::ERROR) { Logger::log(this->_message, logLevel); } + void logMessageFatal() { Logger::fatalError(this->_message); } }; \ No newline at end of file diff --git a/core/src/error/instance.h b/core/src/error/instance.h new file mode 100644 index 0000000..d637f84 --- /dev/null +++ b/core/src/error/instance.h @@ -0,0 +1,18 @@ +#pragma once + +#include "error.h" + +class NoSuchInstance : public Error { + public: + inline NoSuchInstance(std::string className) : Error("NoSuchInstance", "Cannot create instance of unknown type " + className) {} +}; + +class NoSuchService : public Error { + public: + inline NoSuchService(std::string className) : Error("NoSuchService", "Cannot insert service of unknown type " + className) {} +}; + +class ServiceAlreadyExists : public Error { + public: + inline ServiceAlreadyExists(std::string className) : Error("ServiceAlreadyExists", "Service " + className + " is already inserted") {} +}; \ No newline at end of file diff --git a/core/src/error/result.h b/core/src/error/result.h index 48fc73f..ac4cc1d 100644 --- a/core/src/error/result.h +++ b/core/src/error/result.h @@ -1,59 +1,68 @@ #pragma once -#include "error.h" +#include "error/error.h" #include "logger.h" #include "panic.h" #include #include +#include #include struct DUMMY_VALUE {}; -template +template class [[nodiscard]] result { - struct ErrorContainer { - std::variant error; + static_assert(std::conjunction_v...>, "result requires T_Errors to derive from Error"); + + struct error_state { + std::variant error; }; - struct SuccessContainer { - Result success; + struct success_state { + T_Result success; }; - std::variant value; + std::variant value; public: - result(Result success) : value(SuccessContainer { success }) {} - result(std::variant error) : value(ErrorContainer { error }) {} + result(T_Result success) : value(success_state { success }) {} + result(std::variant error) : value(error_state { error }) {} + template ...>, int> = 0> + result(T_Error error) : value(error_state { error }) {} // Expects the result to be successful, otherwise panic with error message - Result expect(std::string errMsg = "Unwrapped a result with failure value") { - if (is_success()) - return std::get(value).success; - Logger::fatalError(errMsg); + T_Result expect(std::string errMsg = "Expected result to contain success") { + if (isSuccess()) + return std::get(value).success; + std::visit([&](auto&& it) { + Logger::fatalErrorf("Unwrapped a result with error value: [%s] %s\n\t%s", it.errorType(), it.message(), errMsg); + }, error().value()); panic(); } - bool is_success() { return std::holds_alternative(value); } - bool is_error() { return std::holds_alternative(value); } + bool isSuccess() { return std::holds_alternative(value); } + bool isError() { return std::holds_alternative(value); } - std::optional success() { return is_success() ? std::get(value).success : std::nullopt; } - std::optional> error() { return is_error() ? std::make_optional(std::get(value).error) : std::nullopt; } + std::optional success() { return isSuccess() ? std::get(value).success : std::nullopt; } + std::optional> error() { return isError() ? std::make_optional(std::get(value).error) : std::nullopt; } void logError(Logger::LogLevel logLevel = Logger::LogLevel::ERROR) { - if (is_success()) return; + if (isSuccess()) return; std::visit([&](auto&& it) { it.logMessage(logLevel); }, error().value()); } // Equivalent to .success - operator std::optional() { return success(); } - operator bool() { return is_success(); } - bool operator !() { return is_error(); } + operator std::optional() { return success(); } + operator bool() { return isSuccess(); } + bool operator !() { return isError(); } }; -template -class fallible : public result { +template +class [[nodiscard]] fallible : public result { public: - fallible() : result(DUMMY_VALUE {}) {} - fallible(std::variant error) : result(error) {} + fallible() : result(DUMMY_VALUE {}) {} + fallible(std::variant error) : result(error) {} + template ...>, int> = 0> + fallible(T_Error error) : result(error) {} }; \ No newline at end of file diff --git a/core/src/objects/base/instance.cpp b/core/src/objects/base/instance.cpp index 9f6e5d5..21fefe0 100644 --- a/core/src/objects/base/instance.cpp +++ b/core/src/objects/base/instance.cpp @@ -240,7 +240,7 @@ void Instance::Serialize(pugi::xml_node parent) { result Instance::Deserialize(pugi::xml_node node) { std::string className = node.attribute("class").value(); if (INSTANCE_MAP.count(className) == 0) { - return std::variant(NoSuchInstance(className)); + return NoSuchInstance(className); } // This will error if an abstract instance is used in the file. Oh well, not my prob rn. // printf("What are you? A %s sandwich\n", className.c_str()); @@ -265,7 +265,7 @@ result Instance::Deserialize(pugi::xml_node node) { // Read children for (pugi::xml_node childNode : node.children("Item")) { result child = Instance::Deserialize(childNode); - if (child.is_error()) { + if (child.isError()) { std::get(child.error().value()).logMessage(); continue; } diff --git a/core/src/objects/base/instance.h b/core/src/objects/base/instance.h index 7f25c88..bd80505 100644 --- a/core/src/objects/base/instance.h +++ b/core/src/objects/base/instance.h @@ -13,7 +13,7 @@ #include #include -#include "error/error.h" +#include "error/instance.h" #include "error/result.h" #include "member.h" @@ -38,11 +38,6 @@ struct InstanceType { InstanceFlags flags; }; -// Errors -class NoSuchInstance : public Error { - public: - inline NoSuchInstance(std::string className) : Error("Cannot create instance of unknown type " + className) {} -}; class DescendantsIterator; diff --git a/core/src/objects/datamodel.cpp b/core/src/objects/datamodel.cpp index 376c1dd..495fa8e 100644 --- a/core/src/objects/datamodel.cpp +++ b/core/src/objects/datamodel.cpp @@ -93,7 +93,7 @@ void DataModel::DeserializeService(pugi::xml_node node) { // Add children for (pugi::xml_node childNode : node.children("Item")) { result child = Instance::Deserialize(childNode); - if (child.is_error()) { + if (child.isError()) { std::get(child.error().value()).logMessage(); continue; } diff --git a/core/src/objects/datamodel.h b/core/src/objects/datamodel.h index 8393da3..5d46fff 100644 --- a/core/src/objects/datamodel.h +++ b/core/src/objects/datamodel.h @@ -1,6 +1,5 @@ #pragma once -#include "base.h" #include "error/result.h" #include "logger.h" #include "objects/base/instance.h" @@ -14,16 +13,6 @@ class Workspace; class DataModel; class Service; -class NoSuchService : public Error { - public: - inline NoSuchService(std::string className) : Error("Cannot insert service of unknown type " + className) {} -}; - -class ServiceAlreadyExists : public Error { - public: - inline ServiceAlreadyExists(std::string className) : Error("Service " + className + " is already inserted") {} -}; - // The root instance to all objects in the hierarchy class DataModel : public Instance { private: