pub type Result<T, E = Error> = std::result::Result<T, E>;
#[derive(Debug)]
pub enum Error {
IoError(std::io::Error),
#[cfg(unix)]
NixError(nix::Error),
NotImplemented(String),
InvalidSize(usize),
ShapeMismatch(String),
#[cfg(target_os = "linux")]
UnknownDeviceType(u64, u64),
#[cfg(target_os = "linux")]
UnknownBufferType(u32),
InvalidMemoryType(String),
PboDisconnected,
PboMapped,
#[cfg(feature = "ndarray")]
NdArrayError(ndarray::ShapeError),
InvalidShape(String),
InvalidArgument(String),
InvalidOperation(String),
PartialWriteRequiresReadWrite(String),
QuantizationInvalid {
field: &'static str,
expected: String,
got: String,
},
InsufficientCapacity {
needed: usize,
capacity: usize,
},
RegionOutOfBounds {
region: crate::Region,
bounds: (usize, usize),
},
BatchIndexOutOfBounds {
index: usize,
batch: usize,
},
}
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Self {
Error::IoError(err)
}
}
#[cfg(unix)]
impl From<nix::Error> for Error {
fn from(err: nix::Error) -> Self {
Error::NixError(err)
}
}
#[cfg(feature = "ndarray")]
impl From<ndarray::ShapeError> for Error {
fn from(err: ndarray::ShapeError) -> Self {
Error::NdArrayError(err)
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::InsufficientCapacity { needed, capacity } => write!(
f,
"insufficient tensor capacity: need {needed} bytes, have {capacity}"
),
Error::RegionOutOfBounds { region, bounds } => write!(
f,
"region {region:?} out of bounds for {}x{} frame",
bounds.0, bounds.1
),
Error::BatchIndexOutOfBounds { index, batch } => write!(
f,
"batch index {index} out of bounds for batch size {batch}"
),
#[cfg(target_os = "linux")]
Error::UnknownBufferType(magic) => write!(
f,
"UnknownBufferType: fd is on an unrecognized filesystem \
(magic {magic:#010x}); expected a DMA-BUF or tmpfs/shm fd"
),
_ => write!(f, "{self:?}"),
}
}
}
impl std::error::Error for Error {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let e = Error::InvalidSize(0);
let msg = e.to_string();
assert!(!msg.is_empty());
assert!(
msg.contains("InvalidSize"),
"unexpected InvalidSize message: {msg}"
);
let e = Error::NotImplemented("foo".to_string());
let msg = e.to_string();
assert!(!msg.is_empty());
assert!(
msg.contains("NotImplemented") && msg.contains("foo"),
"unexpected NotImplemented message: {msg}"
);
let e = Error::ShapeMismatch("expected 3, got 4".to_string());
let msg = e.to_string();
assert!(!msg.is_empty());
assert!(
msg.contains("ShapeMismatch") && msg.contains("expected 3"),
"unexpected ShapeMismatch message: {msg}"
);
let e = Error::InvalidMemoryType("dma".to_string());
let msg = e.to_string();
assert!(!msg.is_empty());
assert!(
msg.contains("InvalidMemoryType") && msg.contains("dma"),
"unexpected InvalidMemoryType message: {msg}"
);
let e = Error::PboDisconnected;
let msg = e.to_string();
assert!(!msg.is_empty());
assert!(
msg.contains("PboDisconnected"),
"unexpected PboDisconnected message: {msg}"
);
let e = Error::PboMapped;
let msg = e.to_string();
assert!(!msg.is_empty());
assert!(
msg.contains("PboMapped"),
"unexpected PboMapped message: {msg}"
);
let e = Error::InvalidShape("bad shape".to_string());
let msg = e.to_string();
assert!(!msg.is_empty());
assert!(
msg.contains("InvalidShape") && msg.contains("bad shape"),
"unexpected InvalidShape message: {msg}"
);
let e = Error::InvalidArgument("negative".to_string());
let msg = e.to_string();
assert!(!msg.is_empty());
assert!(
msg.contains("InvalidArgument") && msg.contains("negative"),
"unexpected InvalidArgument message: {msg}"
);
let e = Error::PartialWriteRequiresReadWrite("retry with ReadWrite".to_string());
let msg = e.to_string();
assert!(!msg.is_empty());
assert!(
msg.contains("PartialWriteRequiresReadWrite") && msg.contains("retry with ReadWrite"),
"unexpected PartialWriteRequiresReadWrite message: {msg}"
);
let e = Error::InvalidOperation("read-only".to_string());
let msg = e.to_string();
assert!(!msg.is_empty());
assert!(
msg.contains("InvalidOperation") && msg.contains("read-only"),
"unexpected InvalidOperation message: {msg}"
);
let e = Error::IoError(std::io::Error::new(
std::io::ErrorKind::NotFound,
"file missing",
));
let msg = e.to_string();
assert!(!msg.is_empty());
assert!(
msg.contains("IoError") && msg.contains("file missing"),
"unexpected IoError message: {msg}"
);
}
#[test]
fn insufficient_capacity_message() {
let e = Error::InsufficientCapacity {
needed: 100,
capacity: 64,
};
assert_eq!(
e.to_string(),
"insufficient tensor capacity: need 100 bytes, have 64"
);
}
#[test]
fn region_out_of_bounds_message_names_the_frame() {
let region = crate::Region::new(2, 3, 8, 8);
let e = Error::RegionOutOfBounds {
region,
bounds: (4, 5),
};
assert_eq!(
e.to_string(),
format!("region {region:?} out of bounds for 4x5 frame")
);
}
#[test]
fn batch_index_out_of_bounds_message_names_index_and_size() {
let e = Error::BatchIndexOutOfBounds { index: 9, batch: 4 };
assert_eq!(
e.to_string(),
"batch index 9 out of bounds for batch size 4"
);
}
#[cfg(target_os = "linux")]
#[test]
fn unknown_buffer_type_message_names_the_magic() {
let e = Error::UnknownBufferType(0x1234);
assert_eq!(
e.to_string(),
"UnknownBufferType: fd is on an unrecognized filesystem (magic 0x00001234); \
expected a DMA-BUF or tmpfs/shm fd"
);
}
}