geode/loader/include/Geode/utils/Result.hpp

177 lines
4.3 KiB
C++
Raw Normal View History

2022-07-30 12:24:03 -04:00
#pragma once
2022-10-30 14:59:20 -04:00
#include "NewResult.hpp"
#include "types.hpp"
2022-07-30 12:24:03 -04:00
#include <Geode/DefaultInclude.hpp>
#include <string_view>
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<T> and Err<T> classes to
* create Result(s).
* @param T Success result value type
* @param E Error message type
* @authors Matcool, HJfod
*/
template <class T = no_result, class E = std::string>
class [[nodiscard]] Result {
2022-07-30 12:24:03 -04:00
protected:
bool success;
2022-10-30 14:59:20 -04:00
2022-07-30 12:24:03 -04:00
union {
T my_value;
E error_msg;
};
2022-10-30 14:59:20 -04:00
2022-07-30 12:24:03 -04:00
Result(const T value) : success(true), my_value(value) {}
2022-10-30 14:59:20 -04:00
2022-07-30 12:24:03 -04:00
Result(const E error, int dummy) : success(false), error_msg(error) {}
public:
/**
* Destructor
*/
~Result() {
if (success) {
if (std::is_destructible<T>::value) {
my_value.~T();
}
2022-10-30 14:59:20 -04:00
}
else {
2022-07-30 12:24:03 -04:00
if (std::is_destructible<E>::value) {
error_msg.~E();
}
}
}
2022-10-30 14:59:20 -04:00
2022-07-30 12:24:03 -04:00
/**
* Copy another Result of the same type
*/
Result(Result<T, E> const& other) {
if (other.success) {
this->success = true;
new (&this->my_value) T(other.value());
2022-10-30 14:59:20 -04:00
}
else {
2022-07-30 12:24:03 -04:00
this->success = false;
new (&this->error_msg) E(other.error());
}
}
/**
* Copy another Result of a convertible type
*/
2022-10-30 14:59:20 -04:00
template <class T2, class E2>
2022-07-30 12:24:03 -04:00
Result(Result<T2, E2> const& other) {
if (other.is_value()) {
this->success = true;
if constexpr (!std::is_same<T, no_result>::value) {
new (&this->my_value) T(other.value());
}
2022-10-30 14:59:20 -04:00
}
else {
2022-07-30 12:24:03 -04:00
this->success = false;
new (&this->error_msg) E(other.error());
}
}
/**
* Check if Result was errorful
* @returns True if errorful
*/
2022-10-30 14:59:20 -04:00
bool is_error() const {
return !success;
}
2022-07-30 12:24:03 -04:00
/**
* Check if Result was succesful
* @returns True if succesful
*/
2022-10-30 14:59:20 -04:00
bool is_value() const {
return success;
}
2022-07-30 12:24:03 -04:00
/**
* Get the success value of a Result
* @returns Value
*/
2022-10-30 14:59:20 -04:00
auto value() const {
return my_value;
}
2022-07-30 12:24:03 -04:00
/**
* Get the error message of a Result
* @returns Error
*/
2022-10-30 14:59:20 -04:00
auto error() const {
return error_msg;
}
2022-07-30 12:24:03 -04:00
/**
* Convert to bool
* @example if (result) { <handle success> } else { <handle failure> }
*/
2022-10-30 14:59:20 -04:00
explicit operator bool() const {
return this->success;
}
2022-07-30 12:24:03 -04:00
/**
* Create a success result
* @param value Value
*/
2022-10-30 14:59:20 -04:00
static auto ok(const T value) {
return Result<T>(value);
}
2022-07-30 12:24:03 -04:00
/**
* Create an error result
* @param error Error information
*/
2022-10-30 14:59:20 -04:00
static auto err(E error) {
return Result<T>(error, 0);
}
2022-07-30 12:24:03 -04:00
};
/**
* 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 <class T = no_result>
2022-10-30 14:59:20 -04:00
[[nodiscard]] Result<T> Ok(T value = T()) {
2022-07-30 12:24:03 -04:00
return Result<T>::ok(value);
}
/**
* @class Err
* Create an errorful Result with an error message
* @param value Error message
* @returns Errorful Result
*/
template <class E = std::string>
struct [[nodiscard]] Err {
2022-07-30 12:24:03 -04:00
const E _value;
2022-10-30 14:59:20 -04:00
Err(TypeIdentityType<E> const value) : _value(value) {}
2022-07-30 12:24:03 -04:00
template <class T>
operator Result<T, E>() const {
return Result<T, E>::err(_value);
}
};
}