mirror of
https://github.com/geode-sdk/geode.git
synced 2024-12-11 08:31:13 -05:00
152 lines
4 KiB
C++
152 lines
4 KiB
C++
#pragma once
|
|
|
|
#include <Geode/DefaultInclude.hpp>
|
|
#include <string_view>
|
|
#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<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 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<T>::value) {
|
|
my_value.~T();
|
|
}
|
|
} else {
|
|
if (std::is_destructible<E>::value) {
|
|
error_msg.~E();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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());
|
|
} else {
|
|
this->success = false;
|
|
new (&this->error_msg) E(other.error());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Copy another Result of a convertible type
|
|
*/
|
|
template<class T2, class E2>
|
|
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());
|
|
}
|
|
} 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) { <handle success> } else { <handle failure> }
|
|
*/
|
|
operator bool() const { return this->success; }
|
|
|
|
/**
|
|
* Create a success result
|
|
* @param value Value
|
|
*/
|
|
static auto ok(const T value) { return Result<T>(value); }
|
|
|
|
/**
|
|
* Create an error result
|
|
* @param error Error information
|
|
*/
|
|
static auto err(E error) { return Result<T>(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 <class T = no_result>
|
|
Result<T> Ok(T value = T()) {
|
|
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 Err {
|
|
const E _value;
|
|
Err(const TypeIdentityType<E> value) : _value(value) {}
|
|
template <class T>
|
|
operator Result<T, E>() const {
|
|
return Result<T, E>::err(_value);
|
|
}
|
|
};
|
|
}
|