use std::io;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum NumaError {
#[error("memory policy not supported: {reason}")]
PolicyNotSupported {
policy: String,
reason: String,
},
#[error("missing capability: {capability}")]
CapabilityMissing {
capability: &'static str,
},
#[error("hard mode unavailable for {feature}: {reason}")]
HardModeUnavailable {
feature: &'static str,
reason: String,
},
#[error("topology discovery failed: {source}")]
TopologyError {
#[source]
source: io::Error,
},
#[error("allocation of {size} bytes failed: {source}")]
AllocationFailed {
size: usize,
#[source]
source: io::Error,
},
#[error("thread pinning failed: {source}")]
PinningFailed {
#[source]
source: io::Error,
},
#[error("memory binding failed: {source}")]
BindFailed {
#[source]
source: io::Error,
},
#[error("invalid argument: {message}")]
InvalidArgument {
message: String,
},
#[error("feature not supported on this platform: {feature}")]
NotSupported {
feature: &'static str,
},
#[error("I/O error: {0}")]
Io(#[from] io::Error),
}
impl NumaError {
pub fn topology(source: io::Error) -> Self {
Self::TopologyError { source }
}
pub fn allocation(size: usize, source: io::Error) -> Self {
Self::AllocationFailed { size, source }
}
pub fn pinning(source: io::Error) -> Self {
Self::PinningFailed { source }
}
pub fn bind(source: io::Error) -> Self {
Self::BindFailed { source }
}
pub fn policy_not_supported(policy: impl Into<String>, reason: impl Into<String>) -> Self {
Self::PolicyNotSupported {
policy: policy.into(),
reason: reason.into(),
}
}
pub fn hard_mode_unavailable(feature: &'static str, reason: impl Into<String>) -> Self {
Self::HardModeUnavailable {
feature,
reason: reason.into(),
}
}
pub fn invalid_argument(message: impl Into<String>) -> Self {
Self::InvalidArgument {
message: message.into(),
}
}
pub fn is_permission_error(&self) -> bool {
match self {
Self::CapabilityMissing { .. } => true,
Self::TopologyError { source }
| Self::AllocationFailed { source, .. }
| Self::PinningFailed { source }
| Self::BindFailed { source } => source.kind() == io::ErrorKind::PermissionDenied,
Self::Io(e) => e.kind() == io::ErrorKind::PermissionDenied,
_ => false,
}
}
pub fn is_not_supported(&self) -> bool {
matches!(
self,
Self::NotSupported { .. } | Self::PolicyNotSupported { .. }
)
}
}
pub type Result<T> = std::result::Result<T, NumaError>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let err = NumaError::policy_not_supported("Bind", "kernel too old");
assert_eq!(
format!("{}", err),
"memory policy not supported: kernel too old"
);
let err = NumaError::CapabilityMissing {
capability: "CAP_SYS_NICE",
};
assert_eq!(format!("{}", err), "missing capability: CAP_SYS_NICE");
}
#[test]
fn test_error_is_permission() {
let err = NumaError::CapabilityMissing {
capability: "CAP_SYS_NICE",
};
assert!(err.is_permission_error());
let err = NumaError::pinning(io::Error::from_raw_os_error(1));
assert!(err.is_permission_error());
}
}