use std::path::{Path, PathBuf};
use std::convert::AsRef;
use std::io::Result as IoResult;
use crate::SysEntityAttributesExt;
const PSU_DIR_PATH: &'static str = "sys/class/power_supply/";
const CLASS_PATH: &'static str = "power_supply";
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "derive", derive(Debug))]
pub enum PowerSupplyAttribute {
Manufacturer,
ModelName,
SerialNumber,
Type,
CurrentAverage,
CurrentMax,
CurrentNow,
Temperature,
TemperatureAlertMax,
TemperatureAlertMin,
TemperatureMax,
TemperatureMin,
VoltageMax,
VoltageMin,
VoltageNow,
Capacity,
CapacityAlertMax,
CapacityAlertMin,
CapacityErrorMargin,
CapacityLevel,
ChargeControlLimit,
ChargeControlLimitMax,
ChargeControlStartThreshold,
ChargeControlEndThreshold,
ChargeType,
ChargeTermCurrent,
ChargeNow,
ChargeFull,
ChargeFullDesign,
Health,
PrechargeCurrent,
Present,
Status,
ChargeBehaviour,
Technology,
VoltageAverage,
CycleCount,
Custom(&'static str)
}
impl crate::SysAttribute for PowerSupplyAttribute {
fn filename(&self) -> PathBuf {
let s = match self {
Self::Manufacturer => "manufacturer",
Self::ModelName => "model_name",
Self::SerialNumber => "serial_number",
Self::Type => "type",
Self::CurrentAverage => "current_avg",
Self::CurrentMax => "current_max",
Self::CurrentNow => "current_now",
Self::Temperature => "temp",
Self::TemperatureAlertMax => "temp_alert_max",
Self::TemperatureAlertMin => "temp_alert_min",
Self::TemperatureMax => "temp_max",
Self::TemperatureMin => "temp_min",
Self::VoltageMax => "voltage_max",
Self::VoltageMin => "voltage_min",
Self::VoltageNow => "voltage_now",
Self::Capacity => "capacity",
Self::CapacityAlertMax => "capacity_alert_max",
Self::CapacityAlertMin => "capacity_alert_min",
Self::CapacityErrorMargin => "capacity_error_margin",
Self::CapacityLevel => "capacity_level",
Self::ChargeControlLimit => "charge_control_limit",
Self::ChargeControlLimitMax => "charge_control_limit_max",
Self::ChargeControlStartThreshold => "charge_control_start_threshold",
Self::ChargeControlEndThreshold => "charge_control_end_threshold",
Self::ChargeType => "charge_type",
Self::ChargeTermCurrent => "charge_term_current",
Self::ChargeNow => "charge_now",
Self::ChargeFull => "charge_full",
Self::ChargeFullDesign => "charge_full_design",
Self::Health => "health",
Self::PrechargeCurrent => "precharge_current",
Self::Present => "present",
Self::Status => "status",
Self::ChargeBehaviour => "charge_behaviour",
Self::Technology => "technology",
Self::VoltageAverage => "voltage_avg",
Self::CycleCount => "cycle_count",
Self::Custom(s) => s,
};
s.into()
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "derive", derive(Debug))]
pub enum PowerSupplyType {
Battery,
UPS,
Mains,
USB,
Wireless,
}
impl PowerSupplyType {
fn allowed_values() -> &'static [&'static str] {
&[
"Battery",
"UPS",
"Mains",
"USB",
"Wireless",
]
}
}
impl std::fmt::Display for PowerSupplyType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Battery => write!(f, "Battery"),
Self::UPS => write!(f, "UPS"),
Self::Mains => write!(f, "Mains"),
Self::USB => write!(f, "USB"),
Self::Wireless => write!(f, "Wireless")
}
}
}
impl std::str::FromStr for PowerSupplyType {
type Err = crate::ValueEnumError<'static>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"Battery" => Ok(Self::Battery),
"UPS" => Ok(Self::UPS),
"Mains" => Ok(Self::Mains),
"USB" => Ok(Self::USB),
"Wireless" => Ok(Self::Wireless),
other => Err(crate::ValueEnumError {
got: other.to_owned(),
allowed: Self::allowed_values(),
})
}
}
}
#[cfg_attr(feature = "derive", derive(Debug, Clone))]
pub struct PowerSupplyPath {
inner: crate::BasicEntityPath,
}
impl PowerSupplyPath {
pub(crate) fn all(root: impl AsRef<Path>) -> IoResult<impl Iterator<Item=IoResult<Self>>> {
Ok(crate::BasicEntityPath::all(root, CLASS_PATH)?
.map(|result| result.map(|inner| Self { inner })))
}
pub(crate) fn name(root: &crate::SysPath, name: &str) -> Self {
Self {
inner: crate::BasicEntityPath::new(root.as_ref().join(PSU_DIR_PATH).join(name))
}
}
pub fn type_str(&self) -> IoResult<String> {
self.attribute(PowerSupplyAttribute::Type).map_err(|e| e.map_infallible_second())
}
pub fn type_enum(&self) -> Result<PowerSupplyType, crate::EitherErr2<std::io::Error, <PowerSupplyType as std::str::FromStr>::Err>> {
self.attribute(PowerSupplyAttribute::Type)
}
}
impl AsRef<Path> for PowerSupplyPath {
fn as_ref(&self) -> &Path {
self.inner.as_ref()
}
}
impl crate::SysEntity for PowerSupplyPath {
fn to_entity_path(self) -> crate::EntityPath {
crate::EntityPath::PowerSupply(self)
}
fn name(&self) -> IoResult<String> {
self.inner.name()
}
}
impl crate::SysEntityAttributes<PowerSupplyAttribute> for PowerSupplyPath {
fn capabilities(&self) -> Vec<PowerSupplyAttribute> {
self.inner.filter_capabilities(vec![
PowerSupplyAttribute::Manufacturer,
PowerSupplyAttribute::ModelName,
PowerSupplyAttribute::SerialNumber,
PowerSupplyAttribute::Type,
PowerSupplyAttribute::CurrentAverage,
PowerSupplyAttribute::CurrentMax,
PowerSupplyAttribute::CurrentNow,
PowerSupplyAttribute::Temperature,
PowerSupplyAttribute::TemperatureAlertMax,
PowerSupplyAttribute::TemperatureAlertMin,
PowerSupplyAttribute::TemperatureMax,
PowerSupplyAttribute::TemperatureMin,
PowerSupplyAttribute::VoltageMax,
PowerSupplyAttribute::VoltageMin,
PowerSupplyAttribute::VoltageNow,
PowerSupplyAttribute::Capacity,
PowerSupplyAttribute::CapacityAlertMax,
PowerSupplyAttribute::CapacityAlertMin,
PowerSupplyAttribute::CapacityErrorMargin,
PowerSupplyAttribute::CapacityLevel,
PowerSupplyAttribute::ChargeNow,
PowerSupplyAttribute::ChargeFull,
PowerSupplyAttribute::ChargeFullDesign,
PowerSupplyAttribute::ChargeControlLimit,
PowerSupplyAttribute::ChargeControlLimitMax,
PowerSupplyAttribute::ChargeControlStartThreshold,
PowerSupplyAttribute::ChargeControlEndThreshold,
PowerSupplyAttribute::ChargeType,
PowerSupplyAttribute::ChargeTermCurrent,
PowerSupplyAttribute::Health,
PowerSupplyAttribute::PrechargeCurrent,
PowerSupplyAttribute::Present,
PowerSupplyAttribute::Status,
PowerSupplyAttribute::ChargeBehaviour,
PowerSupplyAttribute::Technology,
PowerSupplyAttribute::VoltageAverage,
PowerSupplyAttribute::CycleCount,
].into_iter()).collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::SysEntityAttributes;
use crate::SysEntityAttributesExt;
use crate::SysAttribute;
#[test]
fn power_supply_all() -> std::io::Result<()> {
if std::fs::read_dir("/sys/class/power_supply")?.count() == 0 {
eprintln!("power_supply test skipped since none exist (maybe running on a desktop PC?)");
return Ok(())
}
let sys = crate::SysPath::default();
let all_psu: Vec<_> = PowerSupplyPath::all(sys)?.collect();
assert!(!all_psu.is_empty());
for p in all_psu.into_iter() {
let p = p?;
assert!(p.type_str()? != "");
assert!(!p.capabilities().is_empty());
assert!(p.capabilities().contains(&PowerSupplyAttribute::Type))
}
Ok(())
}
#[test]
fn power_supply_capabilities() -> std::io::Result<()> {
let sys = crate::SysPath::default();
if !PowerSupplyAttribute::Type.exists(&sys.power_supply_by_name("BAT0")) {
eprintln!("power_supply test skipped since BAT0 does not exist (maybe running on a desktop PC?)");
return Ok(())
}
let psu = sys.power_supply(crate::capability::attributes([
PowerSupplyAttribute::Type,
PowerSupplyAttribute::Capacity,
].into_iter()))?.next().expect("Missing capable battery");
assert!(psu.attribute::<PowerSupplyType, _>(PowerSupplyAttribute::Type).expect("type capable but also incapable") == PowerSupplyType::Battery);
Ok(())
}
}