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 /// Refreshes component.
273 ///
274 /// ```no_run
275 /// use sysinfo::Components;
276 ///
277 /// let mut components = Components::new_with_refreshed_list();
278 /// for component in components.iter_mut() {
279 /// component.refresh();
280 /// }
281 /// ```
282 pub fn refresh(&mut self) {
283 self.inner.refresh()
284 }
285}
286
287#[cfg(test)]
288mod tests {
289 use crate::*;
290
291 #[test]
292 fn test_components_mac_m1() {
293 let mut components = Components::new();
294 components.refresh(false);
295 components.refresh(false);
296 }
297}