Skip to main content

cuest_cudarc/
error.rs

1//! Error types for cuEST operations.
2
3use cudarc::driver::DriverError;
4use cuest_ffi::status::{status_to_str, CuestStatus};
5use std::fmt;
6
7/// Error type for all cuEST wrapper operations.
8///
9/// This enum is `#[non_exhaustive]`: new variants may be added in patch
10/// releases, so downstream matches must include a wildcard (`_`) arm.
11#[derive(Debug)]
12#[non_exhaustive]
13pub enum CuestError {
14    /// A cuEST C API call returned a non-success status code.
15    ///
16    /// `context` names the failing call (or wrapper-level operation).
17    Status {
18        /// The status code returned by cuEST.
19        status: CuestStatus,
20        /// Name of the failing call, e.g. `"cuestAOBasisCreate"`.
21        context: &'static str,
22    },
23    /// A CUDA operation performed through cudarc failed.
24    Cuda(DriverError),
25    /// An error originating in this wrapper: invalid arguments (sizes,
26    /// mismatched streams, unknown enum values), parse failures, etc.
27    Rust(String),
28    /// The loaded cuEST library version does not match the C API these
29    /// bindings were generated from.
30    ///
31    /// `needed` is the (major, minor, patch) version of the bindings, `found`
32    /// the version reported by the loaded library.
33    UnsupportedVersion { needed: (u32, u32, u32), found: (u32, u32, u32) },
34}
35
36impl fmt::Display for CuestError {
37    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38        match self {
39            CuestError::Status { status, context } => {
40                write!(
41                    f,
42                    "{context} failed: {} (cuEST status {})",
43                    status_to_str(*status),
44                    status.0
45                )
46            },
47            CuestError::Cuda(err) => write!(f, "cudarc error: {err}"),
48            CuestError::Rust(msg) => write!(f, "{msg}"),
49            CuestError::UnsupportedVersion { needed, found } => write!(
50                f,
51                "these bindings require cuEST {}.{}.{}, but the loaded library is {}.{}.{}",
52                needed.0, needed.1, needed.2, found.0, found.1, found.2
53            ),
54        }
55    }
56}
57
58impl std::error::Error for CuestError {
59    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
60        match self {
61            CuestError::Cuda(err) => Some(err),
62            _ => None,
63        }
64    }
65}
66
67impl From<DriverError> for CuestError {
68    fn from(err: DriverError) -> Self {
69        CuestError::Cuda(err)
70    }
71}
72
73/// Convert a cuEST status code into `Result`, attaching the call name.
74pub(crate) fn status_check(status: CuestStatus, context: &'static str) -> Result<(), CuestError> {
75    if status == cuest_ffi::ffi::CUEST_STATUS_SUCCESS {
76        Ok(())
77    } else {
78        Err(CuestError::Status { status, context })
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85    use cuest_ffi::ffi::{CUEST_STATUS_INVALID_ARGUMENT, CUEST_STATUS_SUCCESS};
86
87    #[test]
88    fn cpu_status_check() {
89        assert!(status_check(CUEST_STATUS_SUCCESS, "f").is_ok());
90        let err = status_check(CUEST_STATUS_INVALID_ARGUMENT, "cuestF").unwrap_err();
91        match err {
92            CuestError::Status { status, context } => {
93                assert_eq!(status, CUEST_STATUS_INVALID_ARGUMENT);
94                assert_eq!(context, "cuestF");
95            },
96            _ => panic!("unexpected variant"),
97        }
98    }
99
100    #[test]
101    fn cpu_display() {
102        let err = CuestError::Status {
103            status: CUEST_STATUS_INVALID_ARGUMENT,
104            context: "cuestAOBasisCreate",
105        };
106        assert_eq!(err.to_string(), "cuestAOBasisCreate failed: invalid argument (cuEST status 3)");
107        let err = CuestError::UnsupportedVersion { needed: (0, 2, 2), found: (0, 3, 0) };
108        assert_eq!(
109            err.to_string(),
110            "these bindings require cuEST 0.2.2, but the loaded library is 0.3.0"
111        );
112        assert!(std::error::Error::source(&err).is_none());
113    }
114}