use crate::device::Device;
use crate::enum_wrappers::unit::LedColor;
use crate::enums::unit::{LedState, TemperatureReading};
use crate::error::{nvml_sym, nvml_try, nvml_try_count, NvmlError};
use crate::ffi::bindings::*;
use crate::struct_wrappers::unit::{FansInfo, PsuInfo, UnitInfo};
use crate::Nvml;
use static_assertions::assert_impl_all;
use std::mem;
use std::{convert::TryFrom, os::raw::c_uint};
#[derive(Debug)]
pub struct Unit<'nvml> {
unit: nvmlUnit_t,
nvml: &'nvml Nvml,
}
unsafe impl<'nvml> Send for Unit<'nvml> {}
unsafe impl<'nvml> Sync for Unit<'nvml> {}
assert_impl_all!(Unit: Send, Sync);
impl<'nvml> Unit<'nvml> {
#[allow(clippy::missing_safety_doc)]
pub unsafe fn new(unit: nvmlUnit_t, nvml: &'nvml Nvml) -> Self {
Self { unit, nvml }
}
pub fn nvml(&self) -> &'nvml Nvml {
self.nvml
}
pub unsafe fn handle(&self) -> nvmlUnit_t {
self.unit
}
#[doc(alias = "nvmlUnitGetDevices")]
pub fn devices(&self) -> Result<Vec<Device<'_>>, NvmlError> {
let sym = nvml_sym(self.nvml.lib.nvmlUnitGetDevices.as_ref())?;
unsafe {
let mut count: c_uint = match self.device_count()? {
0 => return Ok(vec![]),
value => value,
};
let mut devices: Vec<nvmlDevice_t> = vec![mem::zeroed(); count as usize];
nvml_try(sym(self.unit, &mut count, devices.as_mut_ptr()))?;
Ok(devices
.into_iter()
.map(|d| Device::new(d, self.nvml))
.collect())
}
}
#[doc(alias = "nvmlUnitGetDevices")]
pub fn device_count(&self) -> Result<u32, NvmlError> {
let sym = nvml_sym(self.nvml.lib.nvmlUnitGetDevices.as_ref())?;
let mut count: c_uint = 0;
unsafe {
nvml_try_count(sym(self.unit, &mut count, std::ptr::null_mut()))?;
}
Ok(count)
}
#[doc(alias = "nvmlUnitGetFanSpeedInfo")]
pub fn fan_info(&self) -> Result<FansInfo, NvmlError> {
let sym = nvml_sym(self.nvml.lib.nvmlUnitGetFanSpeedInfo.as_ref())?;
unsafe {
let mut fans_info: nvmlUnitFanSpeeds_t = mem::zeroed();
nvml_try(sym(self.unit, &mut fans_info))?;
FansInfo::try_from(fans_info)
}
}
#[doc(alias = "nvmlUnitGetLedState")]
pub fn led_state(&self) -> Result<LedState, NvmlError> {
let sym = nvml_sym(self.nvml.lib.nvmlUnitGetLedState.as_ref())?;
unsafe {
let mut state: nvmlLedState_t = mem::zeroed();
nvml_try(sym(self.unit, &mut state))?;
LedState::try_from(state)
}
}
#[doc(alias = "nvmlUnitGetPsuInfo")]
pub fn psu_info(&self) -> Result<PsuInfo, NvmlError> {
let sym = nvml_sym(self.nvml.lib.nvmlUnitGetPsuInfo.as_ref())?;
unsafe {
let mut info: nvmlPSUInfo_t = mem::zeroed();
nvml_try(sym(self.unit, &mut info))?;
PsuInfo::try_from(info)
}
}
#[doc(alias = "nvmlUnitGetTemperature")]
pub fn temperature(&self, reading_type: TemperatureReading) -> Result<u32, NvmlError> {
let sym = nvml_sym(self.nvml.lib.nvmlUnitGetTemperature.as_ref())?;
unsafe {
let mut temp: c_uint = mem::zeroed();
nvml_try(sym(self.unit, reading_type as c_uint, &mut temp))?;
Ok(temp)
}
}
#[doc(alias = "nvmlUnitGetUnitInfo")]
pub fn info(&self) -> Result<UnitInfo, NvmlError> {
let sym = nvml_sym(self.nvml.lib.nvmlUnitGetUnitInfo.as_ref())?;
unsafe {
let mut info: nvmlUnitInfo_t = mem::zeroed();
nvml_try(sym(self.unit, &mut info))?;
UnitInfo::try_from(info)
}
}
#[doc(alias = "nvmlUnitSetLedState")]
pub fn set_led_color(&mut self, color: LedColor) -> Result<(), NvmlError> {
let sym = nvml_sym(self.nvml.lib.nvmlUnitSetLedState.as_ref())?;
unsafe { nvml_try(sym(self.unit, color.as_c())) }
}
}
#[cfg(test)]
#[deny(unused_mut)]
mod test {
use crate::enum_wrappers::unit::LedColor;
use crate::enums::unit::TemperatureReading;
use crate::test_utils::*;
#[test]
#[ignore = "my machine does not support this call"]
fn devices() {
let nvml = nvml();
let unit = unit(&nvml);
unit.devices().expect("devices");
}
#[test]
#[ignore = "my machine does not support this call"]
fn fan_info() {
let nvml = nvml();
test_with_unit(3, &nvml, |unit| unit.fan_info())
}
#[test]
#[ignore = "my machine does not support this call"]
fn led_state() {
let nvml = nvml();
test_with_unit(3, &nvml, |unit| unit.led_state())
}
#[test]
#[ignore = "my machine does not support this call"]
fn psu_info() {
let nvml = nvml();
test_with_unit(3, &nvml, |unit| unit.psu_info())
}
#[test]
#[ignore = "my machine does not support this call"]
fn temperature() {
let nvml = nvml();
test_with_unit(3, &nvml, |unit| unit.temperature(TemperatureReading::Board))
}
#[test]
#[ignore = "my machine does not support this call"]
fn info() {
let nvml = nvml();
test_with_unit(3, &nvml, |unit| unit.info())
}
#[allow(dead_code)]
fn set_led_color() {
let nvml = nvml();
let mut unit = unit(&nvml);
unit.set_led_color(LedColor::Amber).expect("set to true")
}
}