Skip to main content

rs_teststand_sys/
error.rs

1//! Errors surfaced by the COM interop layer.
2
3use std::fmt;
4
5/// A failure originating in the COM dispatch layer.
6///
7/// This is the low-level error type. The public `rs-teststand` crate maps it
8/// onto the public crate's `Error` (HRESULT → named variant).
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub enum ComError {
11    /// A COM call returned a failing `HRESULT`.
12    Hresult {
13        /// The 32-bit `HRESULT` code (for `DISP_E_EXCEPTION` this is the
14        /// underlying `EXCEPINFO.scode`, i.e. the real engine error).
15        code: i32,
16        /// Which operation failed, for diagnostics.
17        context: &'static str,
18        /// The dispatch id that was being invoked, or `0` when the failure
19        /// happened outside a member call (apartment or class creation).
20        ///
21        /// Without this a bare engine code says nothing about *which* member
22        /// refused, which is the first question when one does.
23        dispid: i32,
24    },
25    /// A returned VARIANT did not hold the type the caller expected.
26    UnexpectedType {
27        /// The type the wrapper asked for.
28        expected: &'static str,
29        /// The type actually returned.
30        actual: &'static str,
31    },
32}
33
34impl ComError {
35    /// Builds a [`ComError::Hresult`] for a failure inside a member call.
36    #[must_use]
37    pub const fn member(code: i32, context: &'static str, dispid: i32) -> Self {
38        Self::Hresult {
39            code,
40            context,
41            dispid,
42        }
43    }
44
45    /// Builds an [`ComError::Hresult`] from a raw code and a static context.
46    #[must_use]
47    pub const fn hresult(code: i32, context: &'static str) -> Self {
48        Self::Hresult {
49            code,
50            context,
51            dispid: 0,
52        }
53    }
54}
55
56impl fmt::Display for ComError {
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        match self {
59            Self::Hresult {
60                code,
61                context,
62                dispid,
63            } => {
64                if *dispid == 0 {
65                    write!(f, "COM call {context} failed with HRESULT {code:#010x}")
66                } else {
67                    write!(
68                        f,
69                        "COM call {context} on DISPID {dispid:#x} failed with HRESULT {code:#010x}"
70                    )
71                }
72            }
73            Self::UnexpectedType { expected, actual } => {
74                write!(f, "expected VARIANT of type {expected}, got {actual}")
75            }
76        }
77    }
78}
79
80impl std::error::Error for ComError {}