#pragma once #include #include #include #include #include #include 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(code))); } [[nodiscard]] std::error_condition default_error_condition(int code) const noexcept override { switch (static_cast(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(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 using Result = std::expected; using Status = Result; [[nodiscard]] inline std::unexpected unexpected_error(std::error_code code, std::string detail = {}) { return std::unexpected(Error{ .code = code, .detail = std::move(detail), }); } [[nodiscard]] inline std::unexpected 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 {}; }