Skip to main content

oxiui_compute_wgpu/
error.rs

1//! Error types for GPU compute operations.
2//!
3//! [`ComputeError`] is the single error type returned by every fallible
4//! operation in this crate.  No external `thiserror` dependency is used;
5//! [`std::fmt::Display`] and [`std::error::Error`] are implemented manually to
6//! keep the crate dependency-minimal.
7
8// ── ComputeError ──────────────────────────────────────────────────────────────
9
10/// Errors that can occur while initialising or using a GPU compute context.
11#[derive(Debug)]
12pub enum ComputeError {
13    /// No GPU adapter was found on this host (headless CI, VM without GPU, …).
14    ///
15    /// Callers should treat this as a *graceful skip*, not a hard failure.
16    NoAdapter,
17
18    /// The adapter was found but the device/queue request failed.
19    ///
20    /// The contained string carries the underlying wgpu diagnostic.
21    DeviceRequest(String),
22
23    /// A GPU memory allocation failed or the device reported an out-of-memory
24    /// condition via an error scope.
25    OutOfMemory,
26
27    /// WGSL shader compilation failed.
28    ///
29    /// The contained string carries the diagnostic message including line and
30    /// column numbers as reported by `wgpu::CompilationInfo`.
31    ShaderCompilation(String),
32
33    /// A compute operation failed with structured context.
34    ///
35    /// `op` names the failing operation (e.g. `"read_back"`, `"dispatch"`);
36    /// `detail` carries the parameters or wgpu-level message.
37    Operation {
38        /// The name of the failing operation.
39        op: &'static str,
40        /// Human-readable detail: parameters, buffer labels, entry-point names, etc.
41        detail: String,
42    },
43}
44
45impl std::fmt::Display for ComputeError {
46    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47        match self {
48            Self::NoAdapter => write!(f, "no suitable GPU adapter found"),
49            Self::DeviceRequest(e) => write!(f, "device request failed: {e}"),
50            Self::OutOfMemory => write!(f, "GPU out of memory"),
51            Self::ShaderCompilation(msg) => write!(f, "WGSL compilation error: {msg}"),
52            Self::Operation { op, detail } => {
53                write!(f, "compute operation '{op}' failed: {detail}")
54            }
55        }
56    }
57}
58
59impl std::error::Error for ComputeError {}
60
61// ── Tests ─────────────────────────────────────────────────────────────────────
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn no_adapter_display() {
69        let e = ComputeError::NoAdapter;
70        let s = e.to_string();
71        assert!(s.contains("no suitable GPU adapter"), "got: {s}");
72    }
73
74    #[test]
75    fn device_request_display() {
76        let e = ComputeError::DeviceRequest("timeout".to_string());
77        let s = e.to_string();
78        assert!(s.contains("device request failed"), "got: {s}");
79        assert!(s.contains("timeout"), "got: {s}");
80    }
81
82    #[test]
83    fn display_out_of_memory() {
84        let e = ComputeError::OutOfMemory;
85        let s = e.to_string();
86        assert!(s.contains("out of memory"), "got: {s}");
87    }
88
89    #[test]
90    fn display_shader_compilation() {
91        let e = ComputeError::ShaderCompilation("line 3, col 5: unknown identifier".to_string());
92        let s = e.to_string();
93        assert!(s.contains("WGSL compilation error"), "got: {s}");
94        assert!(s.contains("unknown identifier"), "got: {s}");
95    }
96
97    #[test]
98    fn display_operation() {
99        let e = ComputeError::Operation {
100            op: "read_back",
101            detail: "buffer label=staging size=4096".to_string(),
102        };
103        let s = e.to_string();
104        assert!(s.contains("read_back"), "got: {s}");
105        assert!(s.contains("staging"), "got: {s}");
106    }
107
108    #[test]
109    fn compute_error_is_std_error() {
110        fn assert_error<E: std::error::Error>(_: &E) {}
111        assert_error(&ComputeError::NoAdapter);
112        assert_error(&ComputeError::DeviceRequest("x".to_string()));
113        assert_error(&ComputeError::OutOfMemory);
114        assert_error(&ComputeError::ShaderCompilation("msg".to_string()));
115        assert_error(&ComputeError::Operation {
116            op: "dispatch",
117            detail: "x".to_string(),
118        });
119    }
120}