Skip to main content

oxicuda_webgpu/
error.rs

1//! Error types for the oxicuda-webgpu backend.
2
3use oxicuda_backend::BackendError;
4
5/// Errors specific to the WebGPU backend.
6#[derive(Debug, thiserror::Error)]
7pub enum WebGpuError {
8    /// No compatible WebGPU adapter was found on this system.
9    #[error("no WebGPU adapter found")]
10    NoAdapter,
11
12    /// The device request to the adapter failed.
13    #[error("device request failed: {0}")]
14    DeviceRequest(String),
15
16    /// The GPU ran out of memory during buffer allocation.
17    #[error("out of device memory")]
18    OutOfMemory,
19
20    /// WGSL shader source failed to compile.
21    #[error("WGSL shader compilation failed: {0}")]
22    ShaderCompilation(String),
23
24    /// A compute pipeline could not be created.
25    #[error("pipeline creation failed: {0}")]
26    PipelineCreation(String),
27
28    /// The backend has not been initialized yet.
29    #[error("not initialized")]
30    NotInitialized,
31
32    /// The requested operation is not supported by this backend.
33    #[error("unsupported operation: {0}")]
34    Unsupported(String),
35
36    /// An invalid argument was passed to an operation.
37    #[error("invalid argument: {0}")]
38    InvalidArgument(String),
39
40    /// A buffer mapping operation failed.
41    #[error("buffer mapping failed: {0}")]
42    BufferMapping(String),
43
44    /// An async operation timed out waiting for the adapter.
45    #[error("adapter timeout")]
46    Timeout,
47}
48
49/// Convenience result alias for WebGPU operations.
50pub type WebGpuResult<T> = Result<T, WebGpuError>;
51
52impl From<WebGpuError> for BackendError {
53    fn from(e: WebGpuError) -> Self {
54        match e {
55            WebGpuError::NoAdapter => BackendError::DeviceError("no WebGPU adapter found".into()),
56            WebGpuError::DeviceRequest(msg) => {
57                BackendError::DeviceError(format!("device request failed: {msg}"))
58            }
59            WebGpuError::OutOfMemory => BackendError::OutOfMemory,
60            WebGpuError::ShaderCompilation(msg) => {
61                BackendError::DeviceError(format!("WGSL shader compilation failed: {msg}"))
62            }
63            WebGpuError::PipelineCreation(msg) => {
64                BackendError::DeviceError(format!("pipeline creation failed: {msg}"))
65            }
66            WebGpuError::NotInitialized => BackendError::NotInitialized,
67            WebGpuError::Unsupported(msg) => BackendError::Unsupported(msg),
68            WebGpuError::InvalidArgument(msg) => BackendError::InvalidArgument(msg),
69            WebGpuError::BufferMapping(msg) => {
70                BackendError::DeviceError(format!("buffer mapping failed: {msg}"))
71            }
72            WebGpuError::Timeout => BackendError::DeviceError("adapter timeout".into()),
73        }
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    #[test]
82    fn webgpu_error_display() {
83        assert_eq!(
84            WebGpuError::NoAdapter.to_string(),
85            "no WebGPU adapter found"
86        );
87        assert_eq!(
88            WebGpuError::DeviceRequest("oops".into()).to_string(),
89            "device request failed: oops"
90        );
91        assert_eq!(WebGpuError::OutOfMemory.to_string(), "out of device memory");
92        assert_eq!(
93            WebGpuError::ShaderCompilation("syntax error".into()).to_string(),
94            "WGSL shader compilation failed: syntax error"
95        );
96        assert_eq!(
97            WebGpuError::PipelineCreation("invalid layout".into()).to_string(),
98            "pipeline creation failed: invalid layout"
99        );
100        assert_eq!(WebGpuError::NotInitialized.to_string(), "not initialized");
101        assert_eq!(
102            WebGpuError::Unsupported("foo".into()).to_string(),
103            "unsupported operation: foo"
104        );
105        assert_eq!(
106            WebGpuError::InvalidArgument("bad arg".into()).to_string(),
107            "invalid argument: bad arg"
108        );
109        assert_eq!(
110            WebGpuError::BufferMapping("lock poisoned".into()).to_string(),
111            "buffer mapping failed: lock poisoned"
112        );
113        assert_eq!(WebGpuError::Timeout.to_string(), "adapter timeout");
114    }
115
116    #[test]
117    fn webgpu_error_from_backend_error() {
118        // Verify the From conversion produces the correct BackendError variants.
119        let e = BackendError::from(WebGpuError::OutOfMemory);
120        assert_eq!(e, BackendError::OutOfMemory);
121
122        let e = BackendError::from(WebGpuError::NotInitialized);
123        assert_eq!(e, BackendError::NotInitialized);
124
125        let e = BackendError::from(WebGpuError::Unsupported("bar".into()));
126        assert_eq!(e, BackendError::Unsupported("bar".into()));
127
128        let e = BackendError::from(WebGpuError::InvalidArgument("baz".into()));
129        assert_eq!(e, BackendError::InvalidArgument("baz".into()));
130
131        let e = BackendError::from(WebGpuError::NoAdapter);
132        assert!(matches!(e, BackendError::DeviceError(_)));
133
134        let e = BackendError::from(WebGpuError::DeviceRequest("x".into()));
135        assert!(matches!(e, BackendError::DeviceError(_)));
136
137        let e = BackendError::from(WebGpuError::BufferMapping("m".into()));
138        assert!(matches!(e, BackendError::DeviceError(_)));
139
140        let e = BackendError::from(WebGpuError::Timeout);
141        assert!(matches!(e, BackendError::DeviceError(_)));
142    }
143}