399 lines
14 KiB
C++
399 lines
14 KiB
C++
#pragma once
|
||
|
||
#include <extra2d/core/types.h>
|
||
#include <string>
|
||
#include <variant>
|
||
|
||
namespace extra2d {
|
||
|
||
/**
|
||
* @brief 错误码枚举
|
||
*/
|
||
enum class ErrorCode {
|
||
None = 0,
|
||
Unknown = 1,
|
||
InvalidArgument = 2,
|
||
OutOfMemory = 3,
|
||
FileNotFound = 4,
|
||
PermissionDenied = 5,
|
||
NotImplemented = 6,
|
||
AlreadyExists = 7,
|
||
NotInitialized = 8,
|
||
AlreadyInitialized = 9,
|
||
OperationFailed = 10,
|
||
Timeout = 11,
|
||
Cancelled = 12,
|
||
InvalidState = 13,
|
||
ResourceExhausted = 14,
|
||
Unavailable = 15,
|
||
DataLoss = 16,
|
||
Unauthenticated = 17,
|
||
PermissionDenied2 = 18,
|
||
ResourceNotFound = 19,
|
||
Aborted = 20,
|
||
OutOfRange = 21,
|
||
Unimplemented = 22,
|
||
Internal = 23,
|
||
DataCorrupted = 24,
|
||
RequestTooLarge = 25,
|
||
ResourceBusy = 26,
|
||
QuotaExceeded = 27,
|
||
DeadlineExceeded = 28,
|
||
LoadBalancing = 29,
|
||
NetworkError = 30,
|
||
ProtocolError = 31,
|
||
ServiceUnavailable = 32,
|
||
GatewayError = 33,
|
||
RateLimited = 34,
|
||
BadRequest = 35,
|
||
Unauthorized = 36,
|
||
Forbidden = 37,
|
||
NotFound = 38,
|
||
MethodNotAllowed = 39,
|
||
Conflict = 40,
|
||
Gone = 41,
|
||
LengthRequired = 42,
|
||
PreconditionFailed = 43,
|
||
PayloadTooLarge = 44,
|
||
UriTooLong = 45,
|
||
UnsupportedMediaType = 46,
|
||
RangeNotSatisfiable = 47,
|
||
ExpectationFailed = 48,
|
||
ImATeapot = 49,
|
||
MisdirectedRequest = 50,
|
||
UnprocessableEntity = 51,
|
||
Locked = 52,
|
||
FailedDependency = 53,
|
||
TooEarly = 54,
|
||
UpgradeRequired = 55,
|
||
PreconditionRequired = 56,
|
||
TooManyRequests = 57,
|
||
RequestHeaderFieldsTooLarge = 58,
|
||
UnavailableForLegalReasons = 59
|
||
};
|
||
|
||
/**
|
||
* @brief 错误信息结构
|
||
*/
|
||
struct Error {
|
||
ErrorCode code = ErrorCode::None;
|
||
std::string message;
|
||
std::string file;
|
||
int line = 0;
|
||
|
||
Error() = default;
|
||
Error(ErrorCode c, const std::string& msg) : code(c), message(msg) {}
|
||
Error(ErrorCode c, const std::string& msg, const std::string& f, int l)
|
||
: code(c), message(msg), file(f), line(l) {}
|
||
|
||
bool ok() const { return code == ErrorCode::None; }
|
||
|
||
static Error none() { return Error(); }
|
||
static Error unknown(const std::string& msg) { return Error(ErrorCode::Unknown, msg); }
|
||
static Error invalidArgument(const std::string& msg) { return Error(ErrorCode::InvalidArgument, msg); }
|
||
static Error outOfMemory(const std::string& msg) { return Error(ErrorCode::OutOfMemory, msg); }
|
||
static Error fileNotFound(const std::string& msg) { return Error(ErrorCode::FileNotFound, msg); }
|
||
static Error permissionDenied(const std::string& msg) { return Error(ErrorCode::PermissionDenied, msg); }
|
||
static Error notImplemented(const std::string& msg) { return Error(ErrorCode::NotImplemented, msg); }
|
||
static Error alreadyExists(const std::string& msg) { return Error(ErrorCode::AlreadyExists, msg); }
|
||
static Error notInitialized(const std::string& msg) { return Error(ErrorCode::NotInitialized, msg); }
|
||
static Error alreadyInitialized(const std::string& msg) { return Error(ErrorCode::AlreadyInitialized, msg); }
|
||
static Error operationFailed(const std::string& msg) { return Error(ErrorCode::OperationFailed, msg); }
|
||
static Error timeout(const std::string& msg) { return Error(ErrorCode::Timeout, msg); }
|
||
static Error cancelled(const std::string& msg) { return Error(ErrorCode::Cancelled, msg); }
|
||
static Error invalidState(const std::string& msg) { return Error(ErrorCode::InvalidState, msg); }
|
||
static Error resourceExhausted(const std::string& msg) { return Error(ErrorCode::ResourceExhausted, msg); }
|
||
static Error unavailable(const std::string& msg) { return Error(ErrorCode::Unavailable, msg); }
|
||
static Error dataLoss(const std::string& msg) { return Error(ErrorCode::DataLoss, msg); }
|
||
static Error unauthenticated(const std::string& msg) { return Error(ErrorCode::Unauthenticated, msg); }
|
||
static Error permissionDenied2(const std::string& msg) { return Error(ErrorCode::PermissionDenied2, msg); }
|
||
static Error resourceNotFound(const std::string& msg) { return Error(ErrorCode::ResourceNotFound, msg); }
|
||
static Error aborted(const std::string& msg) { return Error(ErrorCode::Aborted, msg); }
|
||
static Error outOfRange(const std::string& msg) { return Error(ErrorCode::OutOfRange, msg); }
|
||
static Error unimplemented(const std::string& msg) { return Error(ErrorCode::Unimplemented, msg); }
|
||
static Error internal(const std::string& msg) { return Error(ErrorCode::Internal, msg); }
|
||
static Error dataCorrupted(const std::string& msg) { return Error(ErrorCode::DataCorrupted, msg); }
|
||
static Error requestTooLarge(const std::string& msg) { return Error(ErrorCode::RequestTooLarge, msg); }
|
||
static Error resourceBusy(const std::string& msg) { return Error(ErrorCode::ResourceBusy, msg); }
|
||
static Error quotaExceeded(const std::string& msg) { return Error(ErrorCode::QuotaExceeded, msg); }
|
||
static Error deadlineExceeded(const std::string& msg) { return Error(ErrorCode::DeadlineExceeded, msg); }
|
||
static Error loadBalancing(const std::string& msg) { return Error(ErrorCode::LoadBalancing, msg); }
|
||
static Error networkError(const std::string& msg) { return Error(ErrorCode::NetworkError, msg); }
|
||
static Error protocolError(const std::string& msg) { return Error(ErrorCode::ProtocolError, msg); }
|
||
static Error serviceUnavailable(const std::string& msg) { return Error(ErrorCode::ServiceUnavailable, msg); }
|
||
static Error gatewayError(const std::string& msg) { return Error(ErrorCode::GatewayError, msg); }
|
||
static Error rateLimited(const std::string& msg) { return Error(ErrorCode::RateLimited, msg); }
|
||
static Error badRequest(const std::string& msg) { return Error(ErrorCode::BadRequest, msg); }
|
||
static Error unauthorized(const std::string& msg) { return Error(ErrorCode::Unauthorized, msg); }
|
||
static Error forbidden(const std::string& msg) { return Error(ErrorCode::Forbidden, msg); }
|
||
static Error notFound(const std::string& msg) { return Error(ErrorCode::NotFound, msg); }
|
||
static Error methodNotAllowed(const std::string& msg) { return Error(ErrorCode::MethodNotAllowed, msg); }
|
||
static Error conflict(const std::string& msg) { return Error(ErrorCode::Conflict, msg); }
|
||
static Error gone(const std::string& msg) { return Error(ErrorCode::Gone, msg); }
|
||
static Error lengthRequired(const std::string& msg) { return Error(ErrorCode::LengthRequired, msg); }
|
||
static Error preconditionFailed(const std::string& msg) { return Error(ErrorCode::PreconditionFailed, msg); }
|
||
static Error payloadTooLarge(const std::string& msg) { return Error(ErrorCode::PayloadTooLarge, msg); }
|
||
static Error uriTooLong(const std::string& msg) { return Error(ErrorCode::UriTooLong, msg); }
|
||
static Error unsupportedMediaType(const std::string& msg) { return Error(ErrorCode::UnsupportedMediaType, msg); }
|
||
static Error rangeNotSatisfiable(const std::string& msg) { return Error(ErrorCode::RangeNotSatisfiable, msg); }
|
||
static Error expectationFailed(const std::string& msg) { return Error(ErrorCode::ExpectationFailed, msg); }
|
||
static Error imATeapot(const std::string& msg) { return Error(ErrorCode::ImATeapot, msg); }
|
||
static Error misdirectedRequest(const std::string& msg) { return Error(ErrorCode::MisdirectedRequest, msg); }
|
||
static Error unprocessableEntity(const std::string& msg) { return Error(ErrorCode::UnprocessableEntity, msg); }
|
||
static Error locked(const std::string& msg) { return Error(ErrorCode::Locked, msg); }
|
||
static Error failedDependency(const std::string& msg) { return Error(ErrorCode::FailedDependency, msg); }
|
||
static Error tooEarly(const std::string& msg) { return Error(ErrorCode::TooEarly, msg); }
|
||
static Error upgradeRequired(const std::string& msg) { return Error(ErrorCode::UpgradeRequired, msg); }
|
||
static Error preconditionRequired(const std::string& msg) { return Error(ErrorCode::PreconditionRequired, msg); }
|
||
static Error tooManyRequests(const std::string& msg) { return Error(ErrorCode::TooManyRequests, msg); }
|
||
static Error requestHeaderFieldsTooLarge(const std::string& msg) { return Error(ErrorCode::RequestHeaderFieldsTooLarge, msg); }
|
||
static Error unavailableForLegalReasons(const std::string& msg) { return Error(ErrorCode::UnavailableForLegalReasons, msg); }
|
||
};
|
||
|
||
/**
|
||
* @brief Result类型,用于错误处理
|
||
* @tparam T 成功时的值类型
|
||
* @tparam E 错误类型,默认为Error
|
||
*/
|
||
template<typename T, typename E = Error>
|
||
class Result {
|
||
public:
|
||
Result() : hasValue_(false) {
|
||
new (&storage_.error) E();
|
||
}
|
||
|
||
~Result() {
|
||
if (hasValue_) {
|
||
storage_.value.~T();
|
||
} else {
|
||
storage_.error.~E();
|
||
}
|
||
}
|
||
|
||
Result(const Result& other) : hasValue_(other.hasValue_) {
|
||
if (hasValue_) {
|
||
new (&storage_.value) T(other.storage_.value);
|
||
} else {
|
||
new (&storage_.error) E(other.storage_.error);
|
||
}
|
||
}
|
||
|
||
Result(Result&& other) noexcept : hasValue_(other.hasValue_) {
|
||
if (hasValue_) {
|
||
new (&storage_.value) T(std::move(other.storage_.value));
|
||
} else {
|
||
new (&storage_.error) E(std::move(other.storage_.error));
|
||
}
|
||
}
|
||
|
||
Result& operator=(const Result& other) {
|
||
if (this != &other) {
|
||
this->~Result();
|
||
hasValue_ = other.hasValue_;
|
||
if (hasValue_) {
|
||
new (&storage_.value) T(other.storage_.value);
|
||
} else {
|
||
new (&storage_.error) E(other.storage_.error);
|
||
}
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
Result& operator=(Result&& other) noexcept {
|
||
if (this != &other) {
|
||
this->~Result();
|
||
hasValue_ = other.hasValue_;
|
||
if (hasValue_) {
|
||
new (&storage_.value) T(std::move(other.storage_.value));
|
||
} else {
|
||
new (&storage_.error) E(std::move(other.storage_.error));
|
||
}
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
static Result<T, E> ok(T value) {
|
||
Result<T, E> result;
|
||
result.hasValue_ = true;
|
||
new (&result.storage_.value) T(std::move(value));
|
||
return result;
|
||
}
|
||
|
||
static Result<T, E> err(E error) {
|
||
Result<T, E> result;
|
||
result.hasValue_ = false;
|
||
new (&result.storage_.error) E(std::move(error));
|
||
return result;
|
||
}
|
||
|
||
bool ok() const { return hasValue_; }
|
||
bool isOk() const { return hasValue_; }
|
||
bool isErr() const { return !hasValue_; }
|
||
|
||
T& value() & {
|
||
return storage_.value;
|
||
}
|
||
|
||
const T& value() const & {
|
||
return storage_.value;
|
||
}
|
||
|
||
T&& value() && {
|
||
return std::move(storage_.value);
|
||
}
|
||
|
||
E& error() & {
|
||
return storage_.error;
|
||
}
|
||
|
||
const E& error() const & {
|
||
return storage_.error;
|
||
}
|
||
|
||
E&& error() && {
|
||
return std::move(storage_.error);
|
||
}
|
||
|
||
T valueOr(T defaultValue) const {
|
||
return hasValue_ ? storage_.value : std::move(defaultValue);
|
||
}
|
||
|
||
template<typename F>
|
||
Result<T, E> map(F&& f) {
|
||
if (hasValue_) {
|
||
return Result<T, E>::ok(f(storage_.value));
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
template<typename F>
|
||
Result<T, E> mapErr(F&& f) {
|
||
if (!hasValue_) {
|
||
return Result<T, E>::err(f(storage_.error));
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
template<typename F>
|
||
auto andThen(F&& f) -> decltype(f(std::declval<T>())) {
|
||
if (hasValue_) {
|
||
return f(storage_.value);
|
||
}
|
||
return Result<typename decltype(f(std::declval<T>()))::ValueType, E>::err(storage_.error);
|
||
}
|
||
|
||
template<typename F>
|
||
Result<T, E> orElse(F&& f) {
|
||
if (!hasValue_) {
|
||
return f(storage_.error);
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
private:
|
||
union Storage {
|
||
T value;
|
||
E error;
|
||
|
||
Storage() {}
|
||
~Storage() {}
|
||
} storage_;
|
||
|
||
bool hasValue_;
|
||
};
|
||
|
||
// 特化void类型
|
||
template<typename E>
|
||
class Result<void, E> {
|
||
public:
|
||
Result() : hasValue_(true) {}
|
||
|
||
~Result() {
|
||
if (!hasValue_) {
|
||
storage_.error.~E();
|
||
}
|
||
}
|
||
|
||
Result(const Result& other) : hasValue_(other.hasValue_) {
|
||
if (!hasValue_) {
|
||
new (&storage_.error) E(other.storage_.error);
|
||
}
|
||
}
|
||
|
||
Result(Result&& other) noexcept : hasValue_(other.hasValue_) {
|
||
if (!hasValue_) {
|
||
new (&storage_.error) E(std::move(other.storage_.error));
|
||
}
|
||
}
|
||
|
||
Result& operator=(const Result& other) {
|
||
if (this != &other) {
|
||
this->~Result();
|
||
hasValue_ = other.hasValue_;
|
||
if (!hasValue_) {
|
||
new (&storage_.error) E(other.storage_.error);
|
||
}
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
Result& operator=(Result&& other) noexcept {
|
||
if (this != &other) {
|
||
this->~Result();
|
||
hasValue_ = other.hasValue_;
|
||
if (!hasValue_) {
|
||
new (&storage_.error) E(std::move(other.storage_.error));
|
||
}
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
static Result<void, E> ok() {
|
||
return Result<void, E>();
|
||
}
|
||
|
||
static Result<void, E> err(E error) {
|
||
Result<void, E> result;
|
||
result.hasValue_ = false;
|
||
new (&result.storage_.error) E(std::move(error));
|
||
return result;
|
||
}
|
||
|
||
bool ok() const { return hasValue_; }
|
||
bool isOk() const { return hasValue_; }
|
||
bool isErr() const { return !hasValue_; }
|
||
|
||
E& error() & {
|
||
return storage_.error;
|
||
}
|
||
|
||
const E& error() const & {
|
||
return storage_.error;
|
||
}
|
||
|
||
E&& error() && {
|
||
return std::move(storage_.error);
|
||
}
|
||
|
||
private:
|
||
union Storage {
|
||
E error;
|
||
|
||
Storage() {}
|
||
~Storage() {}
|
||
} storage_;
|
||
|
||
bool hasValue_;
|
||
};
|
||
|
||
// 便捷宏
|
||
#define E2D_TRY(result) \
|
||
do { \
|
||
auto _res = (result); \
|
||
if (!_res.ok()) { \
|
||
return Result<decltype(_res)::ValueType, decltype(_res)::ErrorType>::err(_res.error()); \
|
||
} \
|
||
} while(0)
|
||
|
||
} // namespace extra2d
|