#pragma once #include #include #include #include using namespace std::literals; #include "TmplBlockBuffer.tlh" #include "TmplBlockBuffer.tli" #include "Hash.String.hpp" // namespace eError = ECOM::Utility::Error; //----------------------------------------------------------------------------- // ECOM::Utility::Error::... //----------------------------------------------------------------------------- namespace ECOM::Utility::Error { using error_code_type = long; // using view_type = eSTR::StringView; using view_type = std::string_view; using string_type = std::string; //--------------------------- // Base //--------------------------- class Base { public: constexpr Base () = default; virtual ~Base () = default; public: [[nodiscard]] virtual size_t Hash () const = 0; [[nodiscard]] virtual view_type Name () const = 0; }; //--------------------------- // Category //--------------------------- class Category : public ECOM::Utility::Error::Base { public: constexpr Category (error_code_type value) : m_Value { value} {} [[nodiscard]] virtual view_type Message () const = 0; protected: error_code_type m_Value; }; //--------------------------- // Where //--------------------------- class Where : public ECOM::Utility::Error::Base { public: [[nodiscard]] virtual view_type Detail () const = 0; }; //--------------------------- // When //--------------------------- class When : public ECOM::Utility::Error::Base { public: [[nodiscard]] virtual view_type Detail () const = 0; }; //--------------------------- // Domain //--------------------------- class Domain : public ECOM::Utility::Error::Base { public: [[nodiscard]] virtual view_type Detail () const = 0; }; //--------------------------- // HowTo //--------------------------- class HowTo : public ECOM::Utility::Error::Base { public: [[nodiscard]] virtual view_type Detail () const = 0; }; //--------------------------- // Reserved //--------------------------- class Reserved : public ECOM::Utility::Error::Base { public: [[nodiscard]] virtual view_type Detail () const = 0; }; } //----------------------------------------------------------------------------- // Default //----------------------------------------------------------------------------- namespace ECOM::Utility::Error::Default { //--------------------------- // Category //--------------------------- class Category : public ECOM::Utility::Error::Category { using base = ECOM::Utility::Error::Category; static constexpr auto _DefName { "Error.Category.Default"sv }; static constexpr auto _DefHash = ECOM::Utility::Hash (_DefName); public: using base::base; [[nodiscard]] virtual size_t Hash () const override { return _DefHash; } [[nodiscard]] virtual view_type Name () const override { return _DefName; } [[nodiscard]] virtual view_type Message () const override { return view_type (); } public: static bool Is (const ECOM::Utility::Error::Category & with) { return (with.Hash () == _DefHash); } }; //--------------------------- // Where //--------------------------- class Where : public ECOM::Utility::Error::Where { using base = ECOM::Utility::Error::Where; static constexpr auto _DefName { "Error.Where.Default"sv }; static constexpr auto _DefHash = ECOM::Utility::Hash (_DefName); public: constexpr Where (const view_type & value) noexcept : m_Value { value } {} [[nodiscard]] virtual size_t Hash () const override { return _DefHash; } [[nodiscard]] virtual view_type Name () const override { return _DefName; } [[nodiscard]] virtual view_type Detail () const override { return m_Value; } constexpr Where (const Where & from) noexcept : m_Value { from.m_Value } {} constexpr Where (Where && from) noexcept : m_Value { std::move (from.m_Value) } {} public: static bool Is (const ECOM::Utility::Error::Where & with) { return (with.Hash () == _DefHash); } protected: const view_type m_Value; }; //--------------------------- // Domain //--------------------------- class Domain : public ECOM::Utility::Error::Domain { using base = ECOM::Utility::Error::Domain; static constexpr auto _DefName { "Error.Domain.Default"sv }; static constexpr auto _DefHash = ECOM::Utility::Hash (_DefName); public: constexpr Domain (const view_type & value) noexcept : m_Value { value } {} [[nodiscard]] virtual size_t Hash () const override { return _DefHash; } [[nodiscard]] virtual view_type Name () const override { return _DefName; } [[nodiscard]] virtual view_type Detail () const override { return m_Value; } constexpr Domain (const Domain & from) noexcept : m_Value { from.m_Value } {} constexpr Domain (Domain && from) noexcept : m_Value { std::move (from.m_Value) } {} public: static bool Is (const ECOM::Utility::Error::Domain & with) { return (with.Hash () == _DefHash); } protected: const view_type m_Value; }; } namespace ECOM::Utility::Error { //----------------------------------------------------------------------------- // ErrorCode // m_Category 一定非空, 其他的未必 //----------------------------------------------------------------------------- class ErrorCode { public: ErrorCode () noexcept : m_Value (0), m_Category (std::make_unique (0)) { } ErrorCode (error_code_type _Val) noexcept : m_Value (_Val), m_Category (std::make_unique (_Val)) { } ErrorCode (error_code_type _Val, std::unique_ptr && _cat) noexcept : m_Value (_Val), m_Category (std::move (_cat)) { assert (m_Category); } ErrorCode (error_code_type _Val, std::unique_ptr && _cat, std::unique_ptr && _where) noexcept : m_Value (_Val), m_Category (std::move (_cat)), m_Where (std::move (_where)) { assert (m_Category); } ErrorCode (error_code_type _Val, std::unique_ptr && _cat, std::unique_ptr && _where, std::unique_ptr && _domain) noexcept : m_Value (_Val), m_Category (std::move (_cat)), m_Where (std::move (_where)), m_Domain (std::move (_domain)) { assert (m_Category); } ~ErrorCode () = default; ErrorCode (const ErrorCode & from) = delete; ErrorCode (ErrorCode && from) noexcept { MoveAssign (std::move (from)); } public: ErrorCode & operator = (const ErrorCode & from) = delete; ErrorCode & operator = (ErrorCode && from) noexcept { MoveAssign (std::move (from)); return (*this); } public: [[nodiscard]] error_code_type Value () const { return m_Value; } [[nodiscard]] view_type What () const { assert (m_Category); return m_Category->Message (); } [[nodiscard]] view_type Where () const { return (m_Where ? m_Where ->Detail () : view_type ()); } [[nodiscard]] view_type Domain () const { return (m_Domain ? m_Domain ->Detail () : view_type ()); } [[nodiscard]] view_type HowTo () const { return (m_HowTo ? m_HowTo ->Detail () : view_type ()); } [[nodiscard]] view_type Reserved () const { return (m_Reserved ? m_Reserved ->Detail () : view_type ()); } [[nodiscard]] const class Category * GetCategory () const { assert (m_Category); return m_Category.get (); } [[nodiscard]] const class Where * GetWhere () const { return m_Where.get (); } [[nodiscard]] const class Domain * GetDomain () const { return m_Domain.get (); } [[nodiscard]] const class HowTo * GetHowTo () const { return m_HowTo.get (); } [[nodiscard]] const class Reserved * GetReserved () const { return m_Reserved.get (); } public: [[nodiscard]] const class ErrorCode * Cause () const { if (m_Root) return m_Root.get (); else return this; } public: [[nodiscard]] string_type ToString () const { string_type rc; rc.reserve (1024); rc.append ("Code="sv).append (std::to_string (m_Value)) .append (", Message=["sv).append (What ()).append ("]"sv) .append (", Category=["sv).append (m_Category->Name ()).append ("]"sv); if (m_Where) rc.append (", Where=["sv).append (m_Where->Name ()).append (", "sv).append (m_Where->Detail ()).append ("]"sv); else rc.append (", Where=[?>"sv); if (m_Domain) rc.append (", Domain=["sv).append (m_Domain->Name ()).append (", "sv).append (m_Domain->Detail ()).append ("]"sv); else rc.append (", Domain=[?>"sv); if (m_HowTo) rc.append (", HowTo=["sv).append (m_HowTo->Name ()).append (", "sv).append (m_HowTo->Detail ()).append ("]"sv); else rc.append (", HowTo=[?>"sv); if (m_Reserved) rc.append (", Reserved=["sv).append (m_Reserved->Name ()).append (", "sv).append (m_Reserved->Detail ()).append ("]"sv); else rc.append (", Reserved=[?>"sv); return rc; } public: ErrorCode & Set (std::unique_ptr && _val) { m_Category = std::move (_val); assert (m_Category); return *this; } ErrorCode & Set (std::unique_ptr && _val) { m_Where = std::move (_val); return *this; } ErrorCode & Set (std::unique_ptr && _val) { m_Domain = std::move (_val); return *this; } ErrorCode & Set (std::unique_ptr && _val) { m_HowTo = std::move (_val); return *this; } ErrorCode & Set (std::unique_ptr && _val) { m_Reserved = std::move (_val); return *this; } void Set (class ErrorCode && _val) { m_Root.reset (new ErrorCode (std::move (_val))); } private: void MoveAssign (ErrorCode && from) { this->m_Value = from.m_Value; this->m_Category = std::move (from.m_Category); this->m_Where = std::move (from.m_Where); this->m_Domain = std::move (from.m_Domain); this->m_HowTo = std::move (from.m_HowTo); this->m_Reserved = std::move (from.m_Reserved); this->m_Root = std::move (from.m_Root); assert (m_Category); } private: error_code_type m_Value; std::unique_ptr m_Category; std::unique_ptr m_Where; std::unique_ptr m_Domain; std::unique_ptr m_HowTo; std::unique_ptr m_Reserved; std::unique_ptr m_Root; }; } //----------------------------------------------------------------------------- // 通用错误/组件内部错误, 比如参数错误, 检测到 NULL 参数等 // 枚举量来自 2019\Community\VC\Tools\MSVC\14.29.30133\include\xerrc.h //----------------------------------------------------------------------------- namespace ECOM::Utility::Error::Generic { enum class enError { enOK = 0, enNoError = 0, enUnknown = 1 , // 未知错误 create_file_failed, read_file_failed, write_file_failed, device_or_resource_busy, // EBUSY device_or_resource_power_off, // device_or_resource_offline, // invalid_argument, // EINVAL invalid_object, // EINVAL io_error, // EIO no_buffer_space, // ENOBUFS permission_denied, // EACCES no_message, // ENOMS no_such_device_or_address, // ENXIO no_such_device, // ENODEV no_such_file_or_directory, // ENOENT no_enough_memory, // ENOMEM operation_not_permitted, // EPERM operation_not_supported, // EOPNOTSUPP resource_unavailable_try_again, // EAGAIN result_out_of_range, // ERANGE timed_out, // ETIMEDOUT value_too_large, // EOVERFLOW value_too_small, // lock_failed, // bad_protocol, // processing_failure, // network_error, // database_error, // exception, // }; //--------------------------- // Category //--------------------------- class Category : public ECOM::Utility::Error::Category { using base = ECOM::Utility::Error::Category; static constexpr auto _DefName { "Error.Catelog.Generic"sv }; static constexpr auto _DefHash = ECOM::Utility::Hash (_DefName); public: using base::base; [[nodiscard]] virtual size_t Hash () const override { return _DefHash; } [[nodiscard]] virtual view_type Name () const override { return _DefName; } [[nodiscard]] virtual view_type Message () const override { if (m_Message.empty ()) const_cast (m_Message) = ToMessage (); return m_Message; } public: static bool Is (const ECOM::Utility::Error::Category & with) { return (with.Hash () == _DefHash); } protected: view_type m_Message; protected: [[nodiscard]] view_type ToMessage () const { auto ec = static_cast (m_Value); switch (ec) { case enError::enUnknown : return "Unknown"sv; case enError::create_file_failed : return "Create file failed"sv; case enError::read_file_failed : return "Read file failed"sv; case enError::write_file_failed : return "Write file failed"sv; case enError::device_or_resource_busy : return "Device or resource busy"sv; case enError::device_or_resource_power_off : return "Device or resource power off"sv; case enError::device_or_resource_offline : return "Device or resource offline"sv; case enError::invalid_argument : return "Invalid argument"sv; case enError::invalid_object : return "Invalid object"sv; case enError::io_error : return "IO error"sv; case enError::no_buffer_space : return "No buffer space"sv; case enError::permission_denied : return "Permission denied"sv; case enError::no_message : return "No message"sv; case enError::no_such_device_or_address : return "No such device or address"sv; case enError::no_such_device : return "No such device"sv; case enError::no_such_file_or_directory : return "No such file or directory"sv; case enError::no_enough_memory : return "No enough memory"sv; case enError::operation_not_permitted : return "Operation not permitted"sv; case enError::operation_not_supported : return "Operation not supported"sv; case enError::resource_unavailable_try_again : return "Resource unavailable, try again"sv; case enError::result_out_of_range : return "Result out of range"sv; case enError::timed_out : return "Time out"sv; case enError::value_too_large : return "Value too large"sv; case enError::value_too_small : return "Value too small"sv; case enError::processing_failure : return "Processing failure"sv; case enError::lock_failed : return "Lock failed"sv; case enError::bad_protocol : return "Bad protocol"sv; case enError::network_error : return "Network error"sv; case enError::database_error : return "Database error"sv; case enError::exception : return "Exception"sv; default : return "Undefined generic error"sv; } } }; //--------------------------- // ErrorCategory_With //--------------------------- class ErrorCategory_With : public Category { using base = Category; static constexpr auto _DefName { "Error.Catelog.Generic.With"sv }; static constexpr auto _DefHash = ECOM::Utility::Hash (_DefName); public: ErrorCategory_With (error_code_type ec, view_type msg) : base (ec), m_With { msg } { } [[nodiscard]] virtual size_t Hash () const override { return _DefHash; } [[nodiscard]] virtual view_type Name () const override { return _DefName; } [[nodiscard]] virtual view_type Message () const override { if (m_Detail.empty ()) { auto & dt = const_cast (m_Detail); dt.append (base::Message ()).append (", with=["sv).append (m_With).append ("]"sv); } return m_Detail; } private: const string_type m_With; const string_type m_Detail; }; inline ErrorCode Make (error_code_type ec) { return { ec, std::make_unique (ec) }; } inline ErrorCode Make (enError ec) { return { static_cast (ec), std::make_unique (static_cast (ec)) }; } } //----------------------------------------------------------------------------- // Windows API 错误 //----------------------------------------------------------------------------- namespace ECOM::Utility::Error::OS::Windows { //--------------------------- // Category //--------------------------- class Category : public ECOM::Utility::Error::Category { using base = ECOM::Utility::Error::Category; static constexpr auto _DefName { "Error.Catelog.OS.Windows"sv }; static constexpr auto _DefHash = ECOM::Utility::Hash (_DefName); public: Category (error_code_type ec) : base (ec) {} [[nodiscard]] virtual size_t Hash () const override { return _DefHash; } [[nodiscard]] virtual view_type Name () const override { return _DefName; } [[nodiscard]] virtual view_type Message () const override { if (m_Message.empty ()) const_cast (m_Message) = ErrorCodeToString (m_Value); return m_Message; } public: static bool Is (const ECOM::Utility::Error::Category & with) { return (with.Hash () == _DefHash); } private: static std::string ErrorCodeToString (DWORD errorCode) { constexpr int nPreAlloc = 4096; OBlockBuffer OMB; auto pc = reinterpret_cast (OMB.GetBufferSetCount (nPreAlloc + 2)); if (errorCode == 0) errorCode = GetLastError (); auto szmsg = ::FormatMessageA (FORMAT_MESSAGE_FROM_SYSTEM, NULL, errorCode, // GetLastError (), MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)pc, nPreAlloc, NULL); std::string rc (pc, szmsg - 2); // -2 是为了去掉尾部的 \r\n return rc; } private: string_type m_Message; }; inline ErrorCode Make (error_code_type ec) { return { ec, std::make_unique (ec) }; } } //----------------------------------------------------------------------------- // ErrorCode //----------------------------------------------------------------------------- //using eiResult = ECOM::Utility::Either ; //constexpr auto eiSuccess = ECOM::Utility::left (1);