2020-07-28 01:23:38 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <string>
|
2021-03-13 22:22:01 +01:00
|
|
|
#include <string_view>
|
2020-07-28 01:23:38 +02:00
|
|
|
#include <variant>
|
|
|
|
|
2020-08-25 19:51:45 +02:00
|
|
|
#include "common.h"
|
|
|
|
|
2020-07-28 01:23:38 +02:00
|
|
|
namespace gin {
|
2020-12-04 22:13:31 +01:00
|
|
|
/**
|
|
|
|
* Utility class for generating errors. Has a base distinction between
|
|
|
|
* critical and recoverable errors. Additional code ids can be provided to the
|
|
|
|
* constructor if additional distinctions are necessary.
|
|
|
|
*/
|
2020-08-09 02:03:09 +02:00
|
|
|
class Error {
|
2021-06-04 23:21:25 +02:00
|
|
|
public:
|
2021-06-09 14:00:03 +02:00
|
|
|
enum class Code : int16_t {
|
|
|
|
GenericCritical = -1,
|
|
|
|
GenericRecoverable = 1,
|
|
|
|
Disconnected = -99,
|
2021-06-29 22:39:27 +02:00
|
|
|
Exhausted = -98
|
2021-06-04 23:21:25 +02:00
|
|
|
};
|
2021-06-09 14:00:03 +02:00
|
|
|
|
2020-08-09 02:11:22 +02:00
|
|
|
private:
|
2021-03-13 22:22:01 +01:00
|
|
|
std::variant<std::string_view, std::string> error_message;
|
2021-06-09 14:00:03 +02:00
|
|
|
Code error_;
|
2020-08-09 02:03:09 +02:00
|
|
|
|
2020-08-09 02:11:22 +02:00
|
|
|
public:
|
2020-08-09 02:09:49 +02:00
|
|
|
Error();
|
2021-06-09 14:00:03 +02:00
|
|
|
Error(const std::string_view &msg, Error::Code code);
|
|
|
|
Error(std::string &&msg, Error::Code code);
|
2020-08-20 00:36:21 +02:00
|
|
|
Error(Error &&error);
|
2020-08-18 22:47:34 +02:00
|
|
|
|
2021-03-13 22:22:01 +01:00
|
|
|
GIN_FORBID_COPY(Error);
|
|
|
|
|
2020-08-20 00:36:21 +02:00
|
|
|
Error &operator=(Error &&) = default;
|
2020-08-09 02:03:09 +02:00
|
|
|
|
2021-03-13 22:22:01 +01:00
|
|
|
const std::string_view message() const;
|
2020-08-09 02:09:49 +02:00
|
|
|
bool failed() const;
|
2020-08-09 02:03:09 +02:00
|
|
|
|
2020-08-09 02:09:49 +02:00
|
|
|
bool isCritical() const;
|
|
|
|
bool isRecoverable() const;
|
2021-03-13 22:22:01 +01:00
|
|
|
|
|
|
|
Error copyError() const;
|
2021-06-04 23:21:25 +02:00
|
|
|
|
2021-06-09 14:00:03 +02:00
|
|
|
Code code() const;
|
2020-08-09 02:03:09 +02:00
|
|
|
};
|
|
|
|
|
2021-06-29 22:39:27 +02:00
|
|
|
Error makeError(const std::string_view &generic, Error::Code c);
|
|
|
|
|
2021-03-13 22:22:01 +01:00
|
|
|
template <typename Formatter>
|
2021-06-09 14:00:03 +02:00
|
|
|
Error makeError(const Formatter &formatter, Error::Code code,
|
2021-03-17 11:24:18 +01:00
|
|
|
const std::string_view &generic) {
|
2021-03-13 22:22:01 +01:00
|
|
|
try {
|
|
|
|
std::string error_msg = formatter();
|
|
|
|
return Error{std::move(error_msg), code};
|
|
|
|
} catch (std::bad_alloc &) {
|
|
|
|
return Error{generic, code};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-09 14:00:03 +02:00
|
|
|
Error criticalError(const std::string_view &generic,
|
|
|
|
Error::Code c = Error::Code::GenericCritical);
|
2021-03-13 22:22:01 +01:00
|
|
|
|
|
|
|
template <typename Formatter>
|
2021-06-09 14:00:03 +02:00
|
|
|
Error criticalError(const Formatter &formatter, const std::string_view &generic,
|
|
|
|
Error::Code c = Error::Code::GenericCritical) {
|
|
|
|
return makeError(formatter, c, generic);
|
2021-03-13 22:22:01 +01:00
|
|
|
}
|
|
|
|
|
2021-06-09 14:00:03 +02:00
|
|
|
Error recoverableError(const std::string_view &generic,
|
|
|
|
Error::Code c = Error::Code::GenericRecoverable);
|
2021-03-13 22:22:01 +01:00
|
|
|
|
|
|
|
template <typename Formatter>
|
|
|
|
Error recoverableError(const Formatter &formatter,
|
2021-06-09 14:00:03 +02:00
|
|
|
const std::string_view &generic,
|
|
|
|
Error::Code c = Error::Code::GenericRecoverable) {
|
|
|
|
return makeError(formatter, c, generic);
|
2021-03-13 22:22:01 +01:00
|
|
|
}
|
|
|
|
|
2020-08-09 02:03:09 +02:00
|
|
|
Error noError();
|
|
|
|
|
2020-12-04 22:13:31 +01:00
|
|
|
/**
|
|
|
|
* Exception alternative. Since I code without exceptions this class is
|
|
|
|
* essentially a kind of exception replacement.
|
|
|
|
*/
|
2020-08-20 00:36:21 +02:00
|
|
|
template <typename T> class ErrorOr;
|
2020-08-18 22:47:34 +02:00
|
|
|
|
2020-08-09 02:03:09 +02:00
|
|
|
class ErrorOrValue {
|
2020-08-09 02:11:22 +02:00
|
|
|
public:
|
2020-08-09 02:09:49 +02:00
|
|
|
virtual ~ErrorOrValue() = default;
|
2020-08-18 22:38:36 +02:00
|
|
|
|
2021-06-29 22:39:27 +02:00
|
|
|
template <typename T> ErrorOr<UnfixVoid<T>> &as() {
|
|
|
|
return dynamic_cast<ErrorOr<UnfixVoid<T>> &>(*this);
|
2020-08-18 22:38:36 +02:00
|
|
|
}
|
|
|
|
|
2021-06-29 22:39:27 +02:00
|
|
|
template <typename T> const ErrorOr<UnfixVoid<T>> &as() const {
|
|
|
|
return dynamic_cast<const ErrorOr<UnfixVoid<T>> &>(*this);
|
2020-08-18 22:38:36 +02:00
|
|
|
}
|
2020-08-09 02:03:09 +02:00
|
|
|
};
|
|
|
|
|
2021-06-29 22:39:27 +02:00
|
|
|
template <typename T> class ErrorOr final : public ErrorOrValue {
|
2020-08-09 02:11:22 +02:00
|
|
|
private:
|
2021-06-20 13:28:59 +02:00
|
|
|
std::variant<Error, FixVoid<T>> value_or_error;
|
2020-08-28 16:59:25 +02:00
|
|
|
|
2021-06-29 22:39:27 +02:00
|
|
|
static_assert(!std::is_same_v<T, Void>, "Don't use internal private types");
|
|
|
|
|
2020-08-09 02:11:22 +02:00
|
|
|
public:
|
2020-08-18 22:38:36 +02:00
|
|
|
ErrorOr() = default;
|
2021-05-02 21:09:50 +02:00
|
|
|
ErrorOr(const FixVoid<T> &value) : value_or_error{value} {}
|
2020-08-09 02:03:09 +02:00
|
|
|
|
2021-05-02 21:09:50 +02:00
|
|
|
ErrorOr(FixVoid<T> &&value) : value_or_error{std::move(value)} {}
|
2020-08-09 02:03:09 +02:00
|
|
|
|
2020-08-09 02:09:49 +02:00
|
|
|
ErrorOr(const Error &error) : value_or_error{error} {}
|
|
|
|
ErrorOr(Error &&error) : value_or_error{std::move(error)} {}
|
2020-08-09 02:03:09 +02:00
|
|
|
|
2021-06-29 22:39:27 +02:00
|
|
|
bool isValue() const {
|
|
|
|
return std::holds_alternative<FixVoid<T>>(value_or_error);
|
|
|
|
}
|
2020-08-09 02:03:09 +02:00
|
|
|
|
2020-08-09 02:09:49 +02:00
|
|
|
bool isError() const {
|
|
|
|
return std::holds_alternative<Error>(value_or_error);
|
|
|
|
}
|
2020-08-09 02:03:09 +02:00
|
|
|
|
2020-08-28 16:59:25 +02:00
|
|
|
Error &error() { return std::get<Error>(value_or_error); }
|
2020-08-26 16:39:59 +02:00
|
|
|
|
2020-08-09 02:09:49 +02:00
|
|
|
const Error &error() const { return std::get<Error>(value_or_error); }
|
2020-08-09 02:03:09 +02:00
|
|
|
|
2021-05-02 21:09:50 +02:00
|
|
|
FixVoid<T> &value() { return std::get<FixVoid<T>>(value_or_error); }
|
2020-08-09 02:03:09 +02:00
|
|
|
|
2021-05-02 21:09:50 +02:00
|
|
|
const FixVoid<T> &value() const {
|
|
|
|
return std::get<FixVoid<T>>(value_or_error);
|
|
|
|
}
|
2020-08-09 02:03:09 +02:00
|
|
|
};
|
2020-08-25 19:51:45 +02:00
|
|
|
|
2021-06-20 13:28:59 +02:00
|
|
|
template <typename T> class ErrorOr<ErrorOr<T>> {
|
|
|
|
private:
|
|
|
|
ErrorOr() = delete;
|
|
|
|
};
|
|
|
|
|
2021-03-17 11:24:18 +01:00
|
|
|
} // namespace gin
|