use static_assertions;
use thiserror::Error;
pub type Result<T> = std::result::Result<T, SaferRingError>;
#[derive(Debug, Error)]
pub enum SaferRingError {
#[error("Buffer still in flight")]
BufferInFlight,
#[error("Operation not completed")]
OperationPending,
#[error("Ring has {count} operations in flight")]
OperationsInFlight {
count: usize,
},
#[error("Invalid operation state transition")]
InvalidStateTransition,
#[error("Resource not registered")]
NotRegistered,
#[error("Buffer pool is empty")]
PoolEmpty,
#[error("Buffer pool mutex is poisoned")]
PoolPoisoned,
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
}
static_assertions::assert_impl_all!(SaferRingError: Send, Sync);
#[cfg(test)]
mod tests {
use super::*;
use std::error::Error;
use std::io::{Error as IoError, ErrorKind};
mod error_messages {
use super::*;
#[test]
fn buffer_in_flight() {
let error = SaferRingError::BufferInFlight;
assert_eq!(error.to_string(), "Buffer still in flight");
}
#[test]
fn operation_pending() {
let error = SaferRingError::OperationPending;
assert_eq!(error.to_string(), "Operation not completed");
}
#[test]
fn operations_in_flight() {
let error = SaferRingError::OperationsInFlight { count: 5 };
assert_eq!(error.to_string(), "Ring has 5 operations in flight");
}
#[test]
fn invalid_state_transition() {
let error = SaferRingError::InvalidStateTransition;
assert_eq!(error.to_string(), "Invalid operation state transition");
}
#[test]
fn not_registered() {
let error = SaferRingError::NotRegistered;
assert_eq!(error.to_string(), "Resource not registered");
}
#[test]
fn pool_empty() {
let error = SaferRingError::PoolEmpty;
assert_eq!(error.to_string(), "Buffer pool is empty");
}
}
mod error_conversion {
use super::*;
#[test]
fn io_error_conversion() {
let io_error = IoError::new(ErrorKind::PermissionDenied, "Access denied");
let safer_ring_error = SaferRingError::from(io_error);
let SaferRingError::Io(ref e) = safer_ring_error else {
panic!("Expected Io error variant");
};
assert_eq!(e.kind(), ErrorKind::PermissionDenied);
assert!(e.to_string().contains("Access denied"));
assert!(safer_ring_error.to_string().contains("I/O error"));
}
#[cfg(target_os = "linux")]
#[test]
#[ignore] fn io_uring_error_conversion() {
}
}
mod error_traits {
use super::*;
#[test]
fn implements_error_trait() {
let error = SaferRingError::BufferInFlight;
let _: &dyn std::error::Error = &error;
assert!(error.source().is_none());
}
#[test]
fn preserves_error_source() {
let io_error = IoError::new(ErrorKind::NotFound, "File not found");
let safer_ring_error = SaferRingError::from(io_error);
assert!(safer_ring_error.source().is_some());
let source = safer_ring_error.source().unwrap();
let io_err = source.downcast_ref::<IoError>().unwrap();
assert_eq!(io_err.kind(), ErrorKind::NotFound);
}
#[test]
fn debug_formatting() {
let error = SaferRingError::OperationsInFlight { count: 3 };
let debug_str = format!("{error:?}");
assert!(debug_str.contains("OperationsInFlight"));
assert!(debug_str.contains("count: 3"));
}
}
mod result_alias {
use super::*;
#[test]
fn success_case() {
fn returns_success() -> Result<i32> {
Ok(42)
}
assert_eq!(returns_success().unwrap(), 42);
}
#[test]
fn error_case() {
fn returns_error() -> Result<i32> {
Err(SaferRingError::BufferInFlight)
}
assert!(returns_error().is_err());
match returns_error() {
Err(SaferRingError::BufferInFlight) => {}
_ => panic!("Expected BufferInFlight error"),
}
}
}
}