Files

265 lines
7.2 KiB
C++

#pragma once
#include <expected>
#include <string>
#include <string_view>
#include <system_error>
#include <type_traits>
#include <utility>
namespace cvmmap_streamer {
enum class ErrorCode : int {
Ok = 0,
InvalidArgument,
InvalidConfig,
Unsupported,
NotReady,
BackendUnavailable,
AllocationFailed,
Io,
Network,
Protocol,
Encoder,
ExternalLibrary,
Serialization,
ChildProcess,
EndOfStream,
Internal,
};
[[nodiscard]]
inline std::string_view error_code_name(ErrorCode code) {
switch (code) {
case ErrorCode::Ok:
return "ok";
case ErrorCode::InvalidArgument:
return "invalid_argument";
case ErrorCode::InvalidConfig:
return "invalid_config";
case ErrorCode::Unsupported:
return "unsupported";
case ErrorCode::NotReady:
return "not_ready";
case ErrorCode::BackendUnavailable:
return "backend_unavailable";
case ErrorCode::AllocationFailed:
return "allocation_failed";
case ErrorCode::Io:
return "io";
case ErrorCode::Network:
return "network";
case ErrorCode::Protocol:
return "protocol";
case ErrorCode::Encoder:
return "encoder";
case ErrorCode::ExternalLibrary:
return "external_library";
case ErrorCode::Serialization:
return "serialization";
case ErrorCode::ChildProcess:
return "child_process";
case ErrorCode::EndOfStream:
return "end_of_stream";
case ErrorCode::Internal:
return "internal";
default:
return "unknown";
}
}
class StreamerErrorCategory final : public std::error_category {
public:
[[nodiscard]]
const char *name() const noexcept override {
return "cvmmap_streamer";
}
[[nodiscard]]
std::string message(int code) const override {
return std::string(error_code_name(static_cast<ErrorCode>(code)));
}
[[nodiscard]]
std::error_condition default_error_condition(int code) const noexcept override {
switch (static_cast<ErrorCode>(code)) {
case ErrorCode::Ok:
return {};
case ErrorCode::InvalidArgument:
return std::make_error_condition(std::errc::invalid_argument);
case ErrorCode::Unsupported:
return std::make_error_condition(std::errc::not_supported);
case ErrorCode::AllocationFailed:
return std::make_error_condition(std::errc::not_enough_memory);
case ErrorCode::Io:
return std::make_error_condition(std::errc::io_error);
case ErrorCode::Protocol:
return std::make_error_condition(std::errc::protocol_error);
default:
return std::error_condition(code, *this);
}
}
};
[[nodiscard]]
inline const std::error_category &streamer_error_category() noexcept {
static const StreamerErrorCategory category{};
return category;
}
[[nodiscard]]
inline std::error_code make_error_code(ErrorCode code) noexcept {
return {static_cast<int>(code), streamer_error_category()};
}
inline constexpr ErrorCode ERR_OK = ErrorCode::Ok;
inline constexpr ErrorCode ERR_INVALID_ARGUMENT = ErrorCode::InvalidArgument;
inline constexpr ErrorCode ERR_INVALID_CONFIG = ErrorCode::InvalidConfig;
inline constexpr ErrorCode ERR_UNSUPPORTED = ErrorCode::Unsupported;
inline constexpr ErrorCode ERR_NOT_READY = ErrorCode::NotReady;
inline constexpr ErrorCode ERR_BACKEND_UNAVAILABLE = ErrorCode::BackendUnavailable;
inline constexpr ErrorCode ERR_ALLOCATION_FAILED = ErrorCode::AllocationFailed;
inline constexpr ErrorCode ERR_IO = ErrorCode::Io;
inline constexpr ErrorCode ERR_NETWORK = ErrorCode::Network;
inline constexpr ErrorCode ERR_PROTOCOL = ErrorCode::Protocol;
inline constexpr ErrorCode ERR_ENCODER = ErrorCode::Encoder;
inline constexpr ErrorCode ERR_EXTERNAL_LIBRARY = ErrorCode::ExternalLibrary;
inline constexpr ErrorCode ERR_SERIALIZATION = ErrorCode::Serialization;
inline constexpr ErrorCode ERR_CHILD_PROCESS = ErrorCode::ChildProcess;
inline constexpr ErrorCode ERR_END_OF_STREAM = ErrorCode::EndOfStream;
inline constexpr ErrorCode ERR_INTERNAL = ErrorCode::Internal;
struct Error {
std::error_code code{make_error_code(ERR_OK)};
std::string detail{};
};
template <typename T>
using Result = std::expected<T, Error>;
using Status = Result<void>;
[[nodiscard]]
inline std::unexpected<Error> unexpected_error(std::error_code code, std::string detail = {}) {
return std::unexpected(Error{
.code = code,
.detail = std::move(detail),
});
}
[[nodiscard]]
inline std::unexpected<Error> unexpected_error(ErrorCode code, std::string detail = {}) {
return unexpected_error(make_error_code(code), std::move(detail));
}
[[nodiscard]]
inline bool has_error_code(const std::error_code &code, ErrorCode expected) noexcept {
return code == make_error_code(expected);
}
[[nodiscard]]
inline bool has_error_code(const Error &error, ErrorCode expected) noexcept {
return has_error_code(error.code, expected);
}
[[nodiscard]]
inline bool has_error_condition(const std::error_code &code, std::errc condition) noexcept {
return code == condition;
}
[[nodiscard]]
inline bool has_error_condition(const Error &error, std::errc condition) noexcept {
return has_error_condition(error.code, condition);
}
[[nodiscard]]
inline bool is_invalid_argument_error(const std::error_code &code) noexcept {
return has_error_condition(code, std::errc::invalid_argument);
}
[[nodiscard]]
inline bool is_invalid_argument_error(const Error &error) noexcept {
return is_invalid_argument_error(error.code);
}
[[nodiscard]]
inline bool is_unsupported_error(const std::error_code &code) noexcept {
return has_error_condition(code, std::errc::not_supported);
}
[[nodiscard]]
inline bool is_unsupported_error(const Error &error) noexcept {
return is_unsupported_error(error.code);
}
[[nodiscard]]
inline bool is_allocation_failed_error(const std::error_code &code) noexcept {
return has_error_condition(code, std::errc::not_enough_memory);
}
[[nodiscard]]
inline bool is_allocation_failed_error(const Error &error) noexcept {
return is_allocation_failed_error(error.code);
}
[[nodiscard]]
inline bool is_io_error(const std::error_code &code) noexcept {
return has_error_condition(code, std::errc::io_error);
}
[[nodiscard]]
inline bool is_io_error(const Error &error) noexcept {
return is_io_error(error.code);
}
[[nodiscard]]
inline bool is_protocol_error(const std::error_code &code) noexcept {
return has_error_condition(code, std::errc::protocol_error);
}
[[nodiscard]]
inline bool is_protocol_error(const Error &error) noexcept {
return is_protocol_error(error.code);
}
[[nodiscard]]
inline bool is_not_ready_error(const std::error_code &code) noexcept {
return has_error_code(code, ERR_NOT_READY);
}
[[nodiscard]]
inline bool is_not_ready_error(const Error &error) noexcept {
return is_not_ready_error(error.code);
}
[[nodiscard]]
inline bool is_end_of_stream_error(const std::error_code &code) noexcept {
return has_error_code(code, ERR_END_OF_STREAM);
}
[[nodiscard]]
inline bool is_end_of_stream_error(const Error &error) noexcept {
return is_end_of_stream_error(error.code);
}
[[nodiscard]]
inline std::string format_error(const Error &error) {
const auto message = error.code.message();
if (error.detail.empty()) {
return message;
}
if (error.code.category() == streamer_error_category()) {
return message + ": " + error.detail;
}
return error.detail + ": " + message;
}
}
namespace std {
template <>
struct is_error_code_enum<::cvmmap_streamer::ErrorCode> : true_type {};
}