Improve .attribute() parse type ergonomics
This commit is contained in:
parent
942d9f71e5
commit
481844408d
6 changed files with 26 additions and 16 deletions
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "sysfuss"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
edition = "2021"
|
||||
authors = ["NGnius (Graham) <ngniusness@gmail.com>"]
|
||||
description = "sysfs wrapper for convenience"
|
||||
|
|
|
@ -35,7 +35,7 @@ pub trait SysAttributeExt: SysAttribute {
|
|||
}
|
||||
|
||||
/// read and parse the attribute value
|
||||
fn parse<T: FromStr<Err=E>, E, ENT: crate::SysEntity + ?Sized>(&self, entity: &ENT) -> Result<T, EitherErr2<std::io::Error, E>> {
|
||||
fn parse<T: FromStr, ENT: crate::SysEntity + ?Sized>(&self, entity: &ENT) -> Result<T, EitherErr2<std::io::Error, <T as FromStr>::Err>> {
|
||||
let s = self.read_str(entity).map_err(EitherErr2::First)?;
|
||||
T::from_str(s.trim_end_matches('\n')).map_err(EitherErr2::Second)
|
||||
}
|
||||
|
|
11
src/basic.rs
11
src/basic.rs
|
@ -5,6 +5,7 @@ use std::io::Result as IoResult;
|
|||
const SYS_CLASS_PATH: &str = "sys/class";
|
||||
|
||||
/// Generic entity path with basic functionality
|
||||
#[derive(PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "derive", derive(Debug, Clone))]
|
||||
pub struct BasicEntityPath {
|
||||
path: PathBuf
|
||||
|
@ -73,6 +74,12 @@ impl crate::SysEntityAttributes<String> for BasicEntityPath {
|
|||
}
|
||||
}
|
||||
|
||||
impl <'a> crate::SysEntityAttributes<&'a str> for BasicEntityPath {
|
||||
fn capabilities(&self) -> Vec<&'a str> {
|
||||
panic!("Cannot read capabilities into &str")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -104,7 +111,7 @@ mod tests {
|
|||
"temp1_alarm".to_string(),
|
||||
"temp1_crit".to_string(),
|
||||
].into_iter()))?.next().expect("Missing any hwmon");
|
||||
let attr_value = crate::SysEntityAttributesExt::attribute::<String, _>(&basic, "name".to_owned()).expect("name capable but also incapable");
|
||||
let attr_value = crate::SysEntityAttributesExt::attribute::<String>(&basic, "name".to_owned()).expect("name capable but also incapable");
|
||||
println!("Attribute ./name = '{}'", attr_value);
|
||||
assert!(attr_value == "nvme");
|
||||
Ok(())
|
||||
|
@ -125,7 +132,7 @@ mod tests {
|
|||
"dev".to_string(),
|
||||
"uevent".to_string(),
|
||||
].into_iter()))?.filter(|basic| basic.name().expect("no name").starts_with("card")).next().expect("Missing drm");
|
||||
let attr_value = crate::SysEntityAttributesExt::attribute::<String, _>(&basic, "dev".to_owned()).expect("dev capable but also incapable");
|
||||
let attr_value = crate::SysEntityAttributesExt::attribute::<String>(&basic, "dev".to_owned()).expect("dev capable but also incapable");
|
||||
println!("Attribute ./dev = '{}'", attr_value);
|
||||
assert!(attr_value == expected_dev);
|
||||
Ok(())
|
||||
|
|
|
@ -38,7 +38,7 @@ pub trait SysEntity: AsRef<Path> {
|
|||
/// 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, T: std::str::FromStr>(&self, attr: A) -> Result<T, EitherErr2<std::io::Error, <T as std::str::FromStr>::Err>>;
|
||||
/// Get an attribute by filename in the entity's directory
|
||||
fn attribute_str<A: AsRef<Path>>(&self, attr: A) -> IoResult<String>;
|
||||
|
||||
|
@ -50,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, T: std::str::FromStr>(&self, attr: A) -> Result<T, EitherErr2<std::io::Error, <T as std::str::FromStr>::Err>> {
|
||||
attr.parse(self)
|
||||
}
|
||||
|
||||
|
@ -82,7 +82,7 @@ pub trait SysEntityAttributesExt<A: crate::SysAttribute>: SysEntityAttributes<A>
|
|||
}
|
||||
|
||||
/// 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>> {
|
||||
fn attribute<T: std::str::FromStr>(&self, attr: A) -> Result<T, EitherErr2<std::io::Error, <T as std::str::FromStr>::Err>> {
|
||||
attr.parse(self)
|
||||
}
|
||||
|
||||
|
|
16
src/hwmon.rs
16
src/hwmon.rs
|
@ -61,6 +61,8 @@ pub enum HwMonAttributeType {
|
|||
Fan,
|
||||
/// Current
|
||||
Curr,
|
||||
/// Frequency
|
||||
Freq,
|
||||
}
|
||||
|
||||
impl HwMonAttributeType {
|
||||
|
@ -70,6 +72,7 @@ impl HwMonAttributeType {
|
|||
Self::Temp => "out",
|
||||
Self::Fan => "fan",
|
||||
Self::Curr => "curr",
|
||||
Self::Freq => "freq",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,7 +207,7 @@ impl HwMonPath {
|
|||
pub(crate) fn name(root: &crate::SysPath, name: &str) -> IoResult<Option<Self>> {
|
||||
for entry in Self::all(root)? {
|
||||
let entry = entry?;
|
||||
let value: String = entry.attribute::<String, _>(HwMonAttribute::name()).map_err(|e| match e {
|
||||
let value: String = entry.attribute::<String>(HwMonAttribute::name()).map_err(|e| match e {
|
||||
crate::EitherErr2::First(e) => e,
|
||||
crate::EitherErr2::Second(_e) => panic!("Infallible"),
|
||||
})?;
|
||||
|
@ -269,8 +272,8 @@ mod tests {
|
|||
assert!(!all_hwmon.is_empty());
|
||||
for hwmon in all_hwmon.into_iter() {
|
||||
let hwmon = hwmon?;
|
||||
assert!(hwmon.attribute::<String, _>(HwMonAttribute::name()).map_err(|e| e.map_infallible_second())? != "");
|
||||
assert!(!hwmon.attribute::<String, _>(HwMonAttribute::name()).map_err(|e| e.map_infallible_second())?.ends_with("\n"));
|
||||
assert!(hwmon.attribute::<String>(HwMonAttribute::name()).map_err(|e| e.map_infallible_second())? != "");
|
||||
assert!(!hwmon.attribute::<String>(HwMonAttribute::name()).map_err(|e| e.map_infallible_second())?.ends_with("\n"));
|
||||
assert!(!hwmon.capabilities().is_empty());
|
||||
assert!(hwmon.capabilities().contains(&HwMonAttribute::name()))
|
||||
}
|
||||
|
@ -287,11 +290,10 @@ mod tests {
|
|||
}
|
||||
let hwmon = sys.hwmon(crate::capability::attributes([
|
||||
HwMonAttribute::name(),
|
||||
HwMonAttribute::new(HwMonAttributeType::Fan, 1, HwMonAttributeItem::Input),
|
||||
HwMonAttribute::new(HwMonAttributeType::Fan, 1, HwMonAttributeItem::Min),
|
||||
HwMonAttribute::new(HwMonAttributeType::Fan, 1, HwMonAttributeItem::Max)
|
||||
HwMonAttribute::new(HwMonAttributeType::In, 0, HwMonAttributeItem::Input),
|
||||
HwMonAttribute::new(HwMonAttributeType::In, 0, HwMonAttributeItem::Label),
|
||||
].into_iter()))?.next().expect("Missing capable amdgpu");
|
||||
assert_eq!(hwmon.attribute::<String, _>(HwMonAttribute::name()).expect("name capable but also incapable"), "amdgpu");
|
||||
assert_eq!(hwmon.attribute::<String>(HwMonAttribute::name()).expect("name capable but also incapable"), "amdgpu");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -197,6 +197,7 @@ impl std::str::FromStr for PowerSupplyType {
|
|||
}
|
||||
|
||||
/// power_supply/<entity>/ directory
|
||||
#[derive(PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "derive", derive(Debug, Clone))]
|
||||
pub struct PowerSupplyPath {
|
||||
inner: crate::BasicEntityPath,
|
||||
|
@ -293,7 +294,7 @@ mod tests {
|
|||
use super::*;
|
||||
use crate::SysEntityAttributes;
|
||||
use crate::SysEntityAttributesExt;
|
||||
use crate::SysAttribute;
|
||||
use crate::SysAttributeExt;
|
||||
|
||||
#[test]
|
||||
fn power_supply_all() -> std::io::Result<()> {
|
||||
|
@ -325,7 +326,7 @@ mod tests {
|
|||
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);
|
||||
assert!(psu.attribute::<PowerSupplyType>(PowerSupplyAttribute::Type).expect("type capable but also incapable") == PowerSupplyType::Battery);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue