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 {}