#![allow(deprecated)]
use std::{
ffi::{CStr, NulError},
fmt::{self, Display, Formatter},
};
use num_enum::{IntoPrimitive, TryFromPrimitive};
use singe_core::impl_enum_conversion;
use singe_nvml_sys as sys;
use thiserror::Error;
#[derive(Error, Debug, Clone, PartialEq, Eq)]
pub enum Error {
#[error("nvml error ({code}): {message}")]
Nvml { code: Status, message: String },
#[error("string contains interior nul byte")]
InteriorNul,
#[error("unknown field value type ({0})")]
UnknownFieldValueType(u32),
#[error("unexpected {name} field value type ({value})")]
UnexpectedFieldValueType { name: String, value: String },
#[error("unknown {name} value ({value})")]
UnknownEnumValue { name: String, value: u32 },
#[error("negative {name} value ({value})")]
NegativeValue { name: String, value: i64 },
#[error("{name} returned no values")]
EmptyOutput { name: String },
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive, IntoPrimitive)]
#[repr(u32)]
pub enum Status {
Success = sys::nvmlReturn_t::NVML_SUCCESS as _,
Uninitialized = sys::nvmlReturn_t::NVML_ERROR_UNINITIALIZED as _,
InvalidArgument = sys::nvmlReturn_t::NVML_ERROR_INVALID_ARGUMENT as _,
NotSupported = sys::nvmlReturn_t::NVML_ERROR_NOT_SUPPORTED as _,
NoPermission = sys::nvmlReturn_t::NVML_ERROR_NO_PERMISSION as _,
#[deprecated]
AlreadyInitialized = sys::nvmlReturn_t::NVML_ERROR_ALREADY_INITIALIZED as _,
NotFound = sys::nvmlReturn_t::NVML_ERROR_NOT_FOUND as _,
InsufficientSize = sys::nvmlReturn_t::NVML_ERROR_INSUFFICIENT_SIZE as _,
InsufficientPower = sys::nvmlReturn_t::NVML_ERROR_INSUFFICIENT_POWER as _,
DriverNotLoaded = sys::nvmlReturn_t::NVML_ERROR_DRIVER_NOT_LOADED as _,
Timeout = sys::nvmlReturn_t::NVML_ERROR_TIMEOUT as _,
IrqIssue = sys::nvmlReturn_t::NVML_ERROR_IRQ_ISSUE as _,
LibraryNotFound = sys::nvmlReturn_t::NVML_ERROR_LIBRARY_NOT_FOUND as _,
FunctionNotFound = sys::nvmlReturn_t::NVML_ERROR_FUNCTION_NOT_FOUND as _,
CorruptedInforom = sys::nvmlReturn_t::NVML_ERROR_CORRUPTED_INFOROM as _,
GpuIsLost = sys::nvmlReturn_t::NVML_ERROR_GPU_IS_LOST as _,
ResetRequired = sys::nvmlReturn_t::NVML_ERROR_RESET_REQUIRED as _,
OperatingSystem = sys::nvmlReturn_t::NVML_ERROR_OPERATING_SYSTEM as _,
LibRmVersionMismatch = sys::nvmlReturn_t::NVML_ERROR_LIB_RM_VERSION_MISMATCH as _,
InUse = sys::nvmlReturn_t::NVML_ERROR_IN_USE as _,
Memory = sys::nvmlReturn_t::NVML_ERROR_MEMORY as _,
NoData = sys::nvmlReturn_t::NVML_ERROR_NO_DATA as _,
VgpuEccNotSupported = sys::nvmlReturn_t::NVML_ERROR_VGPU_ECC_NOT_SUPPORTED as _,
InsufficientResources = sys::nvmlReturn_t::NVML_ERROR_INSUFFICIENT_RESOURCES as _,
FreqNotSupported = sys::nvmlReturn_t::NVML_ERROR_FREQ_NOT_SUPPORTED as _,
ArgumentVersionMismatch = sys::nvmlReturn_t::NVML_ERROR_ARGUMENT_VERSION_MISMATCH as _,
Deprecated = sys::nvmlReturn_t::NVML_ERROR_DEPRECATED as _,
NotReady = sys::nvmlReturn_t::NVML_ERROR_NOT_READY as _,
GpuNotFound = sys::nvmlReturn_t::NVML_ERROR_GPU_NOT_FOUND as _,
InvalidState = sys::nvmlReturn_t::NVML_ERROR_INVALID_STATE as _,
ResetTypeNotSupported = sys::nvmlReturn_t::NVML_ERROR_RESET_TYPE_NOT_SUPPORTED as _,
Unknown = sys::nvmlReturn_t::NVML_ERROR_UNKNOWN as _,
}
impl_enum_conversion!(sys::nvmlReturn_t, Status);
impl Status {
pub fn description(self) -> String {
unsafe {
let ptr = sys::nvmlErrorString(self.into());
if ptr.is_null() {
String::from("unknown nvml error")
} else {
CStr::from_ptr(ptr).to_string_lossy().into_owned()
}
}
}
}
impl Display for Status {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Success => write!(f, "NVML_SUCCESS"),
Self::Uninitialized => write!(f, "NVML_ERROR_UNINITIALIZED"),
Self::InvalidArgument => write!(f, "NVML_ERROR_INVALID_ARGUMENT"),
Self::NotSupported => write!(f, "NVML_ERROR_NOT_SUPPORTED"),
Self::NoPermission => write!(f, "NVML_ERROR_NO_PERMISSION"),
Self::AlreadyInitialized => write!(f, "NVML_ERROR_ALREADY_INITIALIZED"),
Self::NotFound => write!(f, "NVML_ERROR_NOT_FOUND"),
Self::InsufficientSize => write!(f, "NVML_ERROR_INSUFFICIENT_SIZE"),
Self::InsufficientPower => write!(f, "NVML_ERROR_INSUFFICIENT_POWER"),
Self::DriverNotLoaded => write!(f, "NVML_ERROR_DRIVER_NOT_LOADED"),
Self::Timeout => write!(f, "NVML_ERROR_TIMEOUT"),
Self::IrqIssue => write!(f, "NVML_ERROR_IRQ_ISSUE"),
Self::LibraryNotFound => write!(f, "NVML_ERROR_LIBRARY_NOT_FOUND"),
Self::FunctionNotFound => write!(f, "NVML_ERROR_FUNCTION_NOT_FOUND"),
Self::CorruptedInforom => write!(f, "NVML_ERROR_CORRUPTED_INFOROM"),
Self::GpuIsLost => write!(f, "NVML_ERROR_GPU_IS_LOST"),
Self::ResetRequired => write!(f, "NVML_ERROR_RESET_REQUIRED"),
Self::OperatingSystem => write!(f, "NVML_ERROR_OPERATING_SYSTEM"),
Self::LibRmVersionMismatch => {
write!(f, "NVML_ERROR_LIB_RM_VERSION_MISMATCH")
}
Self::InUse => write!(f, "NVML_ERROR_IN_USE"),
Self::Memory => write!(f, "NVML_ERROR_MEMORY"),
Self::NoData => write!(f, "NVML_ERROR_NO_DATA"),
Self::VgpuEccNotSupported => write!(f, "NVML_ERROR_VGPU_ECC_NOT_SUPPORTED"),
Self::InsufficientResources => write!(f, "NVML_ERROR_INSUFFICIENT_RESOURCES"),
Self::FreqNotSupported => write!(f, "NVML_ERROR_FREQ_NOT_SUPPORTED"),
Self::ArgumentVersionMismatch => {
write!(f, "NVML_ERROR_ARGUMENT_VERSION_MISMATCH")
}
Self::Deprecated => write!(f, "NVML_ERROR_DEPRECATED"),
Self::NotReady => write!(f, "NVML_ERROR_NOT_READY"),
Self::GpuNotFound => write!(f, "NVML_ERROR_GPU_NOT_FOUND"),
Self::InvalidState => write!(f, "NVML_ERROR_INVALID_STATE"),
Self::ResetTypeNotSupported => write!(f, "NVML_ERROR_RESET_TYPE_NOT_SUPPORTED"),
Self::Unknown => write!(f, "NVML_ERROR_UNKNOWN"),
}
}
}
impl From<NulError> for Error {
fn from(_: NulError) -> Self {
Self::InteriorNul
}
}
impl From<sys::nvmlReturn_t> for Error {
fn from(code: sys::nvmlReturn_t) -> Self {
let message = unsafe {
let c_ptr = sys::nvmlErrorString(code);
if c_ptr.is_null() {
String::from("unknown nvml error")
} else {
CStr::from_ptr(c_ptr).to_string_lossy().into_owned()
}
};
Self::Nvml {
code: code.into(),
message,
}
}
}
impl From<Status> for Error {
fn from(status: Status) -> Self {
sys::nvmlReturn_t::from(status).into()
}
}
#[macro_export]
macro_rules! try_ffi {
($expr:expr) => {{
let err = { $expr };
if err != singe_nvml_sys::nvmlReturn_t::NVML_SUCCESS {
Err($crate::error::Error::from(err))
} else {
Ok(())
}
}};
}