use std::ffi::c_void;
#[link(name = "objc", kind = "dylib")]
unsafe extern "C" {
fn objc_getClass(name: *const i8) -> *mut c_void;
fn sel_registerName(name: *const i8) -> *mut c_void;
fn objc_msgSend(receiver: *mut c_void, selector: *mut c_void, ...) -> *mut c_void;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i64)]
pub enum ThermalState {
Nominal = 0,
Fair = 1,
Serious = 2,
Critical = 3,
}
impl ThermalState {
pub fn from_raw(value: i64) -> Self {
match value {
0 => ThermalState::Nominal,
1 => ThermalState::Fair,
2 => ThermalState::Serious,
3 => ThermalState::Critical,
_ => ThermalState::Nominal, }
}
pub fn as_str(&self) -> &'static str {
match self {
ThermalState::Nominal => "Nominal",
ThermalState::Fair => "Fair",
ThermalState::Serious => "Serious",
ThermalState::Critical => "Critical",
}
}
#[allow(dead_code)]
pub fn is_throttling(&self) -> bool {
matches!(self, ThermalState::Serious | ThermalState::Critical)
}
}
impl std::fmt::Display for ThermalState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_str())
}
}
pub fn get_thermal_state() -> ThermalState {
unsafe {
let class = objc_getClass(c"NSProcessInfo".as_ptr());
if class.is_null() {
return ThermalState::Nominal;
}
let process_info_sel = sel_registerName(c"processInfo".as_ptr());
if process_info_sel.is_null() {
return ThermalState::Nominal;
}
let process_info = objc_msgSend(class, process_info_sel);
if process_info.is_null() {
return ThermalState::Nominal;
}
let thermal_state_sel = sel_registerName(c"thermalState".as_ptr());
if thermal_state_sel.is_null() {
return ThermalState::Nominal;
}
let state = objc_msgSend(process_info, thermal_state_sel) as i64;
ThermalState::from_raw(state)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_thermal_state_from_raw() {
assert_eq!(ThermalState::from_raw(0), ThermalState::Nominal);
assert_eq!(ThermalState::from_raw(1), ThermalState::Fair);
assert_eq!(ThermalState::from_raw(2), ThermalState::Serious);
assert_eq!(ThermalState::from_raw(3), ThermalState::Critical);
assert_eq!(ThermalState::from_raw(99), ThermalState::Nominal); }
#[test]
fn test_thermal_state_strings() {
assert_eq!(ThermalState::Nominal.as_str(), "Nominal");
assert_eq!(ThermalState::Fair.as_str(), "Fair");
assert_eq!(ThermalState::Serious.as_str(), "Serious");
assert_eq!(ThermalState::Critical.as_str(), "Critical");
}
#[test]
fn test_is_throttling() {
assert!(!ThermalState::Nominal.is_throttling());
assert!(!ThermalState::Fair.is_throttling());
assert!(ThermalState::Serious.is_throttling());
assert!(ThermalState::Critical.is_throttling());
}
#[test]
fn test_display_trait() {
assert_eq!(format!("{}", ThermalState::Nominal), "Nominal");
assert_eq!(format!("{}", ThermalState::Critical), "Critical");
}
}