#pragma once #include #include #include "types.hpp" namespace geode { /** * @struct no_result * The default value of a Result. * Represents a Result that has no * data to carry on Success, but * may still return extended * error information on failure. */ struct no_result {}; /** * @class Result * Represents an optional value with an * associated error state and -information. * Use the Ok and Err classes to * create Result(s). * @param T Success result value type * @param E Error message type * @authors Matcool, HJfod */ template class Result { protected: bool success; union { T my_value; E error_msg; }; Result(const T value) : success(true), my_value(value) {} Result(const E error, int dummy) : success(false), error_msg(error) {} public: /** * Destructor */ ~Result() { if (success) { if (std::is_destructible::value) { my_value.~T(); } } else { if (std::is_destructible::value) { error_msg.~E(); } } } /** * Copy another Result of the same type */ Result(Result const& other) { if (other.success) { this->success = true; new (&this->my_value) T(other.value()); } else { this->success = false; new (&this->error_msg) E(other.error()); } } /** * Copy another Result of a convertible type */ template Result(Result const& other) { if (other.is_value()) { this->success = true; if constexpr (!std::is_same::value) { new (&this->my_value) T(other.value()); } } else { this->success = false; new (&this->error_msg) E(other.error()); } } /** * Check if Result was errorful * @returns True if errorful */ bool is_error() const { return !success; } /** * Check if Result was succesful * @returns True if succesful */ bool is_value() const { return success; } /** * Get the success value of a Result * @returns Value */ auto value() const { return my_value; } /** * Get the error message of a Result * @returns Error */ auto error() const { return error_msg; } /** * Convert to bool * @example if (result) { } else { } */ operator bool() const { return this->success; } /** * Create a success result * @param value Value */ static auto ok(const T value) { return Result(value); } /** * Create an error result * @param error Error information */ static auto err(E error) { return Result(error, 0); } }; /** * Create a succesful Result with a value * @param value The value. If none is provided, the type will be no_result * @returns Successful Result */ template Result Ok(T value = T()) { return Result::ok(value); } /** * @class Err * Create an errorful Result with an error message * @param value Error message * @returns Errorful Result */ template struct Err { const E _value; Err(const TypeIdentityType value) : _value(value) {} template operator Result() const { return Result::err(_value); } }; }