use thiserror::Error;
pub type Result<T> = std::result::Result<T, NirError>;
#[derive(Debug, Clone, PartialEq, Eq, Error)]
#[non_exhaustive]
pub enum NirError {
#[error("not implemented: {0}")]
Unimplemented(&'static str),
#[error("unknown node type: {0}")]
UnknownNodeType(String),
#[error("duplicate node: {0}")]
DuplicateNode(String),
#[error("missing node: {0}")]
MissingNode(String),
#[error("duplicate edge: ({0}, {1})")]
DuplicateEdge(String, String),
#[error("invalid graph: {0}")]
InvalidGraph(String),
#[error("unsupported version: {0}")]
UnsupportedVersion(String),
#[error("missing field: {0}")]
MissingField(String),
#[error("invalid tensor: {0}")]
InvalidTensor(String),
#[error(
"read allocation limit exceeded at {context}: limit {limit} bytes, used {used} bytes, requested {requested} bytes"
)]
ReadLimitExceeded {
context: String,
limit: usize,
used: usize,
requested: usize,
},
#[error("io error: {0}")]
Io(String),
}
#[cfg(feature = "hdf5")]
impl From<hdf5::Error> for NirError {
fn from(err: hdf5::Error) -> Self {
Self::Io(err.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unimplemented_display() {
let err = NirError::Unimplemented("hdf5 read");
assert_eq!(err.to_string(), "not implemented: hdf5 read");
}
#[test]
fn unknown_node_type_display() {
let err = NirError::UnknownNodeType("CurrLIF".into());
assert_eq!(err.to_string(), "unknown node type: CurrLIF");
}
#[test]
fn duplicate_node_display() {
let err = NirError::DuplicateNode("lif".into());
assert_eq!(err.to_string(), "duplicate node: lif");
}
#[test]
fn missing_node_display() {
let err = NirError::MissingNode("missing".into());
assert_eq!(err.to_string(), "missing node: missing");
}
#[test]
fn duplicate_edge_display() {
let err = NirError::DuplicateEdge("a".into(), "b".into());
assert_eq!(err.to_string(), "duplicate edge: (a, b)");
}
#[test]
fn invalid_graph_display() {
let err = NirError::InvalidGraph("empty subgraph".into());
assert_eq!(err.to_string(), "invalid graph: empty subgraph");
}
#[test]
fn unsupported_version_display() {
let err = NirError::UnsupportedVersion("99.0".into());
assert_eq!(err.to_string(), "unsupported version: 99.0");
}
#[test]
fn missing_field_display() {
let err = NirError::MissingField("weight".into());
assert_eq!(err.to_string(), "missing field: weight");
}
#[test]
fn invalid_tensor_display() {
let err = NirError::InvalidTensor("shape product 4 != data len 3".into());
assert_eq!(
err.to_string(),
"invalid tensor: shape product 4 != data len 3"
);
}
#[test]
fn read_limit_display() {
let err = NirError::ReadLimitExceeded {
context: "lif.tau".into(),
limit: 1024,
used: 768,
requested: 512,
};
assert_eq!(
err.to_string(),
"read allocation limit exceeded at lif.tau: limit 1024 bytes, used 768 bytes, requested 512 bytes"
);
}
#[test]
fn io_display() {
let err = NirError::Io("unable to open file: model.nir".into());
assert_eq!(err.to_string(), "io error: unable to open file: model.nir");
}
#[test]
fn error_trait_implemented() {
let err: Box<dyn std::error::Error> = Box::new(NirError::Unimplemented("x"));
assert!(err.to_string().contains("not implemented"));
}
}