1use crate::HRESULT;
7use mssf_com::FabricTypes::FABRIC_ERROR_CODE;
8
9mod errorcode;
10pub use errorcode::ErrorCode;
11use windows_core::WString;
12
13pub type Result<T> = core::result::Result<T, Error>;
15
16#[derive(Clone, PartialEq)]
22pub struct Error {
23 code: super::HRESULT,
24 msg: Option<WString>,
25}
26
27impl Error {
28 pub fn new(code: HRESULT, msg: Option<WString>) -> Self {
29 Self { code, msg }
30 }
31
32 pub fn from_hresult(code: HRESULT) -> Self {
34 Self::new(code, None)
35 }
36
37 pub fn try_as_fabric_error_code(&self) -> std::result::Result<ErrorCode, &str> {
39 ErrorCode::try_from(FABRIC_ERROR_CODE(self.code.0))
40 }
41
42 pub fn from_thread(code: HRESULT) -> Self {
44 let msg = get_last_error_message();
45 Self::new(code, msg)
46 }
47
48 pub fn code(&self) -> HRESULT {
49 self.code
50 }
51}
52
53impl From<HRESULT> for Error {
54 fn from(value: HRESULT) -> Self {
55 Self::from_hresult(value)
56 }
57}
58
59impl From<FABRIC_ERROR_CODE> for Error {
60 fn from(value: FABRIC_ERROR_CODE) -> Self {
61 Self::from_hresult(HRESULT(value.0))
62 }
63}
64
65impl From<Error> for super::WinError {
66 fn from(val: Error) -> Self {
67 super::WinError::from_hresult(val.code)
68 }
69}
70
71impl From<Error> for HRESULT {
72 fn from(value: Error) -> Self {
73 value.code
74 }
75}
76
77impl From<crate::WinError> for Error {
78 fn from(error: crate::WinError) -> Self {
79 Self::from_hresult(error.code())
80 }
81}
82
83impl core::fmt::Debug for Error {
84 fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
85 let mut debug = fmt.debug_struct("FabricError");
86 let code_str = ErrorCode::try_from(FABRIC_ERROR_CODE(self.code.0)).ok();
87 debug.field("code", &self.code.0);
88 match code_str {
89 Some(c) => debug.field("code_str", &c),
90 None => debug.field("code_str", &"unknown fabric error"),
91 };
92 match &self.msg {
93 Some(m) => debug.field("message", m),
94 None => debug.field("message", &"none"),
95 };
96 debug.finish()
97 }
98}
99
100impl core::fmt::Display for Error {
101 fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
102 let str_code = ErrorCode::try_from(FABRIC_ERROR_CODE(self.code.0)).ok();
103 match str_code {
104 Some(c) => core::write!(fmt, "{} ({})", c, self.code.0),
105 None => core::write!(fmt, "{}", self.code.0),
106 }?;
107 match &self.msg {
108 Some(m) => core::write!(fmt, ": {m}"),
109 None => Ok(()),
110 }
111 }
112}
113
114impl std::error::Error for Error {}
115
116impl From<std::io::Error> for Error {
119 fn from(value: std::io::Error) -> Self {
120 crate::WinError::from(value).into()
122 }
123}
124
125impl From<Error> for std::io::Error {
126 fn from(value: Error) -> Self {
127 Self::from(crate::WinError::from(value))
129 }
130}
131
132impl From<core::num::TryFromIntError> for Error {
133 fn from(value: core::num::TryFromIntError) -> Self {
134 crate::WinError::from(value).into()
136 }
137}
138
139fn get_last_error_message() -> Option<WString> {
142 let msg = crate::api::API_TABLE.fabric_get_last_error_message().ok()?;
146 let smsg = crate::strings::StringResult::from(&msg).into_inner();
149 #[allow(clippy::len_zero)]
151 match smsg.len() == 0 {
152 true => None,
153 false => Some(smsg),
154 }
155}
156
157#[cfg(test)]
158mod test {
159
160 use super::{Error, ErrorCode};
161 use crate::HRESULT;
162 use mssf_com::FabricTypes::FABRIC_E_CODE_PACKAGE_NOT_FOUND;
163 use windows_core::Win32::Foundation::{E_ACCESSDENIED, E_POINTER};
164
165 #[test]
166 fn test_fabric_error() {
167 let fe = Error::from(FABRIC_E_CODE_PACKAGE_NOT_FOUND);
168 assert_eq!(
170 format!("{fe:?}"),
171 "FabricError { code: -2147017733, code_str: FABRIC_E_CODE_PACKAGE_NOT_FOUND, message: \"none\" }"
172 );
173 assert_eq!(
175 format!("{fe}"),
176 "FABRIC_E_CODE_PACKAGE_NOT_FOUND (-2147017733)"
177 );
178 let e = crate::WinError::from(fe.clone());
179 assert_eq!(e.code(), fe.into());
180 let ec = Error::from(e)
181 .try_as_fabric_error_code()
182 .expect("unknown code");
183 assert_eq!(ec, ErrorCode::FABRIC_E_CODE_PACKAGE_NOT_FOUND);
184 }
185
186 #[test]
187 fn test_hresult_error() {
188 let err1: HRESULT = Error::from(ErrorCode::E_ACCESSDENIED).into();
189 let err2 = E_ACCESSDENIED;
190 assert_eq!(err1, err2);
191
192 let e: crate::WinError = ErrorCode::E_POINTER.into();
193 assert_eq!(e, E_POINTER.into());
194
195 const SEC_E_INTERNAL_ERROR: crate::HRESULT = crate::HRESULT(0x80090304_u32 as _);
196 let fe = Error::from(SEC_E_INTERNAL_ERROR);
198 assert_eq!(format!("{fe}"), "-2146893052");
200 assert_eq!(
201 format!("{fe:?}"),
202 "FabricError { code: -2146893052, code_str: \"unknown fabric error\", message: \"none\" }"
203 );
204 }
205
206 #[test]
207 fn test_error_from_thread() {
208 let err = crate::runtime::create_com_runtime().unwrap_err();
211 let err_thread = Error::from_thread(err.code());
212 match err_thread.try_as_fabric_error_code().unwrap() {
213 ErrorCode::FABRIC_INTERNAL_E_CANNOT_CONNECT => {
215 assert_eq!(
216 format!("{err_thread}"),
217 "FABRIC_INTERNAL_E_CANNOT_CONNECT (-2147017536)"
218 );
219 }
220 ErrorCode::FABRIC_E_CONNECTION_DENIED => {
222 assert_eq!(
223 format!("{err_thread}"),
224 "FABRIC_E_CONNECTION_DENIED (-2147017661)"
225 );
226 }
227 c => panic!("unexpected error code {c}"),
228 }
229 }
230}