Utility.Error.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. #pragma once
  2. #include <system_error>
  3. #include <memory>
  4. #include <map>
  5. #include <string>
  6. using namespace std::literals;
  7. #include "TmplBlockBuffer.tlh"
  8. #include "TmplBlockBuffer.tli"
  9. #include "Hash.String.hpp"
  10. // namespace eError = ECOM::Utility::Error;
  11. //-----------------------------------------------------------------------------
  12. // ECOM::Utility::Error::...
  13. //-----------------------------------------------------------------------------
  14. namespace ECOM::Utility::Error
  15. {
  16. using error_code_type = long;
  17. // using view_type = eSTR::StringView;
  18. using view_type = std::string_view;
  19. using string_type = std::string;
  20. //---------------------------
  21. // Base
  22. //---------------------------
  23. class Base
  24. {
  25. public:
  26. constexpr Base () = default;
  27. virtual ~Base () = default;
  28. public:
  29. [[nodiscard]] virtual size_t Hash () const = 0;
  30. [[nodiscard]] virtual view_type Name () const = 0;
  31. };
  32. //---------------------------
  33. // Category
  34. //---------------------------
  35. class Category : public ECOM::Utility::Error::Base
  36. {
  37. public:
  38. constexpr Category (error_code_type value) : m_Value { value} {}
  39. [[nodiscard]] virtual view_type Message () const = 0;
  40. protected:
  41. error_code_type m_Value;
  42. };
  43. //---------------------------
  44. // Where
  45. //---------------------------
  46. class Where : public ECOM::Utility::Error::Base
  47. {
  48. public:
  49. [[nodiscard]] virtual view_type Detail () const = 0;
  50. };
  51. //---------------------------
  52. // When
  53. //---------------------------
  54. class When : public ECOM::Utility::Error::Base
  55. {
  56. public:
  57. [[nodiscard]] virtual view_type Detail () const = 0;
  58. };
  59. //---------------------------
  60. // Domain
  61. //---------------------------
  62. class Domain : public ECOM::Utility::Error::Base
  63. {
  64. public:
  65. [[nodiscard]] virtual view_type Detail () const = 0;
  66. };
  67. //---------------------------
  68. // HowTo
  69. //---------------------------
  70. class HowTo : public ECOM::Utility::Error::Base
  71. {
  72. public:
  73. [[nodiscard]] virtual view_type Detail () const = 0;
  74. };
  75. //---------------------------
  76. // Reserved
  77. //---------------------------
  78. class Reserved : public ECOM::Utility::Error::Base
  79. {
  80. public:
  81. [[nodiscard]] virtual view_type Detail () const = 0;
  82. };
  83. }
  84. //-----------------------------------------------------------------------------
  85. // Default
  86. //-----------------------------------------------------------------------------
  87. namespace ECOM::Utility::Error::Default
  88. {
  89. //---------------------------
  90. // Category
  91. //---------------------------
  92. class Category : public ECOM::Utility::Error::Category
  93. {
  94. using base = ECOM::Utility::Error::Category;
  95. static constexpr auto _DefName { "Error.Category.Default"sv };
  96. static constexpr auto _DefHash = ECOM::Utility::Hash (_DefName);
  97. public:
  98. using base::base;
  99. [[nodiscard]] virtual size_t Hash () const override { return _DefHash; }
  100. [[nodiscard]] virtual view_type Name () const override { return _DefName; }
  101. [[nodiscard]] virtual view_type Message () const override { return view_type (); }
  102. public:
  103. static bool Is (const ECOM::Utility::Error::Category & with)
  104. {
  105. return (with.Hash () == _DefHash);
  106. }
  107. };
  108. //---------------------------
  109. // Where
  110. //---------------------------
  111. class Where : public ECOM::Utility::Error::Where
  112. {
  113. using base = ECOM::Utility::Error::Where;
  114. static constexpr auto _DefName { "Error.Where.Default"sv };
  115. static constexpr auto _DefHash = ECOM::Utility::Hash (_DefName);
  116. public:
  117. constexpr Where (const view_type & value) noexcept : m_Value { value } {}
  118. [[nodiscard]] virtual size_t Hash () const override { return _DefHash; }
  119. [[nodiscard]] virtual view_type Name () const override { return _DefName; }
  120. [[nodiscard]] virtual view_type Detail () const override
  121. {
  122. return m_Value;
  123. }
  124. constexpr Where (const Where & from) noexcept : m_Value { from.m_Value } {}
  125. constexpr Where (Where && from) noexcept : m_Value { std::move (from.m_Value) } {}
  126. public:
  127. static bool Is (const ECOM::Utility::Error::Where & with)
  128. {
  129. return (with.Hash () == _DefHash);
  130. }
  131. protected:
  132. const view_type m_Value;
  133. };
  134. //---------------------------
  135. // Domain
  136. //---------------------------
  137. class Domain : public ECOM::Utility::Error::Domain
  138. {
  139. using base = ECOM::Utility::Error::Domain;
  140. static constexpr auto _DefName { "Error.Domain.Default"sv };
  141. static constexpr auto _DefHash = ECOM::Utility::Hash (_DefName);
  142. public:
  143. constexpr Domain (const view_type & value) noexcept : m_Value { value } {}
  144. [[nodiscard]] virtual size_t Hash () const override { return _DefHash; }
  145. [[nodiscard]] virtual view_type Name () const override { return _DefName; }
  146. [[nodiscard]] virtual view_type Detail () const override
  147. {
  148. return m_Value;
  149. }
  150. constexpr Domain (const Domain & from) noexcept : m_Value { from.m_Value } {}
  151. constexpr Domain (Domain && from) noexcept : m_Value { std::move (from.m_Value) } {}
  152. public:
  153. static bool Is (const ECOM::Utility::Error::Domain & with)
  154. {
  155. return (with.Hash () == _DefHash);
  156. }
  157. protected:
  158. const view_type m_Value;
  159. };
  160. }
  161. namespace ECOM::Utility::Error
  162. {
  163. //-----------------------------------------------------------------------------
  164. // ErrorCode
  165. // m_Category 一定非空, 其他的未必
  166. //-----------------------------------------------------------------------------
  167. class ErrorCode
  168. {
  169. public:
  170. ErrorCode () noexcept : m_Value (0), m_Category (std::make_unique <Default::Category> (0)) { }
  171. ErrorCode (error_code_type _Val) noexcept : m_Value (_Val), m_Category (std::make_unique <Default::Category> (_Val)) { }
  172. ErrorCode (error_code_type _Val, std::unique_ptr <Category> && _cat) noexcept
  173. : m_Value (_Val), m_Category (std::move (_cat))
  174. {
  175. assert (m_Category);
  176. }
  177. ErrorCode (error_code_type _Val, std::unique_ptr <Category> && _cat, std::unique_ptr <Where> && _where) noexcept
  178. : m_Value (_Val), m_Category (std::move (_cat)), m_Where (std::move (_where))
  179. {
  180. assert (m_Category);
  181. }
  182. ErrorCode (error_code_type _Val, std::unique_ptr <Category> && _cat, std::unique_ptr <Where> && _where, std::unique_ptr <Domain> && _domain) noexcept
  183. : m_Value (_Val), m_Category (std::move (_cat)), m_Where (std::move (_where)), m_Domain (std::move (_domain))
  184. {
  185. assert (m_Category);
  186. }
  187. ~ErrorCode () = default;
  188. ErrorCode (const ErrorCode & from) = delete;
  189. ErrorCode (ErrorCode && from) noexcept
  190. {
  191. MoveAssign (std::move (from));
  192. }
  193. public:
  194. ErrorCode & operator = (const ErrorCode & from) = delete;
  195. ErrorCode & operator = (ErrorCode && from) noexcept
  196. {
  197. MoveAssign (std::move (from));
  198. return (*this);
  199. }
  200. public:
  201. [[nodiscard]] error_code_type Value () const { return m_Value; }
  202. [[nodiscard]] view_type What () const { assert (m_Category); return m_Category->Message (); }
  203. [[nodiscard]] view_type Where () const { return (m_Where ? m_Where ->Detail () : view_type ()); }
  204. [[nodiscard]] view_type Domain () const { return (m_Domain ? m_Domain ->Detail () : view_type ()); }
  205. [[nodiscard]] view_type HowTo () const { return (m_HowTo ? m_HowTo ->Detail () : view_type ()); }
  206. [[nodiscard]] view_type Reserved () const { return (m_Reserved ? m_Reserved ->Detail () : view_type ()); }
  207. [[nodiscard]] const class Category * GetCategory () const { assert (m_Category); return m_Category.get (); }
  208. [[nodiscard]] const class Where * GetWhere () const { return m_Where.get (); }
  209. [[nodiscard]] const class Domain * GetDomain () const { return m_Domain.get (); }
  210. [[nodiscard]] const class HowTo * GetHowTo () const { return m_HowTo.get (); }
  211. [[nodiscard]] const class Reserved * GetReserved () const { return m_Reserved.get (); }
  212. public:
  213. [[nodiscard]] const class ErrorCode * Cause () const
  214. {
  215. if (m_Root)
  216. return m_Root.get ();
  217. else
  218. return this;
  219. }
  220. public:
  221. [[nodiscard]] string_type ToString () const
  222. {
  223. string_type rc;
  224. rc.reserve (1024);
  225. rc.append ("Code="sv).append (std::to_string (m_Value))
  226. .append (", Message=["sv).append (What ()).append ("]"sv)
  227. .append (", Category=["sv).append (m_Category->Name ()).append ("]"sv);
  228. if (m_Where) rc.append (", Where=["sv).append (m_Where->Name ()).append (", "sv).append (m_Where->Detail ()).append ("]"sv);
  229. else rc.append (", Where=[?>"sv);
  230. if (m_Domain) rc.append (", Domain=["sv).append (m_Domain->Name ()).append (", "sv).append (m_Domain->Detail ()).append ("]"sv);
  231. else rc.append (", Domain=[?>"sv);
  232. if (m_HowTo) rc.append (", HowTo=["sv).append (m_HowTo->Name ()).append (", "sv).append (m_HowTo->Detail ()).append ("]"sv);
  233. else rc.append (", HowTo=[?>"sv);
  234. if (m_Reserved) rc.append (", Reserved=["sv).append (m_Reserved->Name ()).append (", "sv).append (m_Reserved->Detail ()).append ("]"sv);
  235. else rc.append (", Reserved=[?>"sv);
  236. return rc;
  237. }
  238. public:
  239. ErrorCode & Set (std::unique_ptr <class Category > && _val) { m_Category = std::move (_val); assert (m_Category); return *this; }
  240. ErrorCode & Set (std::unique_ptr <class Where > && _val) { m_Where = std::move (_val); return *this; }
  241. ErrorCode & Set (std::unique_ptr <class Domain > && _val) { m_Domain = std::move (_val); return *this; }
  242. ErrorCode & Set (std::unique_ptr <class HowTo > && _val) { m_HowTo = std::move (_val); return *this; }
  243. ErrorCode & Set (std::unique_ptr <class Reserved > && _val) { m_Reserved = std::move (_val); return *this; }
  244. void Set (class ErrorCode && _val) { m_Root.reset (new ErrorCode (std::move (_val))); }
  245. private:
  246. void MoveAssign (ErrorCode && from)
  247. {
  248. this->m_Value = from.m_Value;
  249. this->m_Category = std::move (from.m_Category);
  250. this->m_Where = std::move (from.m_Where);
  251. this->m_Domain = std::move (from.m_Domain);
  252. this->m_HowTo = std::move (from.m_HowTo);
  253. this->m_Reserved = std::move (from.m_Reserved);
  254. this->m_Root = std::move (from.m_Root);
  255. assert (m_Category);
  256. }
  257. private:
  258. error_code_type m_Value;
  259. std::unique_ptr <class Category> m_Category;
  260. std::unique_ptr <class Where > m_Where;
  261. std::unique_ptr <class Domain> m_Domain;
  262. std::unique_ptr <class HowTo > m_HowTo;
  263. std::unique_ptr <class Reserved> m_Reserved;
  264. std::unique_ptr <class ErrorCode> m_Root;
  265. };
  266. }
  267. //-----------------------------------------------------------------------------
  268. // 通用错误/组件内部错误, 比如参数错误, 检测到 NULL 参数等
  269. // 枚举量来自 2019\Community\VC\Tools\MSVC\14.29.30133\include\xerrc.h
  270. //-----------------------------------------------------------------------------
  271. namespace ECOM::Utility::Error::Generic
  272. {
  273. enum class enError
  274. {
  275. enOK = 0,
  276. enNoError = 0,
  277. enUnknown = 1 , // 未知错误
  278. create_file_failed,
  279. read_file_failed,
  280. write_file_failed,
  281. device_or_resource_busy, // EBUSY
  282. device_or_resource_power_off, //
  283. device_or_resource_offline, //
  284. invalid_argument, // EINVAL
  285. invalid_object, // EINVAL
  286. io_error, // EIO
  287. no_buffer_space, // ENOBUFS
  288. permission_denied, // EACCES
  289. no_message, // ENOMS
  290. no_such_device_or_address, // ENXIO
  291. no_such_device, // ENODEV
  292. no_such_file_or_directory, // ENOENT
  293. no_enough_memory, // ENOMEM
  294. operation_not_permitted, // EPERM
  295. operation_not_supported, // EOPNOTSUPP
  296. resource_unavailable_try_again, // EAGAIN
  297. result_out_of_range, // ERANGE
  298. timed_out, // ETIMEDOUT
  299. value_too_large, // EOVERFLOW
  300. value_too_small, //
  301. lock_failed, //
  302. bad_protocol, //
  303. processing_failure, //
  304. network_error, //
  305. database_error, //
  306. exception, //
  307. };
  308. //---------------------------
  309. // Category
  310. //---------------------------
  311. class Category : public ECOM::Utility::Error::Category
  312. {
  313. using base = ECOM::Utility::Error::Category;
  314. static constexpr auto _DefName { "Error.Catelog.Generic"sv };
  315. static constexpr auto _DefHash = ECOM::Utility::Hash (_DefName);
  316. public:
  317. using base::base;
  318. [[nodiscard]] virtual size_t Hash () const override { return _DefHash; }
  319. [[nodiscard]] virtual view_type Name () const override { return _DefName; }
  320. [[nodiscard]] virtual view_type Message () const override
  321. {
  322. if (m_Message.empty ())
  323. const_cast <view_type &> (m_Message) = ToMessage ();
  324. return m_Message;
  325. }
  326. public:
  327. static bool Is (const ECOM::Utility::Error::Category & with)
  328. {
  329. return (with.Hash () == _DefHash);
  330. }
  331. protected:
  332. view_type m_Message;
  333. protected:
  334. [[nodiscard]] view_type ToMessage () const
  335. {
  336. auto ec = static_cast <enError> (m_Value);
  337. switch (ec)
  338. {
  339. case enError::enUnknown : return "Unknown"sv;
  340. case enError::create_file_failed : return "Create file failed"sv;
  341. case enError::read_file_failed : return "Read file failed"sv;
  342. case enError::write_file_failed : return "Write file failed"sv;
  343. case enError::device_or_resource_busy : return "Device or resource busy"sv;
  344. case enError::device_or_resource_power_off : return "Device or resource power off"sv;
  345. case enError::device_or_resource_offline : return "Device or resource offline"sv;
  346. case enError::invalid_argument : return "Invalid argument"sv;
  347. case enError::invalid_object : return "Invalid object"sv;
  348. case enError::io_error : return "IO error"sv;
  349. case enError::no_buffer_space : return "No buffer space"sv;
  350. case enError::permission_denied : return "Permission denied"sv;
  351. case enError::no_message : return "No message"sv;
  352. case enError::no_such_device_or_address : return "No such device or address"sv;
  353. case enError::no_such_device : return "No such device"sv;
  354. case enError::no_such_file_or_directory : return "No such file or directory"sv;
  355. case enError::no_enough_memory : return "No enough memory"sv;
  356. case enError::operation_not_permitted : return "Operation not permitted"sv;
  357. case enError::operation_not_supported : return "Operation not supported"sv;
  358. case enError::resource_unavailable_try_again : return "Resource unavailable, try again"sv;
  359. case enError::result_out_of_range : return "Result out of range"sv;
  360. case enError::timed_out : return "Time out"sv;
  361. case enError::value_too_large : return "Value too large"sv;
  362. case enError::value_too_small : return "Value too small"sv;
  363. case enError::processing_failure : return "Processing failure"sv;
  364. case enError::lock_failed : return "Lock failed"sv;
  365. case enError::bad_protocol : return "Bad protocol"sv;
  366. case enError::network_error : return "Network error"sv;
  367. case enError::database_error : return "Database error"sv;
  368. case enError::exception : return "Exception"sv;
  369. default : return "Undefined generic error"sv;
  370. }
  371. }
  372. };
  373. //---------------------------
  374. // ErrorCategory_With
  375. //---------------------------
  376. class ErrorCategory_With : public Category
  377. {
  378. using base = Category;
  379. static constexpr auto _DefName { "Error.Catelog.Generic.With"sv };
  380. static constexpr auto _DefHash = ECOM::Utility::Hash (_DefName);
  381. public:
  382. ErrorCategory_With (error_code_type ec, view_type msg) : base (ec), m_With { msg }
  383. {
  384. }
  385. [[nodiscard]] virtual size_t Hash () const override { return _DefHash; }
  386. [[nodiscard]] virtual view_type Name () const override { return _DefName; }
  387. [[nodiscard]] virtual view_type Message () const override
  388. {
  389. if (m_Detail.empty ())
  390. {
  391. auto & dt = const_cast <string_type &> (m_Detail);
  392. dt.append (base::Message ()).append (", with=["sv).append (m_With).append ("]"sv);
  393. }
  394. return m_Detail;
  395. }
  396. private:
  397. const string_type m_With;
  398. const string_type m_Detail;
  399. };
  400. inline ErrorCode Make (error_code_type ec)
  401. {
  402. return { ec, std::make_unique <Category> (ec) };
  403. }
  404. inline ErrorCode Make (enError ec)
  405. {
  406. return { static_cast <error_code_type> (ec), std::make_unique <Category> (static_cast <error_code_type> (ec)) };
  407. }
  408. }
  409. //-----------------------------------------------------------------------------
  410. // Windows API 错误
  411. //-----------------------------------------------------------------------------
  412. namespace ECOM::Utility::Error::OS::Windows
  413. {
  414. //---------------------------
  415. // Category
  416. //---------------------------
  417. class Category : public ECOM::Utility::Error::Category
  418. {
  419. using base = ECOM::Utility::Error::Category;
  420. static constexpr auto _DefName { "Error.Catelog.OS.Windows"sv };
  421. static constexpr auto _DefHash = ECOM::Utility::Hash (_DefName);
  422. public:
  423. Category (error_code_type ec) : base (ec) {}
  424. [[nodiscard]] virtual size_t Hash () const override { return _DefHash; }
  425. [[nodiscard]] virtual view_type Name () const override { return _DefName; }
  426. [[nodiscard]] virtual view_type Message () const override
  427. {
  428. if (m_Message.empty ())
  429. const_cast <string_type&> (m_Message) = ErrorCodeToString (m_Value);
  430. return m_Message;
  431. }
  432. public:
  433. static bool Is (const ECOM::Utility::Error::Category & with)
  434. {
  435. return (with.Hash () == _DefHash);
  436. }
  437. private:
  438. static std::string ErrorCodeToString (DWORD errorCode)
  439. {
  440. constexpr int nPreAlloc = 4096;
  441. OBlockBuffer OMB;
  442. auto pc = reinterpret_cast <char *> (OMB.GetBufferSetCount (nPreAlloc + 2));
  443. if (errorCode == 0) errorCode = GetLastError ();
  444. auto szmsg = ::FormatMessageA (FORMAT_MESSAGE_FROM_SYSTEM,
  445. NULL,
  446. errorCode, // GetLastError (),
  447. MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
  448. (LPSTR)pc,
  449. nPreAlloc,
  450. NULL);
  451. std::string rc (pc, szmsg - 2); // -2 是为了去掉尾部的 \r\n
  452. return rc;
  453. }
  454. private:
  455. string_type m_Message;
  456. };
  457. inline ErrorCode Make (error_code_type ec)
  458. {
  459. return { ec, std::make_unique <Category> (ec) };
  460. }
  461. }
  462. //-----------------------------------------------------------------------------
  463. // ErrorCode
  464. //-----------------------------------------------------------------------------
  465. //using eiResult = ECOM::Utility::Either <int, ECOM::Utility::Error::ErrorCode>;
  466. //constexpr auto eiSuccess = ECOM::Utility::left <int> (1);