1#![deny(missing_docs)]
24
25use std::fs;
26use std::io;
27use std::path::{Path, PathBuf};
28
29pub const BACKLIGHT_PATH: &str = "/sys/class/backlight";
33
34pub const BL_POWER: &str = "bl_power";
38
39#[derive(Debug)]
52pub struct Device {
53 path: PathBuf,
54 bl_power: PathBuf,
55}
56
57impl Device {
58 pub fn new<P: AsRef<Path>>(path: P) -> Self {
60 let path: &Path = path.as_ref();
61 Self {
62 path: path.to_path_buf(),
63 bl_power: path.join(BL_POWER),
64 }
65 }
66
67 #[allow(unused)]
69 fn custom<P: AsRef<Path>, Q: AsRef<Path>>(path: P, bl_power: Option<Q>) -> Self {
70 let path: &Path = path.as_ref();
71 match bl_power {
72 Some(q) => Device {
73 path: path.to_path_buf(),
74 bl_power: path.join(q),
75 },
76 None => Device {
77 path: path.to_path_buf(),
78 bl_power: path.join(BL_POWER),
79 },
80 }
81 }
82
83 pub fn path(&self) -> &Path {
85 &self.path
86 }
87
88 pub fn bl_power(&self) -> &Path {
90 &self.bl_power
91 }
92
93 pub fn toggle(&self) -> io::Result<i32> {
99 let old_value = read_i32(&self.bl_power)?;
100 let new_value = if old_value == 0 { 1 } else { 0 };
101 write_i32(&self.bl_power, new_value)?;
102 Ok(new_value)
103 }
104}
105
106pub struct DeviceIter {
108 readdir: Option<fs::ReadDir>,
109}
110
111impl DeviceIter {
112 pub fn new<P: AsRef<Path>>(path: P) -> Self {
114 let readdir = match fs::read_dir(&path) {
115 Ok(iter) => Some(iter),
116 Err(_) => None,
117 };
118 Self { readdir }
119 }
120}
121
122impl Default for DeviceIter {
123 fn default() -> Self {
124 Self::new(Path::new(BACKLIGHT_PATH))
125 }
126}
127
128impl Iterator for DeviceIter {
129 type Item = Device;
130
131 fn next(&mut self) -> Option<Self::Item> {
132 match self.readdir {
133 Some(ref mut diriter) => diriter
134 .filter(|entry| entry.is_ok())
135 .map(|entry| entry.unwrap().path())
136 .find(|path| bl_power(path).is_file())
137 .map(|p| Device::new(&p)),
138 _ => None,
139 }
140 }
141}
142
143pub fn iterate_devices<P: AsRef<Path>>(dir: P) -> io::Result<impl Iterator<Item = Device>> {
152 let diriter = fs::read_dir(dir)?;
153 Ok(diriter
154 .filter(|entry| entry.is_ok())
155 .map(|entry| entry.unwrap().path())
156 .filter(|path| bl_power(path).is_file())
157 .map(|p| Device::new(&p)))
158}
159
160fn bl_power(path: &Path) -> PathBuf {
161 path.join(BL_POWER)
162}
163
164fn read_i32(path: &Path) -> io::Result<i32> {
165 fs::read_to_string(path)?
166 .trim()
167 .parse::<i32>()
168 .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "cannot parse i32"))
169}
170
171fn write_i32(path: &Path, value: i32) -> io::Result<()> {
172 fs::write(path, value.to_string())
173}