crates/mimir-graph/src/error.rs
use std::fmt;
/// Everything that can go wrong in this crate.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error {
/// A GraphBLAS call returned an error `GrB_Info` (negative code).
GraphBlas { call: &'static str, info: i32 },
/// The input was rejected before it reached GraphBLAS (bad CSR, index out
/// of range, size mismatch, …).
Invalid(String),
/// The Arrow batch does not have the expected shape.
Arrow(String),
/// `malloc` failed for a buffer handed to GraphBLAS.
Alloc { bytes: usize },
/// The linked libgraphblas is not the major version the bindings are for.
Version {
found: (i32, i32, i32),
expected_major: i32,
},
}
pub type Result<T> = std::result::Result<T, Error>;
impl Error {
pub(crate) fn invalid(msg: impl Into<String>) -> Self {
Error::Invalid(msg.into())
}
}
fn info_name(info: i32) -> &'static str {
match info {
-1 => "GrB_UNINITIALIZED_OBJECT",
-2 => "GrB_NULL_POINTER",
-3 => "GrB_INVALID_VALUE",
-4 => "GrB_INVALID_INDEX",
-5 => "GrB_DOMAIN_MISMATCH",
-6 => "GrB_DIMENSION_MISMATCH",
-7 => "GrB_OUTPUT_NOT_EMPTY",
-8 => "GrB_NOT_IMPLEMENTED",
-101 => "GrB_PANIC",
-102 => "GrB_OUT_OF_MEMORY",
-103 => "GrB_INSUFFICIENT_SPACE",
-104 => "GrB_INVALID_OBJECT",
-105 => "GrB_INDEX_OUT_OF_BOUNDS",
-106 => "GrB_EMPTY_OBJECT",
_ => "unknown GrB_Info",
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::GraphBlas { call, info } => {
write!(f, "{call} failed: {} ({info})", info_name(*info))
}
Error::Invalid(m) => write!(f, "invalid input: {m}"),
Error::Arrow(m) => write!(f, "arrow: {m}"),
Error::Alloc { bytes } => write!(f, "malloc of {bytes} bytes failed"),
Error::Version {
found: (a, b, c),
expected_major,
} => write!(
f,
"libgraphblas {a}.{b}.{c} is linked, the bindings are for {expected_major}.x"
),
}
}
}
impl std::error::Error for Error {}
/// Turn a `GrB_Info` into a `Result`. `GrB_SUCCESS` (0) and `GrB_NO_VALUE` (1)
/// are both "not an error"; callers that care about NO_VALUE use [`check_value`].
pub(crate) fn check(call: &'static str, info: graphblas_sys::GrB_Info) -> Result<()> {
if info >= 0 {
Ok(())
} else {
Err(Error::GraphBlas { call, info })
}
}
/// Like [`check`] but reports whether an entry was present (`GrB_NO_VALUE` → false).
pub(crate) fn check_value(call: &'static str, info: graphblas_sys::GrB_Info) -> Result<bool> {
match info {
graphblas_sys::GrB_SUCCESS => Ok(true),
graphblas_sys::GrB_NO_VALUE => Ok(false),
_ => check(call, info).map(|_| false),
}
}
/// Call a GraphBLAS function and `?` its `GrB_Info`, naming the call in the error.
macro_rules! grb {
($f:ident ( $($arg:expr),* $(,)? )) => {
$crate::error::check(stringify!($f), unsafe { graphblas_sys::$f($($arg),*) })
};
}
pub(crate) use grb;