1use std::path::{Path, PathBuf};
2use std::convert::AsRef;
3use std::io::Result as IoResult;
4
5const SYS_CLASS_PATH: &str = "sys/class";
6
7#[cfg_attr(feature = "derive", derive(Debug, Clone))]
9pub struct BasicEntityPath {
10 path: PathBuf
11}
12
13impl BasicEntityPath {
14 pub fn new(path: impl AsRef<Path>) -> Self {
16 Self {
17 path: path.as_ref().to_path_buf(),
18 }
19 }
20
21 pub(crate) fn all(root: impl AsRef<Path>, class: impl AsRef<Path>) -> IoResult<impl Iterator<Item=IoResult<Self>>> {
22 let dir_path = root.as_ref().join(SYS_CLASS_PATH).join(class);
23 Ok(dir_path.read_dir()?
24 .filter_map(
25 |entry| entry.map(
26 |entry| if entry.path().is_file() { None } else { Some(Self::new(entry.path())) }
27 ).transpose()))
28 }
29
30 pub fn filter_capabilities<A: crate::SysAttribute>(&self, attributes: impl Iterator<Item=A>) -> impl Iterator<Item=A> {
32 let found_attrs: Vec<PathBuf> = if let Ok(dir_iter) = self.path.read_dir() {
33 dir_iter.filter_map(
34 |entry| entry.ok().filter(|entry| entry.path().is_file()).map(|entry| PathBuf::from(entry.file_name()))
35 ).collect()
36 } else {
37 Vec::with_capacity(0)
38 };
39
40 attributes.filter(move |attr| found_attrs.contains(&attr.filename()))
41 }
42}
43
44impl AsRef<Path> for BasicEntityPath {
45 fn as_ref(&self) -> &Path {
46 self.path.as_path()
47 }
48}
49
50impl crate::SysEntity for BasicEntityPath {
51 fn to_entity_path(self) -> crate::EntityPath {
52 crate::EntityPath::Generic(self)
53 }
54
55 fn name(&self) -> IoResult<String> {
56 if let Some(s) = self.path.file_name().map(|name| name.to_str().map(|s| s.to_owned())).flatten() {
57 Ok(s)
58 } else {
59 Err(std::io::Error::from_raw_os_error(std::io::ErrorKind::InvalidInput as _))
60 }
61 }
62}
63
64impl crate::SysEntityAttributes<String> for BasicEntityPath {
65 fn capabilities(&self) -> Vec<String> {
66 if let Ok(dir_iter) = self.path.read_dir() {
67 dir_iter.filter_map(
68 |entry| entry.ok().filter(|entry| entry.path().is_file()).and_then(|entry| entry.file_name().to_str().map(|s| s.to_owned()))
69 ).collect()
70 } else {
71 Vec::with_capacity(0)
72 }
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use crate::SysEntity;
80 use crate::SysEntityRawExt;
81
82 #[test]
83 fn basic_entity_all() -> std::io::Result<()> {
84 let sys = crate::SysPath::default();
85 let all_basic: Vec<_> = BasicEntityPath::all(sys, "drm")?.collect();
86 assert!(!all_basic.is_empty());
87 for ent in all_basic.into_iter() {
88 assert!(ent?.attribute_str("uevent")? != "");
89 }
90 Ok(())
91 }
92
93 #[test]
94 fn basic_capabilities() -> std::io::Result<()> {
95 let sys = crate::SysPath::default();
96 if std::fs::read_to_string("/sys/class/hwmon/hwmon0/name")?.trim() != "nvme" {
97 eprintln!("basic entity test skipped since hwmon0 is not nvme (maybe running on a different PC?)");
100 return Ok(())
101 }
102 let basic = sys.class("hwmon", crate::capability::attributes([
103 "name".to_string(),
104 "temp1_alarm".to_string(),
105 "temp1_crit".to_string(),
106 ].into_iter()))?.next().expect("Missing any hwmon");
107 let attr_value = crate::SysEntityAttributesExt::attribute::<String, _>(&basic, "name".to_owned()).expect("name capable but also incapable");
108 println!("Attribute ./name = '{}'", attr_value);
109 assert!(attr_value == "nvme");
110 Ok(())
111 }
112
113 #[test]
114 fn basic_drm_capabilities() -> std::io::Result<()> {
115 let sys = crate::SysPath::default();
116 let expected_dev = if let Ok(dev) = std::fs::read_to_string("/sys/class/drm/card1/dev") {
117 dev.trim().to_owned()
118 } else {
119 eprintln!("basic entity test skipped since drm card0 does not exist (maybe running on a different PC?)");
122 return Ok(())
123 };
124 let basic = sys.class("drm", crate::capability::attributes([
125 "dev".to_string(),
126 "uevent".to_string(),
127 ].into_iter()))?.filter(|basic| basic.name().expect("no name").starts_with("card")).next().expect("Missing drm");
128 let attr_value = crate::SysEntityAttributesExt::attribute::<String, _>(&basic, "dev".to_owned()).expect("dev capable but also incapable");
129 println!("Attribute ./dev = '{}'", attr_value);
130 assert!(attr_value == expected_dev);
131 Ok(())
132 }
133}