use std::fmt;
pub type GpuResult<T> = Result<T, GpuError>;
#[derive(Debug, Clone)]
pub enum GpuError {
NotAvailable,
AdapterNotFound,
DeviceCreationFailed(String),
BufferError(String),
ShaderError(String),
PipelineError(String),
ComputeError(String),
InvalidBufferSize {
requested: u64,
max: u64,
},
AlignmentError {
offset: u64,
required: u64,
},
DeviceLost,
OutOfMemory,
UnsupportedOperation(String),
}
impl fmt::Display for GpuError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NotAvailable => write!(f, "WebGPU is not available on this platform"),
Self::AdapterNotFound => write!(f, "Failed to find a suitable GPU adapter"),
Self::DeviceCreationFailed(msg) => write!(f, "GPU device creation failed: {msg}"),
Self::BufferError(msg) => write!(f, "GPU buffer error: {msg}"),
Self::ShaderError(msg) => write!(f, "Shader compilation error: {msg}"),
Self::PipelineError(msg) => write!(f, "Pipeline creation error: {msg}"),
Self::ComputeError(msg) => write!(f, "Compute operation error: {msg}"),
Self::InvalidBufferSize { requested, max } => {
write!(
f,
"Invalid buffer size: requested {requested} bytes, max {max}"
)
}
Self::AlignmentError { offset, required } => {
write!(
f,
"Buffer alignment error: offset {offset} not aligned to {required}"
)
}
Self::DeviceLost => write!(f, "GPU device was lost"),
Self::OutOfMemory => write!(f, "GPU out of memory"),
Self::UnsupportedOperation(op) => write!(f, "Unsupported GPU operation: {op}"),
}
}
}
impl std::error::Error for GpuError {}
impl GpuError {
#[must_use]
pub fn buffer(msg: impl Into<String>) -> Self {
Self::BufferError(msg.into())
}
#[must_use]
pub fn shader(msg: impl Into<String>) -> Self {
Self::ShaderError(msg.into())
}
#[must_use]
pub fn pipeline(msg: impl Into<String>) -> Self {
Self::PipelineError(msg.into())
}
#[must_use]
pub fn compute(msg: impl Into<String>) -> Self {
Self::ComputeError(msg.into())
}
#[must_use]
pub fn device(msg: impl Into<String>) -> Self {
Self::DeviceCreationFailed(msg.into())
}
#[must_use]
pub fn is_recoverable(&self) -> bool {
!matches!(
self,
Self::NotAvailable | Self::DeviceLost | Self::OutOfMemory
)
}
#[must_use]
pub fn is_unavailable(&self) -> bool {
matches!(self, Self::NotAvailable | Self::AdapterNotFound)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
assert!(GpuError::NotAvailable.to_string().contains("not available"));
assert!(GpuError::AdapterNotFound.to_string().contains("adapter"));
assert!(GpuError::DeviceLost.to_string().contains("lost"));
assert!(GpuError::OutOfMemory.to_string().contains("memory"));
}
#[test]
fn test_error_constructors() {
let err = GpuError::buffer("test");
assert!(matches!(err, GpuError::BufferError(_)));
let err = GpuError::shader("test");
assert!(matches!(err, GpuError::ShaderError(_)));
let err = GpuError::pipeline("test");
assert!(matches!(err, GpuError::PipelineError(_)));
let err = GpuError::compute("test");
assert!(matches!(err, GpuError::ComputeError(_)));
let err = GpuError::device("test");
assert!(matches!(err, GpuError::DeviceCreationFailed(_)));
}
#[test]
fn test_error_is_recoverable() {
assert!(GpuError::BufferError("test".into()).is_recoverable());
assert!(GpuError::ShaderError("test".into()).is_recoverable());
assert!(!GpuError::NotAvailable.is_recoverable());
assert!(!GpuError::DeviceLost.is_recoverable());
assert!(!GpuError::OutOfMemory.is_recoverable());
}
#[test]
fn test_error_is_unavailable() {
assert!(GpuError::NotAvailable.is_unavailable());
assert!(GpuError::AdapterNotFound.is_unavailable());
assert!(!GpuError::DeviceLost.is_unavailable());
assert!(!GpuError::BufferError("test".into()).is_unavailable());
}
#[test]
fn test_invalid_buffer_size_display() {
let err = GpuError::InvalidBufferSize {
requested: 1000,
max: 500,
};
let msg = err.to_string();
assert!(msg.contains("1000"));
assert!(msg.contains("500"));
}
#[test]
fn test_alignment_error_display() {
let err = GpuError::AlignmentError {
offset: 100,
required: 256,
};
let msg = err.to_string();
assert!(msg.contains("100"));
assert!(msg.contains("256"));
}
#[test]
fn test_unsupported_operation() {
let err = GpuError::UnsupportedOperation("sparse matmul".into());
assert!(err.to_string().contains("sparse matmul"));
}
}