sysinfo/common/
component.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use crate::{ComponentInner, ComponentsInner};
4
5/// Interacting with components.
6///
7/// ```no_run
8/// use sysinfo::Components;
9///
10/// let components = Components::new_with_refreshed_list();
11/// for component in &components {
12///     println!("{component:?}");
13/// }
14/// ```
15pub struct Components {
16    pub(crate) inner: ComponentsInner,
17}
18
19impl Default for Components {
20    fn default() -> Self {
21        Self::new()
22    }
23}
24
25impl From<Components> for Vec<Component> {
26    fn from(components: Components) -> Self {
27        components.inner.into_vec()
28    }
29}
30
31impl From<Vec<Component>> for Components {
32    fn from(components: Vec<Component>) -> Self {
33        Self {
34            inner: ComponentsInner::from_vec(components),
35        }
36    }
37}
38
39impl std::ops::Deref for Components {
40    type Target = [Component];
41
42    fn deref(&self) -> &Self::Target {
43        self.list()
44    }
45}
46
47impl std::ops::DerefMut for Components {
48    fn deref_mut(&mut self) -> &mut Self::Target {
49        self.list_mut()
50    }
51}
52
53impl<'a> IntoIterator for &'a Components {
54    type Item = &'a Component;
55    type IntoIter = std::slice::Iter<'a, Component>;
56
57    fn into_iter(self) -> Self::IntoIter {
58        self.list().iter()
59    }
60}
61
62impl<'a> IntoIterator for &'a mut Components {
63    type Item = &'a mut Component;
64    type IntoIter = std::slice::IterMut<'a, Component>;
65
66    fn into_iter(self) -> Self::IntoIter {
67        self.list_mut().iter_mut()
68    }
69}
70
71impl Components {
72    /// Creates a new empty [`Components`][crate::Components] type.
73    ///
74    /// If you want it to be filled directly, take a look at
75    /// [`Components::new_with_refreshed_list`].
76    ///
77    /// ```no_run
78    /// use sysinfo::Components;
79    ///
80    /// let mut components = Components::new();
81    /// components.refresh(false);
82    /// for component in &components {
83    ///     println!("{component:?}");
84    /// }
85    /// ```
86    pub fn new() -> Self {
87        Self {
88            inner: ComponentsInner::new(),
89        }
90    }
91
92    /// Creates a new [`Components`][crate::Components] type with the components list
93    /// loaded.
94    ///
95    /// ```no_run
96    /// use sysinfo::Components;
97    ///
98    /// let mut components = Components::new_with_refreshed_list();
99    /// for component in components.list() {
100    ///     println!("{component:?}");
101    /// }
102    /// ```
103    pub fn new_with_refreshed_list() -> Self {
104        let mut components = Self::new();
105        components.refresh(true);
106        components
107    }
108
109    /// Returns the components list.
110    ///
111    /// ```no_run
112    /// use sysinfo::Components;
113    ///
114    /// let components = Components::new_with_refreshed_list();
115    /// for component in components.list() {
116    ///     println!("{component:?}");
117    /// }
118    /// ```
119    pub fn list(&self) -> &[Component] {
120        self.inner.list()
121    }
122
123    /// Returns the components list.
124    ///
125    /// ```no_run
126    /// use sysinfo::Components;
127    ///
128    /// let mut components = Components::new_with_refreshed_list();
129    /// for component in components.list_mut() {
130    ///     component.refresh();
131    ///     println!("{component:?}");
132    /// }
133    /// ```
134    pub fn list_mut(&mut self) -> &mut [Component] {
135        self.inner.list_mut()
136    }
137
138    /// Refreshes the components list.
139    ///
140    /// ```no_run
141    /// use sysinfo::Components;
142    ///
143    /// let mut components = Components::new_with_refreshed_list();
144    /// // We wait some time...?
145    /// components.refresh(false);
146    /// ```
147    pub fn refresh(&mut self, remove_not_listed_components: bool) {
148        self.inner.refresh();
149        if remove_not_listed_components {
150            // Remove interfaces which are gone.
151            self.inner.components.retain_mut(|c| {
152                if !c.inner.updated {
153                    return false;
154                }
155                c.inner.updated = false;
156                true
157            });
158        }
159    }
160}
161
162/// Getting a component temperature information.
163///
164/// ```no_run
165/// use sysinfo::Components;
166///
167/// let components = Components::new_with_refreshed_list();
168/// for component in &components {
169///     if let Some(temperature) = component.temperature() {
170///         println!("{} {temperature}°C", component.label());
171///     } else {
172///         println!("{} (unknown temperature)", component.label());
173///     }
174/// }
175/// ```
176pub struct Component {
177    pub(crate) inner: ComponentInner,
178}
179
180impl Component {
181    /// Returns the temperature of the component (in celsius degree).
182    ///
183    /// ## Linux
184    ///
185    /// Returns `f32::NAN` if it failed to retrieve it.
186    ///
187    /// ```no_run
188    /// use sysinfo::Components;
189    ///
190    /// let components = Components::new_with_refreshed_list();
191    /// for component in &components {
192    ///     if let Some(temperature) = component.temperature() {
193    ///         println!("{temperature}°C");
194    ///     }
195    /// }
196    /// ```
197    pub fn temperature(&self) -> Option<f32> {
198        self.inner.temperature()
199    }
200
201    /// Returns the maximum temperature of the component (in celsius degree).
202    ///
203    /// Note: if `temperature` is higher than the current `max`,
204    /// `max` value will be updated on refresh.
205    ///
206    /// ## Linux
207    ///
208    /// May be computed by `sysinfo` from kernel.
209    /// Returns `f32::NAN` if it failed to retrieve it.
210    ///
211    /// ```no_run
212    /// use sysinfo::Components;
213    ///
214    /// let components = Components::new_with_refreshed_list();
215    /// for component in &components {
216    ///     if let Some(max) = component.max() {
217    ///         println!("{max}°C");
218    ///     }
219    /// }
220    /// ```
221    pub fn max(&self) -> Option<f32> {
222        self.inner.max()
223    }
224
225    /// Returns the highest temperature before the component halts (in celsius degree).
226    ///
227    /// ## Linux
228    ///
229    /// Critical threshold defined by chip or kernel.
230    ///
231    /// ```no_run
232    /// use sysinfo::Components;
233    ///
234    /// let components = Components::new_with_refreshed_list();
235    /// for component in &components {
236    ///     if let Some(critical) = component.critical() {
237    ///         println!("{critical}°C");
238    ///     }
239    /// }
240    /// ```
241    pub fn critical(&self) -> Option<f32> {
242        self.inner.critical()
243    }
244
245    /// Returns the label of the component.
246    ///
247    /// ## Linux
248    ///
249    /// Since components information is retrieved thanks to `hwmon`,
250    /// the labels are generated as follows.
251    /// Note: it may change and it was inspired by `sensors` own formatting.
252    ///
253    /// | name | label | device_model | id_sensor | Computed label by `sysinfo` |
254    /// |---------|--------|------------|----------|----------------------|
255    /// | ✓    | ✓    | ✓  | ✓ | `"{name} {label} {device_model}"` |
256    /// | ✓    | ✓    | ✗  | ✓ | `"{name} {label}"` |
257    /// | ✓    | ✗    | ✓  | ✓ | `"{name} {device_model}"` |
258    /// | ✓    | ✗    | ✗  | ✓ | `"{name} temp{id}"` |
259    ///
260    /// ```no_run
261    /// use sysinfo::Components;
262    ///
263    /// let components = Components::new_with_refreshed_list();
264    /// for component in &components {
265    ///     println!("{}", component.label());
266    /// }
267    /// ```
268    pub fn label(&self) -> &str {
269        self.inner.label()
270    }
271
272    /// Returns the identifier of the component.
273    ///
274    /// Note: The identifier should be reasonably unique but is provided by the kernel.
275    /// It could change if the hardware changes or after a reboot.
276    ///
277    /// | OS | Computed ID by `sysinfo` | Example |
278    /// |----|--------------------------|----------|
279    /// | Linux/hwmon | hwmon file concatenated with the temp index. | ` hwmon0_1` if the temperature data comes from the `hwmon0/temp1_input` file. |
280    /// | Linux/thermal | thermal file name | `thermal_zone0` |
281    /// | FreeBSD | `cpu_` concatenated with the core index. | `cpu_1` for the first core. |
282    /// | macOS/arm | Serial ID reported by the HID driver. | |
283    /// | macOS/x86 | Technical ID sent to the OS (see below) | `TXCX` |
284    /// | Windows | `Computer` (same as the label) | `Computer` |
285    /// | appstore | Components are not available | None |
286    /// | unknown | Components are not available | None |
287    ///
288    /// For macOS on X86 the following identifiers are possible:
289    /// - `TXCX` or `TXCx` for PECI CPU (depending on if run on iMac or MacBook)
290    /// - `TC0P` for CPU Proximity
291    /// - `TG0P` for GPU
292    /// - `TB0T` for Battery
293    ///
294    /// ```no_run
295    /// use sysinfo::Components;
296    ///
297    /// let components = Components::new_with_refreshed_list();
298    /// for component in &components {
299    ///     if let Some(id) = component.id() {
300    ///         println!("{id}");
301    ///     }
302    /// }
303    /// ```
304    pub fn id(&self) -> Option<&str> {
305        self.inner.id()
306    }
307
308    /// Refreshes component.
309    ///
310    /// ```no_run
311    /// use sysinfo::Components;
312    ///
313    /// let mut components = Components::new_with_refreshed_list();
314    /// for component in components.iter_mut() {
315    ///     component.refresh();
316    /// }
317    /// ```
318    pub fn refresh(&mut self) {
319        self.inner.refresh()
320    }
321}
322
323#[cfg(test)]
324mod tests {
325    use crate::*;
326
327    #[test]
328    fn test_components_mac_m1() {
329        let mut components = Components::new();
330        components.refresh(false);
331        components.refresh(false);
332    }
333}