mssf_core/error/
mod.rs

1// ------------------------------------------------------------
2// Copyright (c) Microsoft Corporation.  All rights reserved.
3// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
4// ------------------------------------------------------------
5
6use crate::HRESULT;
7use mssf_com::FabricTypes::FABRIC_ERROR_CODE;
8
9mod errorcode;
10pub use errorcode::ErrorCode;
11
12/// Result containing mssf Error.
13pub type Result<T> = core::result::Result<T, Error>;
14
15/// Make passing error code to SF api easier.
16/// Provides conversion from windows errors or fabric error code
17/// to windows_core::Error.
18/// All safe code uses this Error, and bridge and proxy code needs to
19/// convert this Error into/from WinError.
20#[derive(Clone, PartialEq)]
21pub struct Error(pub super::HRESULT);
22
23impl Error {
24    pub fn new(code: HRESULT) -> Self {
25        Self(code)
26    }
27
28    /// Convert to fabric error code if possible.
29    pub fn try_as_fabric_error_code(&self) -> std::result::Result<ErrorCode, &str> {
30        ErrorCode::try_from(FABRIC_ERROR_CODE(self.0.0))
31    }
32}
33
34impl From<HRESULT> for Error {
35    fn from(value: HRESULT) -> Self {
36        Self::new(value)
37    }
38}
39
40impl From<FABRIC_ERROR_CODE> for Error {
41    fn from(value: FABRIC_ERROR_CODE) -> Self {
42        Self::new(HRESULT(value.0))
43    }
44}
45
46impl From<Error> for super::WinError {
47    fn from(val: Error) -> Self {
48        super::WinError::from_hresult(val.0)
49    }
50}
51
52impl From<Error> for HRESULT {
53    fn from(value: Error) -> Self {
54        value.0
55    }
56}
57
58impl From<crate::WinError> for Error {
59    fn from(error: crate::WinError) -> Self {
60        Self(error.into())
61    }
62}
63
64impl core::fmt::Debug for Error {
65    fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
66        let mut debug = fmt.debug_struct("FabricError");
67        let str_code = ErrorCode::try_from(FABRIC_ERROR_CODE(self.0.0)).ok();
68        debug.field("code", &self.0.0);
69        match str_code {
70            Some(c) => debug.field("message", &c),
71            None => debug.field("message", &"unknown fabric error"),
72        };
73
74        debug.finish()
75    }
76}
77
78impl core::fmt::Display for Error {
79    fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
80        let str_code = ErrorCode::try_from(FABRIC_ERROR_CODE(self.0.0)).ok();
81        match str_code {
82            Some(c) => core::write!(fmt, "{} ({})", c, self.0.0),
83            None => core::write!(fmt, "{}", self.0.0),
84        }
85    }
86}
87
88impl std::error::Error for Error {}
89
90// conversion from common error types in std
91
92impl From<std::io::Error> for Error {
93    fn from(value: std::io::Error) -> Self {
94        // Use the windows implementation to convert
95        crate::WinError::from(value).into()
96    }
97}
98
99impl From<Error> for std::io::Error {
100    fn from(value: Error) -> Self {
101        // Use windows implementation
102        Self::from(crate::WinError::from(value))
103    }
104}
105
106impl From<core::num::TryFromIntError> for Error {
107    fn from(value: core::num::TryFromIntError) -> Self {
108        // Use windows implementation
109        crate::WinError::from(value).into()
110    }
111}
112
113#[cfg(test)]
114mod test {
115
116    use super::{Error, ErrorCode};
117    use crate::HRESULT;
118    use mssf_com::FabricTypes::FABRIC_E_CODE_PACKAGE_NOT_FOUND;
119    use windows_core::Win32::Foundation::{E_ACCESSDENIED, E_POINTER};
120
121    #[test]
122    fn test_fabric_error() {
123        let fe = Error::from(FABRIC_E_CODE_PACKAGE_NOT_FOUND);
124        // check debug string
125        assert_eq!(
126            format!("{fe:?}"),
127            "FabricError { code: -2147017733, message: FABRIC_E_CODE_PACKAGE_NOT_FOUND }"
128        );
129        // check display string
130        assert_eq!(
131            format!("{fe}"),
132            "FABRIC_E_CODE_PACKAGE_NOT_FOUND (-2147017733)"
133        );
134        let e = crate::WinError::from(fe.clone());
135        assert_eq!(e.code(), fe.into());
136        let ec = Error::from(e)
137            .try_as_fabric_error_code()
138            .expect("unknown code");
139        assert_eq!(ec, ErrorCode::FABRIC_E_CODE_PACKAGE_NOT_FOUND);
140    }
141
142    #[test]
143    fn test_hresult_error() {
144        let err1: HRESULT = Error::from(ErrorCode::E_ACCESSDENIED).into();
145        let err2 = E_ACCESSDENIED;
146        assert_eq!(err1, err2);
147
148        let e: crate::WinError = ErrorCode::E_POINTER.into();
149        assert_eq!(e, E_POINTER.into());
150
151        const SEC_E_INTERNAL_ERROR: crate::HRESULT = crate::HRESULT(0x80090304_u32 as _);
152        // use an error that is not fabric error
153        let fe = Error::from(SEC_E_INTERNAL_ERROR);
154        // check display string
155        assert_eq!(format!("{fe}"), "-2146893052");
156        assert_eq!(
157            format!("{fe:?}"),
158            "FabricError { code: -2146893052, message: \"unknown fabric error\" }"
159        );
160    }
161}