1#[cfg(test)]
4mod tests;
5
6use alloc::ffi::CString;
7use core::ffi::CStr;
8use core::ffi::{c_int, c_uint};
9use core::fmt;
10use std::io;
11
12use sensors_sys::sensors_feature_type::{
13 SENSORS_FEATURE_BEEP_ENABLE, SENSORS_FEATURE_CURR, SENSORS_FEATURE_ENERGY, SENSORS_FEATURE_FAN,
14 SENSORS_FEATURE_HUMIDITY, SENSORS_FEATURE_IN, SENSORS_FEATURE_INTRUSION, SENSORS_FEATURE_POWER,
15 SENSORS_FEATURE_TEMP, SENSORS_FEATURE_UNKNOWN, SENSORS_FEATURE_VID,
16};
17use sensors_sys::{
18 sensors_feature, sensors_get_features, sensors_get_label, sensors_get_subfeature,
19};
20
21use crate::chip::ChipRef;
22use crate::errors::{Error, Result};
23use crate::sub_feature::SubFeatureRef;
24use crate::utils::API_ACCESS_LOCK;
25
26#[derive(Debug, Clone, Copy, Eq)]
31pub struct FeatureRef<'sensors> {
32 pub(crate) chip: ChipRef<'sensors>,
33 pub(crate) raw: &'sensors sensors_feature,
34}
35
36impl<'sensors> FeatureRef<'sensors> {
37 #[must_use]
39 pub fn raw_ref(self) -> &'sensors sensors_feature {
40 self.raw
41 }
42
43 #[must_use]
45 pub fn chip(self) -> ChipRef<'sensors> {
46 self.chip
47 }
48
49 #[must_use]
51 pub fn name(self) -> Option<Result<&'sensors str>> {
52 self.raw_name()
53 .map(|name| name.to_str().map_err(Into::into))
54 }
55
56 pub fn label(self) -> Result<String> {
58 self.raw_label()?.into_string().map_err(Into::into)
59 }
60
61 #[must_use]
63 pub fn number(self) -> c_int {
64 self.raw.number
65 }
66
67 #[must_use]
69 pub fn kind(self) -> Option<Kind> {
70 Kind::from_raw(self.raw_kind())
71 }
72
73 pub fn sub_feature_by_kind(self, kind: crate::value::Kind) -> Result<SubFeatureRef<'sensors>> {
76 self.sub_feature_by_raw_kind(c_uint::from(kind))
77 }
78
79 pub fn sub_feature_iter(self) -> crate::sub_feature::Iter<'sensors> {
82 crate::sub_feature::Iter {
83 feature: self,
84 state: 0,
85 }
86 }
87
88 #[must_use]
90 pub fn raw_name(self) -> Option<&'sensors CStr> {
91 (!self.raw.name.is_null()).then(|| unsafe { CStr::from_ptr(self.raw.name) })
93 }
94
95 pub fn raw_label(self) -> Result<CString> {
101 let label = {
102 let _guard = API_ACCESS_LOCK.lock();
103 unsafe { sensors_get_label(self.chip.raw_ref(), self.raw) }
105 };
106
107 if label.is_null() {
108 let err = io::ErrorKind::InvalidInput.into();
109 Err(Error::from_io("sensors_get_label()", err))
110 } else {
111 Ok(unsafe {
113 let result = CString::from(CStr::from_ptr(label));
114 libc::free(label.cast());
115 result
116 })
117 }
118 }
119
120 #[must_use]
125 pub fn raw_kind(self) -> c_uint {
126 self.raw.type_
127 }
128
129 pub fn sub_feature_by_raw_kind(self, kind: c_uint) -> Result<SubFeatureRef<'sensors>> {
136 let sub_feature = {
137 let _guard = API_ACCESS_LOCK.lock();
138 unsafe { sensors_get_subfeature(self.chip.raw_ref(), self.raw, kind).as_ref() }
140 };
141
142 sub_feature
143 .map(|raw| SubFeatureRef { feature: self, raw })
144 .ok_or_else(|| {
145 let err = io::ErrorKind::NotFound.into();
146 Error::from_io("sensors_get_subfeature", err)
147 })
148 }
149}
150
151impl PartialEq for FeatureRef<'_> {
152 fn eq(&self, other: &Self) -> bool {
153 self.chip == other.chip
154 && self.number() == other.number()
155 && self.raw_kind() == other.raw_kind()
156 && self.raw_name() == other.raw_name()
157 }
158}
159
160impl fmt::Display for FeatureRef<'_> {
161 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162 if let Ok(label) = self.raw_label() {
163 write!(f, "{}", label.to_string_lossy())
164 } else {
165 write!(f, "\u{fffd}")
166 }
167 }
168}
169
170#[allow(missing_docs)] #[repr(u32)]
173#[non_exhaustive]
174#[derive(
175 Debug,
176 Clone,
177 Copy,
178 PartialEq,
179 Eq,
180 PartialOrd,
181 Ord,
182 num_enum::TryFromPrimitive,
183 num_enum::IntoPrimitive,
184)]
185pub enum Kind {
186 Voltage = SENSORS_FEATURE_IN,
187 Fan = SENSORS_FEATURE_FAN,
188 Temperature = SENSORS_FEATURE_TEMP,
189 Power = SENSORS_FEATURE_POWER,
190 Energy = SENSORS_FEATURE_ENERGY,
191 Current = SENSORS_FEATURE_CURR,
192 Humidity = SENSORS_FEATURE_HUMIDITY,
193 VoltageID = SENSORS_FEATURE_VID,
195 Intrusion = SENSORS_FEATURE_INTRUSION,
196 BeepEnable = SENSORS_FEATURE_BEEP_ENABLE,
198 Unknown = SENSORS_FEATURE_UNKNOWN,
200}
201
202impl Kind {
203 #[must_use]
206 pub fn from_raw(kind: c_uint) -> Option<Self> {
207 Self::try_from(kind).ok()
208 }
209
210 #[must_use]
213 pub fn as_raw(self) -> c_uint {
214 self.into()
215 }
216}
217
218impl Default for Kind {
219 fn default() -> Self {
220 Self::Unknown
221 }
222}
223
224impl fmt::Display for Kind {
225 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
226 match *self {
227 Self::Voltage => write!(f, "Voltage"),
228 Self::Fan => write!(f, "Fan"),
229 Self::Temperature => write!(f, "Temperature"),
230 Self::Power => write!(f, "Power"),
231 Self::Energy => write!(f, "Energy"),
232 Self::Current => write!(f, "Current"),
233 Self::Humidity => write!(f, "Humidity"),
234 Self::VoltageID => write!(f, "VoltageID"),
235 Self::Intrusion => write!(f, "Intrusion"),
236 Self::BeepEnable => write!(f, "BeepEnable"),
237 Self::Unknown => write!(f, "Unknown"),
238 }
239 }
240}
241
242#[derive(Debug)]
244#[must_use]
245pub struct Iter<'sensors> {
246 pub(crate) chip: ChipRef<'sensors>,
247 pub(crate) state: c_int,
248}
249
250impl<'sensors> Iterator for Iter<'sensors> {
251 type Item = FeatureRef<'sensors>;
252
253 fn next(&mut self) -> Option<Self::Item> {
255 let feature = {
256 let _guard = API_ACCESS_LOCK.lock();
257 unsafe { sensors_get_features(self.chip.raw_ref(), &mut self.state).as_ref() }
259 };
260
261 feature.map(|raw| FeatureRef {
262 chip: self.chip,
263 raw,
264 })
265 }
266}