Improve API ergonomics and add optional additional derives
This commit is contained in:
parent
346341b804
commit
16f32e7e9d
10 changed files with 207 additions and 35 deletions
|
@ -6,3 +6,7 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
derive = []
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::str::FromStr;
|
|||
use crate::EitherErr2;
|
||||
|
||||
/// sysfs entity attribute file functionality
|
||||
pub trait SysAttribute: Eq {
|
||||
pub trait SysAttribute {
|
||||
/// attribute file name
|
||||
fn filename(&self) -> PathBuf;
|
||||
|
||||
|
@ -29,6 +29,11 @@ pub trait SysAttribute: Eq {
|
|||
fn write_value(&self, entity: &dyn crate::SysEntity, value: &[u8]) -> IoResult<()> {
|
||||
std::fs::write(self.path(entity), value)
|
||||
}
|
||||
|
||||
/// Returns true if the attribute is readonly
|
||||
fn readonly(&self, entity: &dyn crate::SysEntity) -> bool {
|
||||
self.path(entity).metadata().map(|meta| meta.permissions().readonly()).unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
impl SysAttribute for String {
|
||||
|
@ -37,8 +42,14 @@ impl SysAttribute for String {
|
|||
}
|
||||
}
|
||||
|
||||
impl SysAttribute for &str {
|
||||
fn filename(&self) -> PathBuf {
|
||||
PathBuf::from(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// sysfs entity attribute functionality extension
|
||||
pub trait SysAttributeExt: SysAttribute {
|
||||
pub trait SysAttributeExt: SysAttribute + Eq {
|
||||
/// read attribute as string
|
||||
fn read_str(&self, entity: &dyn crate::SysEntity) -> IoResult<String> {
|
||||
std::fs::read_to_string(self.path(entity))
|
||||
|
@ -56,4 +67,4 @@ pub trait SysAttributeExt: SysAttribute {
|
|||
}
|
||||
}
|
||||
|
||||
impl <X: SysAttribute> SysAttributeExt for X {}
|
||||
impl <X: SysAttribute + Eq> SysAttributeExt for X {}
|
||||
|
|
|
@ -5,6 +5,7 @@ use std::io::Result as IoResult;
|
|||
const SYS_CLASS_PATH: &str = "sys/class";
|
||||
|
||||
/// Generic entity path with basic functionality
|
||||
#[cfg_attr(feature = "derive", derive(Debug, Clone))]
|
||||
pub struct BasicEntityPath {
|
||||
path: PathBuf
|
||||
}
|
||||
|
@ -61,7 +62,7 @@ impl crate::SysEntity for BasicEntityPath {
|
|||
}
|
||||
}
|
||||
|
||||
impl crate::SysEntityAttributes<String, String, <String as std::str::FromStr>::Err> for BasicEntityPath {
|
||||
impl crate::SysEntityAttributes<String> for BasicEntityPath {
|
||||
fn capabilities(&self) -> Vec<String> {
|
||||
if let Ok(dir_iter) = self.path.read_dir() {
|
||||
dir_iter.filter_map(
|
||||
|
|
53
src/capability.rs
Normal file
53
src/capability.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
//! sysfs class entity capability filtering
|
||||
|
||||
/// Capabilities filter
|
||||
pub trait Capabilities<A: crate::SysAttribute, R: std::borrow::Borrow<A>> {
|
||||
/// Are the required capabilities (self) satisfied by the provided capabilities (the parameter)?
|
||||
fn can(&mut self, capabilities: &Vec<R>) -> bool;
|
||||
}
|
||||
|
||||
impl <F: FnMut(&Vec<R>) -> bool, A: crate::SysAttribute, R: std::borrow::Borrow<A>> Capabilities<A, R> for F {
|
||||
fn can(&mut self, capabilities: &Vec<R>) -> bool {
|
||||
(self)(capabilities)
|
||||
}
|
||||
}
|
||||
|
||||
/// Build a Capabilities implementor which needs specific attributes to exist
|
||||
pub fn attributes<'a, A: crate::SysAttribute + Eq + 'a, R: std::borrow::Borrow<A> + 'a>(attributes: impl Iterator<Item=R>) -> impl Capabilities<A, R> + 'a {
|
||||
AllNeedsCapabilities::new(
|
||||
attributes.map(|attr: R| { move |other_attr: &R| attr.borrow() == other_attr.borrow() }).collect()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
struct AllNeedsCapabilities<'a, 'f, A: crate::SysAttribute + 'a, R: std::borrow::Borrow<A> + 'a, F: (FnMut(&R) -> bool) + 'f> {
|
||||
wanted: Vec<F>,
|
||||
_attr_ty: std::marker::PhantomData<A>,
|
||||
_attr_brw_ty: std::marker::PhantomData<R>,
|
||||
_life_attr_ty: std::marker::PhantomData<&'a ()>,
|
||||
_life_fn_ty: std::marker::PhantomData<&'f ()>,
|
||||
}
|
||||
|
||||
impl <'a, 'f, A: crate::SysAttribute + 'a, R: std::borrow::Borrow<A> + 'a, F: (FnMut(&R) -> bool) + 'f> AllNeedsCapabilities<'a, 'f, A, R, F> {
|
||||
pub(crate) fn new(wanted: Vec<F>) -> Self {
|
||||
Self {
|
||||
wanted,
|
||||
_attr_ty: Default::default(),
|
||||
_attr_brw_ty: Default::default(),
|
||||
_life_attr_ty: Default::default(),
|
||||
_life_fn_ty: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a, 'f, A: crate::SysAttribute + 'a, R: std::borrow::Borrow<A> + 'a, F: (FnMut(&R) -> bool) + 'f> Capabilities<A, R> for AllNeedsCapabilities<'a, 'f, A, R, F> {
|
||||
fn can(&mut self, capabilities: &Vec<R>) -> bool {
|
||||
let mut wants = vec![false; self.wanted.len()];
|
||||
for capability in capabilities {
|
||||
if let Some(pos) = self.wanted.iter_mut().position(|w| w(capability)) {
|
||||
wants[pos] = true;
|
||||
}
|
||||
}
|
||||
wants.into_iter().all(|item| item)
|
||||
}
|
||||
}
|
|
@ -6,18 +6,39 @@ use crate::EitherErr2;
|
|||
use crate::SysAttributeExt;
|
||||
|
||||
/// sysfs class entity functionality
|
||||
#[cfg(feature = "derive")]
|
||||
pub trait SysEntity: AsRef<Path> + core::fmt::Debug {
|
||||
/// Convert specialized entity into general entity path container
|
||||
fn to_entity_path(self) -> EntityPath;
|
||||
|
||||
/// Get the entity's name
|
||||
fn name(&self) -> IoResult<String>;
|
||||
|
||||
/// Try to get the entity's root sysfs dir (probably `/`)
|
||||
fn root(&self) -> Option<crate::SysPath> {
|
||||
crate::SysPath::from_entity_path(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// sysfs class entity functionality
|
||||
#[cfg(not(feature = "derive"))]
|
||||
pub trait SysEntity: AsRef<Path> {
|
||||
/// Convert specialized entity into general entity path container
|
||||
fn to_entity_path(self) -> EntityPath;
|
||||
|
||||
/// Get the entity's name
|
||||
fn name(&self) -> IoResult<String>;
|
||||
|
||||
/// Try to get the entity's root sysfs dir (probably `/`)
|
||||
fn root(&self) -> Option<crate::SysPath> {
|
||||
crate::SysPath::from_entity_path(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// sysfs class entity functionality extension
|
||||
pub trait SysEntityRawExt: SysEntity {
|
||||
/// Get an attribute on the entity
|
||||
fn attribute<A: crate::SysAttribute, T: std::str::FromStr<Err=E>, E>(&self, attr: A) -> Result<T, EitherErr2<std::io::Error, E>>;
|
||||
fn attribute<A: crate::SysAttribute + Eq, T: std::str::FromStr<Err=E>, E>(&self, attr: A) -> Result<T, EitherErr2<std::io::Error, E>>;
|
||||
/// Get an attribute by filename in the entity's directory
|
||||
fn attribute_str<A: AsRef<Path>>(&self, attr: A) -> IoResult<String>;
|
||||
|
||||
|
@ -29,7 +50,7 @@ pub trait SysEntityRawExt: SysEntity {
|
|||
}
|
||||
|
||||
impl <X: SysEntity> SysEntityRawExt for X {
|
||||
fn attribute<A: crate::SysAttribute, T: std::str::FromStr<Err=E>, E>(&self, attr: A) -> Result<T, EitherErr2<std::io::Error, E>> {
|
||||
fn attribute<A: crate::SysAttribute + Eq, T: std::str::FromStr<Err=E>, E>(&self, attr: A) -> Result<T, EitherErr2<std::io::Error, E>> {
|
||||
attr.parse(self)
|
||||
}
|
||||
|
||||
|
@ -48,21 +69,26 @@ impl <X: SysEntity> SysEntityRawExt for X {
|
|||
|
||||
|
||||
/// sysfs class entity attribute type indicator
|
||||
pub trait SysEntityAttributes<A: crate::SysAttribute, T: std::str::FromStr<Err=E>, E>: SysEntity + Sized {
|
||||
/// Get an attribute on the entity
|
||||
fn attribute(&self, attr: A) -> Result<T, EitherErr2<std::io::Error, E>> {
|
||||
attr.parse(self)
|
||||
}
|
||||
|
||||
pub trait SysEntityAttributes<A: crate::SysAttribute + Eq>: SysEntity + Sized {
|
||||
/// Get attributes available on this entity;
|
||||
fn capabilities(&self) -> Vec<A>;
|
||||
}
|
||||
|
||||
/*pub trait SysEntityAttributesExt<A: crate::SysAttribute, T: std::str::FromStr<Err=E>, E>: SysEntityAttributes<A, T, E> {
|
||||
fn attribute()
|
||||
}*/
|
||||
pub trait SysEntityAttributesExt<A: crate::SysAttribute + Eq>: SysEntityAttributes<A> {
|
||||
fn capable<C: crate::capability::Capabilities<A, A>>(&self, mut capabilities: C) -> bool {
|
||||
capabilities.can(&self.capabilities())
|
||||
}
|
||||
|
||||
/// Get an attribute on the entity
|
||||
fn attribute<T: std::str::FromStr<Err=E>, E>(&self, attr: A) -> Result<T, EitherErr2<std::io::Error, E>> {
|
||||
attr.parse(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl <A: crate::SysAttribute + Eq, X: SysEntityAttributes<A>> SysEntityAttributesExt<A> for X {}
|
||||
|
||||
/// sysfs class entity implementors
|
||||
#[cfg_attr(feature = "derive", derive(Debug, Clone))]
|
||||
pub enum EntityPath {
|
||||
/// hwmon
|
||||
HwMon(crate::HwMonPath),
|
||||
|
@ -71,7 +97,7 @@ pub enum EntityPath {
|
|||
/// Generic
|
||||
Generic(crate::BasicEntityPath),
|
||||
/// Miscellaneous
|
||||
Custom(Box<dyn SysEntity>),
|
||||
Custom(std::sync::Arc<Box<dyn SysEntity>>),
|
||||
}
|
||||
|
||||
impl EntityPath {
|
||||
|
@ -80,19 +106,14 @@ impl EntityPath {
|
|||
Self::HwMon(inner) => inner,
|
||||
Self::PowerSupply(inner) => inner,
|
||||
Self::Generic(inner) => inner,
|
||||
Self::Custom(inner) => inner.as_ref(),
|
||||
Self::Custom(inner) => inner.as_ref().as_ref(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Path> for EntityPath {
|
||||
fn as_ref(&self) -> &Path {
|
||||
match self {
|
||||
Self::HwMon(inner) => inner.as_ref(),
|
||||
Self::PowerSupply(inner) => inner.as_ref(),
|
||||
Self::Generic(inner) => inner.as_ref(),
|
||||
Self::Custom(inner) => inner.as_ref().as_ref(),
|
||||
}
|
||||
self.inner().as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/// Multi-error convenience enum
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum EitherErr2<T1, T2> {
|
||||
/// Type 1
|
||||
First(T1),
|
||||
|
@ -32,7 +32,7 @@ impl <T1: std::error::Error, T2: std::error::Error> std::error::Error for Either
|
|||
|
||||
/// Value parse error for an enumeration.
|
||||
/// This usually indicates an unexpected value (one without an enum variant) was received while parsing.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ValueEnumError<'a> {
|
||||
pub(crate) got: String,
|
||||
pub(crate) allowed: &'a [&'a str],
|
||||
|
|
16
src/hwmon.rs
16
src/hwmon.rs
|
@ -7,11 +7,13 @@ const HWMON_DIR_PATH: &'static str = "sys/class/hwmon/";
|
|||
/// Attribute representation.
|
||||
/// Attribute files are usually in the format `<type><number>_<item>`.
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "derive", derive(Debug))]
|
||||
pub struct HwMonAttribute {
|
||||
inner: HwMonAttributeInner,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "derive", derive(Debug))]
|
||||
enum HwMonAttributeInner {
|
||||
Name,
|
||||
Standard {
|
||||
|
@ -20,6 +22,7 @@ enum HwMonAttributeInner {
|
|||
item: HwMonAttributeItem,
|
||||
},
|
||||
Uevent,
|
||||
Custom(&'static str),
|
||||
}
|
||||
|
||||
impl std::str::FromStr for HwMonAttributeInner {
|
||||
|
@ -46,6 +49,7 @@ impl std::str::FromStr for HwMonAttributeInner {
|
|||
|
||||
/// Attribute type in the format `<type><number>_<item>`
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "derive", derive(Debug))]
|
||||
pub enum HwMonAttributeType {
|
||||
/// Voltage
|
||||
In,
|
||||
|
@ -84,6 +88,7 @@ impl HwMonAttributeType {
|
|||
|
||||
/// Attribute item in the format `<type><number>_<item>`
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "derive", derive(Debug))]
|
||||
pub enum HwMonAttributeItem {
|
||||
/// Input
|
||||
Input,
|
||||
|
@ -137,11 +142,19 @@ impl HwMonAttribute {
|
|||
}
|
||||
}
|
||||
|
||||
/// Custom entity attribute
|
||||
pub const fn custom(attr: &'static str) -> Self {
|
||||
Self {
|
||||
inner: HwMonAttributeInner::Custom(attr)
|
||||
}
|
||||
}
|
||||
|
||||
fn to_attr_str(&self) -> String {
|
||||
match self.inner {
|
||||
HwMonAttributeInner::Name => "name".to_string(),
|
||||
HwMonAttributeInner::Standard { ty, number, item } => format!("{}{}_{}", ty.to_attr_str(), number, item.to_attr_str()),
|
||||
HwMonAttributeInner::Uevent => "uevent".to_string(),
|
||||
HwMonAttributeInner::Custom(s) => s.to_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -153,6 +166,7 @@ impl crate::SysAttribute for HwMonAttribute {
|
|||
}
|
||||
|
||||
/// hwmon<number>/ directory
|
||||
#[cfg_attr(feature = "derive", derive(Debug, Clone))]
|
||||
pub struct HwMonPath {
|
||||
path: PathBuf
|
||||
}
|
||||
|
@ -226,7 +240,7 @@ impl crate::SysEntity for HwMonPath {
|
|||
}
|
||||
}
|
||||
|
||||
impl crate::SysEntityAttributes<HwMonAttribute, String, <String as std::str::FromStr>::Err> for HwMonPath {
|
||||
impl crate::SysEntityAttributes<HwMonAttribute> for HwMonPath {
|
||||
fn capabilities(&self) -> Vec<HwMonAttribute> {
|
||||
if let Ok(dir_iter) = self.path.read_dir() {
|
||||
dir_iter.filter_map(
|
||||
|
|
|
@ -10,6 +10,8 @@ pub use attribute::{SysAttribute, SysAttributeExt};
|
|||
mod basic;
|
||||
pub use basic::BasicEntityPath;
|
||||
|
||||
pub mod capability;
|
||||
|
||||
mod entity;
|
||||
pub use entity::{EntityPath, SysEntity, SysEntityRawExt, SysEntityAttributes};
|
||||
|
||||
|
|
|
@ -11,7 +11,8 @@ const CLASS_PATH: &'static str = "power_supply";
|
|||
|
||||
/// Attribute files in a power supply directory
|
||||
/// These attributes are taken from https://github.com/torvalds/linux/blob/master/Documentation/ABI/testing/sysfs-class-power
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "derive", derive(Debug))]
|
||||
pub enum PowerSupplyAttribute {
|
||||
/// Reports the name of the device manufacturer.
|
||||
Manufacturer,
|
||||
|
@ -65,6 +66,12 @@ pub enum PowerSupplyAttribute {
|
|||
ChargeType,
|
||||
/// Reports the charging current value which is used to determine when the battery is considered full and charging should end (uA).
|
||||
ChargeTermCurrent,
|
||||
/// Reports the instantaneous charge value of the power supply (uA).
|
||||
ChargeNow,
|
||||
/// Reports the maximum charge value of the power supply (uA).
|
||||
ChargeFull,
|
||||
/// Reports the maximum rated charge value of the power supply (uA).
|
||||
ChargeFullDesign,
|
||||
/// Reports the health of the battery or battery side of charger functionality ( "Unknown", "Good", "Overheat", "Dead", "Over voltage", "Unspecified failure", "Cold", "Watchdog timer expire", "Safety timer expire", "Over current", "Calibration required", "Warm", "Cool", "Hot", or "No battery").
|
||||
Health,
|
||||
/// Reports the charging current applied during pre-charging phase for a battery charge cycle (uA).
|
||||
|
@ -82,6 +89,8 @@ pub enum PowerSupplyAttribute {
|
|||
/// Reports the number of full charge + discharge cycles the battery has undergone.
|
||||
CycleCount,
|
||||
// TODO USB properties
|
||||
/// Custom entity attribute
|
||||
Custom(&'static str)
|
||||
}
|
||||
|
||||
impl crate::SysAttribute for PowerSupplyAttribute {
|
||||
|
@ -113,6 +122,9 @@ impl crate::SysAttribute for PowerSupplyAttribute {
|
|||
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",
|
||||
|
@ -121,13 +133,15 @@ impl crate::SysAttribute for PowerSupplyAttribute {
|
|||
Self::Technology => "technology",
|
||||
Self::VoltageAverage => "voltage_avg",
|
||||
Self::CycleCount => "cycle_count",
|
||||
Self::Custom(s) => s,
|
||||
};
|
||||
s.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// power_supply/<entity>/type attribute value
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "derive", derive(Debug))]
|
||||
pub enum PowerSupplyType {
|
||||
/// Battery
|
||||
Battery,
|
||||
|
@ -184,6 +198,7 @@ impl std::str::FromStr for PowerSupplyType {
|
|||
}
|
||||
|
||||
/// power_supply/<entity>/ directory
|
||||
#[cfg_attr(feature = "derive", derive(Debug, Clone))]
|
||||
pub struct PowerSupplyPath {
|
||||
inner: crate::BasicEntityPath,
|
||||
}
|
||||
|
@ -229,7 +244,7 @@ impl crate::SysEntity for PowerSupplyPath {
|
|||
}
|
||||
}
|
||||
|
||||
impl crate::SysEntityAttributes<PowerSupplyAttribute, String, <String as std::str::FromStr>::Err> for PowerSupplyPath {
|
||||
impl crate::SysEntityAttributes<PowerSupplyAttribute> for PowerSupplyPath {
|
||||
fn capabilities(&self) -> Vec<PowerSupplyAttribute> {
|
||||
self.inner.filter_capabilities(vec![
|
||||
PowerSupplyAttribute::Manufacturer,
|
||||
|
@ -278,6 +293,10 @@ mod tests {
|
|||
|
||||
#[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());
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::convert::AsRef;
|
||||
|
||||
use crate::SysEntity;
|
||||
use crate::{SysEntity, SysEntityAttributes};
|
||||
|
||||
/// sysfs root
|
||||
#[cfg_attr(feature = "derive", derive(Debug))]
|
||||
pub struct SysPath {
|
||||
root: PathBuf,
|
||||
}
|
||||
|
@ -35,16 +36,42 @@ impl SysPath {
|
|||
}
|
||||
|
||||
/// Find a hardware monitor entry by index
|
||||
pub fn hwmon_by_index(&self, index: u64) -> std::io::Result<crate::HwMonPath> {
|
||||
pub fn hwmon_by_index(&self, index: u64) -> crate::HwMonPath {
|
||||
let entry = crate::HwMonPath::entry(self, index);
|
||||
entry.attribute(crate::HwMonAttribute::name())?;
|
||||
Ok(entry)
|
||||
//entry.attribute(crate::HwMonAttribute::name())?;
|
||||
entry
|
||||
}
|
||||
|
||||
/// Find a hardware monitor by capabilities
|
||||
pub fn hwmon(&self, mut c: impl crate::capability::Capabilities<crate::HwMonAttribute, crate::HwMonAttribute>) -> std::io::Result<impl Iterator<Item=crate::HwMonPath>> {
|
||||
Ok(crate::HwMonPath::all(self.root.clone())?
|
||||
.filter_map(|p| p.ok())
|
||||
.filter(move |p| c.can(&p.capabilities())))
|
||||
}
|
||||
|
||||
/// Find a power supply entry by name
|
||||
pub fn power_supply(&self, name: &str) -> crate::PowerSupplyPath {
|
||||
pub fn power_supply_by_name(&self, name: &str) -> crate::PowerSupplyPath {
|
||||
crate::PowerSupplyPath::name(self, name)
|
||||
}
|
||||
|
||||
/// Find a power supply by capabilities
|
||||
pub fn power_supply(&self, mut c: impl crate::capability::Capabilities<crate::PowerSupplyAttribute, crate::PowerSupplyAttribute>) -> std::io::Result<impl Iterator<Item=crate::PowerSupplyPath>> {
|
||||
Ok(crate::PowerSupplyPath::all(self.root.clone())?
|
||||
.filter_map(|p| p.ok())
|
||||
.filter(move |p| c.can(&p.capabilities())))
|
||||
}
|
||||
|
||||
/// Find entities in a sysfs class by capabilities
|
||||
pub fn class(&self, class: impl AsRef<Path>, mut c: impl crate::capability::Capabilities<String, String>) -> std::io::Result<impl Iterator<Item=crate::BasicEntityPath>> {
|
||||
Ok(crate::BasicEntityPath::all(self.root.clone(), class)?
|
||||
.filter_map(|p| p.ok())
|
||||
.filter(move |p| c.can(&p.capabilities()))
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn from_entity_path(entity: impl AsRef<Path>) -> Option<Self> {
|
||||
Some(Self::path(entity.as_ref().parent()?.parent()?.parent()?.parent()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::default::Default for SysPath {
|
||||
|
@ -60,3 +87,23 @@ impl AsRef<Path> for SysPath {
|
|||
self.root.as_path()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::SysEntity;
|
||||
|
||||
#[test]
|
||||
fn syspath_root_recovery() -> std::io::Result<()> {
|
||||
let sys = crate::SysPath::default();
|
||||
let all_ent: Vec<_> = crate::BasicEntityPath::all(&sys, "hwmon")?.collect();
|
||||
assert!(!all_ent.is_empty());
|
||||
for p in all_ent.into_iter() {
|
||||
let p = p?;
|
||||
let root_opt = p.root();
|
||||
assert!(root_opt.is_some());
|
||||
assert_eq!(sys.as_ref(), root_opt.unwrap().as_ref());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue