Skip to main content

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