#pragma once #include "error/error.h" #include "logger.h" #include "panic.h" #include #include #include #include struct DUMMY_VALUE {}; template class [[nodiscard]] result { static_assert(std::conjunction_v...>, "result requires T_Errors to derive from Error"); struct error_state { std::variant error; }; struct success_state { T_Result success; }; std::variant value; public: 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 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().c_str(), it.message().c_str(), errMsg.c_str()); }, error().value()); panic(); } bool isSuccess() { return std::holds_alternative(value); } bool isError() { return std::holds_alternative(value); } std::optional success() { return isSuccess() ? std::make_optional(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 (isSuccess()) return; std::visit([&](auto&& it) { it.logMessage(logLevel); }, error().value()); } std::optional errorMessage() { if (isSuccess()) return std::nullopt; return std::visit([&](auto&& it) { return it.message(); }, error().value()); } // Equivalent to .success operator std::optional() { return success(); } operator bool() { return isSuccess(); } bool operator !() { return isError(); } }; template class [[nodiscard]] fallible : public result { public: fallible() : result(DUMMY_VALUE {}) {} fallible(std::variant error) : result(error) {} template ...>, int> = 0> fallible(T_Error error) : result(error) {} };