sysinfo/common/disk.rs
1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::ffi::OsStr;
4use std::fmt;
5use std::path::Path;
6
7use crate::common::impl_get_set::impl_get_set;
8use crate::DiskUsage;
9
10/// Struct containing a disk information.
11///
12/// ```no_run
13/// use sysinfo::Disks;
14///
15/// let disks = Disks::new_with_refreshed_list();
16/// for disk in disks.list() {
17/// println!("{:?}: {:?}", disk.name(), disk.kind());
18/// }
19/// ```
20pub struct Disk {
21 pub(crate) inner: crate::DiskInner,
22}
23
24impl Disk {
25 /// Returns the kind of disk.
26 ///
27 /// ```no_run
28 /// use sysinfo::Disks;
29 ///
30 /// let disks = Disks::new_with_refreshed_list();
31 /// for disk in disks.list() {
32 /// println!("[{:?}] {:?}", disk.name(), disk.kind());
33 /// }
34 /// ```
35 pub fn kind(&self) -> DiskKind {
36 self.inner.kind()
37 }
38
39 /// Returns the disk name.
40 ///
41 /// ```no_run
42 /// use sysinfo::Disks;
43 ///
44 /// let disks = Disks::new_with_refreshed_list();
45 /// for disk in disks.list() {
46 /// println!("{:?}", disk.name());
47 /// }
48 /// ```
49 pub fn name(&self) -> &OsStr {
50 self.inner.name()
51 }
52
53 /// Returns the file system used on this disk (so for example: `EXT4`, `NTFS`, etc...).
54 ///
55 /// ```no_run
56 /// use sysinfo::Disks;
57 ///
58 /// let disks = Disks::new_with_refreshed_list();
59 /// for disk in disks.list() {
60 /// println!("[{:?}] {:?}", disk.name(), disk.file_system());
61 /// }
62 /// ```
63 pub fn file_system(&self) -> &OsStr {
64 self.inner.file_system()
65 }
66
67 /// Returns the mount point of the disk (`/` for example).
68 ///
69 /// ```no_run
70 /// use sysinfo::Disks;
71 ///
72 /// let disks = Disks::new_with_refreshed_list();
73 /// for disk in disks.list() {
74 /// println!("[{:?}] {:?}", disk.name(), disk.mount_point());
75 /// }
76 /// ```
77 pub fn mount_point(&self) -> &Path {
78 self.inner.mount_point()
79 }
80
81 /// Returns the total disk size, in bytes.
82 ///
83 /// ```no_run
84 /// use sysinfo::Disks;
85 ///
86 /// let disks = Disks::new_with_refreshed_list();
87 /// for disk in disks.list() {
88 /// println!("[{:?}] {}B", disk.name(), disk.total_space());
89 /// }
90 /// ```
91 pub fn total_space(&self) -> u64 {
92 self.inner.total_space()
93 }
94
95 /// Returns the available disk size, in bytes.
96 ///
97 /// ```no_run
98 /// use sysinfo::Disks;
99 ///
100 /// let disks = Disks::new_with_refreshed_list();
101 /// for disk in disks.list() {
102 /// println!("[{:?}] {}B", disk.name(), disk.available_space());
103 /// }
104 /// ```
105 pub fn available_space(&self) -> u64 {
106 self.inner.available_space()
107 }
108
109 /// Returns `true` if the disk is removable.
110 ///
111 /// ```no_run
112 /// use sysinfo::Disks;
113 ///
114 /// let disks = Disks::new_with_refreshed_list();
115 /// for disk in disks.list() {
116 /// println!("[{:?}] {}", disk.name(), disk.is_removable());
117 /// }
118 /// ```
119 pub fn is_removable(&self) -> bool {
120 self.inner.is_removable()
121 }
122
123 /// Returns `true` if the disk is read-only.
124 ///
125 /// ```no_run
126 /// use sysinfo::Disks;
127 ///
128 /// let disks = Disks::new_with_refreshed_list();
129 /// for disk in disks.list() {
130 /// println!("[{:?}] is read-only: {}", disk.name(), disk.is_read_only());
131 /// }
132 /// ```
133 pub fn is_read_only(&self) -> bool {
134 self.inner.is_read_only()
135 }
136
137 /// Updates the disk' information with everything loaded.
138 ///
139 /// Equivalent to <code>[Disk::refresh_specifics]\([DiskRefreshKind::everything]\())</code>.
140 ///
141 /// ```no_run
142 /// use sysinfo::Disks;
143 ///
144 /// let mut disks = Disks::new_with_refreshed_list();
145 /// for disk in disks.list_mut() {
146 /// disk.refresh();
147 /// }
148 /// ```
149 pub fn refresh(&mut self) -> bool {
150 self.refresh_specifics(DiskRefreshKind::everything())
151 }
152
153 /// Updates the disk's information corresponding to the given [`DiskRefreshKind`].
154 ///
155 /// ```no_run
156 /// use sysinfo::{Disks, DiskRefreshKind};
157 ///
158 /// let mut disks = Disks::new_with_refreshed_list();
159 /// for disk in disks.list_mut() {
160 /// disk.refresh_specifics(DiskRefreshKind::nothing());
161 /// }
162 /// ```
163 pub fn refresh_specifics(&mut self, refreshes: DiskRefreshKind) -> bool {
164 self.inner.refresh_specifics(refreshes)
165 }
166
167 /// Returns number of bytes read and written by the disk
168 ///
169 /// ```no_run
170 /// use sysinfo::Disks;
171 ///
172 /// let disks = Disks::new_with_refreshed_list();
173 /// for disk in disks.list() {
174 /// println!("[{:?}] disk usage: {:?}", disk.name(), disk.usage());
175 /// }
176 /// ```
177 pub fn usage(&self) -> DiskUsage {
178 self.inner.usage()
179 }
180}
181
182/// Disks interface.
183///
184/// ```no_run
185/// use sysinfo::Disks;
186///
187/// let disks = Disks::new_with_refreshed_list();
188/// for disk in disks.list() {
189/// println!("{disk:?}");
190/// }
191/// ```
192///
193/// ⚠️ Note that tmpfs mounts are excluded by default under Linux.
194/// To display tmpfs mount points, the `linux-tmpfs` feature must be enabled.
195///
196/// ⚠️ Note that network devices are excluded by default under Linux.
197/// To display mount points using the CIFS and NFS protocols, the `linux-netdevs`
198/// feature must be enabled. Note, however, that sysinfo may hang under certain
199/// circumstances. For example, if a CIFS or NFS share has been mounted with
200/// the _hard_ option, but the connection has an error, such as the share server has stopped.
201pub struct Disks {
202 inner: crate::DisksInner,
203}
204
205impl Default for Disks {
206 fn default() -> Self {
207 Self::new()
208 }
209}
210
211impl From<Disks> for Vec<Disk> {
212 fn from(disks: Disks) -> Vec<Disk> {
213 disks.inner.into_vec()
214 }
215}
216
217impl From<Vec<Disk>> for Disks {
218 fn from(disks: Vec<Disk>) -> Self {
219 Self {
220 inner: crate::DisksInner::from_vec(disks),
221 }
222 }
223}
224
225impl<'a> IntoIterator for &'a Disks {
226 type Item = &'a Disk;
227 type IntoIter = std::slice::Iter<'a, Disk>;
228
229 fn into_iter(self) -> Self::IntoIter {
230 self.list().iter()
231 }
232}
233
234impl<'a> IntoIterator for &'a mut Disks {
235 type Item = &'a mut Disk;
236 type IntoIter = std::slice::IterMut<'a, Disk>;
237
238 fn into_iter(self) -> Self::IntoIter {
239 self.list_mut().iter_mut()
240 }
241}
242
243impl Disks {
244 /// Creates a new empty [`Disks`][crate::Disks] type.
245 ///
246 /// If you want it to be filled directly, take a look at [`Disks::new_with_refreshed_list`].
247 ///
248 /// ```no_run
249 /// use sysinfo::Disks;
250 ///
251 /// let mut disks = Disks::new();
252 /// disks.refresh(false);
253 /// for disk in disks.list() {
254 /// println!("{disk:?}");
255 /// }
256 /// ```
257 pub fn new() -> Self {
258 Self {
259 inner: crate::DisksInner::new(),
260 }
261 }
262
263 /// Creates a new [`Disks`][crate::Disks] type with the disk list loaded.
264 ///
265 /// Equivalent to <code>[Disks::new_with_refreshed_list_specifics]\([DiskRefreshKind::everything]\())</code>.
266 ///
267 /// ```no_run
268 /// use sysinfo::Disks;
269 ///
270 /// let mut disks = Disks::new_with_refreshed_list();
271 /// for disk in disks.list() {
272 /// println!("{disk:?}");
273 /// }
274 /// ```
275 pub fn new_with_refreshed_list() -> Self {
276 Self::new_with_refreshed_list_specifics(DiskRefreshKind::everything())
277 }
278
279 /// Creates a new [`Disks`][crate::Disks] type with the disk list loaded
280 /// and refreshed according to the given [`DiskRefreshKind`].
281 ///
282 /// ```no_run
283 /// use sysinfo::{Disks, DiskRefreshKind};
284 ///
285 /// let mut disks = Disks::new_with_refreshed_list_specifics(DiskRefreshKind::nothing());
286 /// for disk in disks.list() {
287 /// println!("{disk:?}");
288 /// }
289 /// ```
290 pub fn new_with_refreshed_list_specifics(refreshes: DiskRefreshKind) -> Self {
291 let mut disks = Self::new();
292 disks.refresh_specifics(false, refreshes);
293 disks
294 }
295
296 /// Returns the disks list.
297 ///
298 /// ```no_run
299 /// use sysinfo::Disks;
300 ///
301 /// let disks = Disks::new_with_refreshed_list();
302 /// for disk in disks.list() {
303 /// println!("{disk:?}");
304 /// }
305 /// ```
306 pub fn list(&self) -> &[Disk] {
307 self.inner.list()
308 }
309
310 /// Returns the disks list.
311 ///
312 /// ```no_run
313 /// use sysinfo::Disks;
314 ///
315 /// let mut disks = Disks::new_with_refreshed_list();
316 /// for disk in disks.list_mut() {
317 /// disk.refresh();
318 /// println!("{disk:?}");
319 /// }
320 /// ```
321 pub fn list_mut(&mut self) -> &mut [Disk] {
322 self.inner.list_mut()
323 }
324
325 /// Refreshes the listed disks' information.
326 ///
327 /// Equivalent to <code>[Disks::refresh_specifics]\([DiskRefreshKind::everything]\())</code>.
328 pub fn refresh(&mut self, remove_not_listed_disks: bool) {
329 self.inner
330 .refresh_specifics(remove_not_listed_disks, DiskRefreshKind::everything());
331 }
332
333 /// Refreshes the disks' information according to the given [`DiskRefreshKind`].
334 ///
335 /// ```no_run
336 /// use sysinfo::Disks;
337 ///
338 /// let mut disks = Disks::new_with_refreshed_list();
339 /// // We wait some time...?
340 /// disks.refresh(true);
341 /// ```
342 pub fn refresh_specifics(&mut self, remove_not_listed_disks: bool, refreshes: DiskRefreshKind) {
343 self.inner
344 .refresh_specifics(remove_not_listed_disks, refreshes);
345 }
346}
347
348impl std::ops::Deref for Disks {
349 type Target = [Disk];
350
351 fn deref(&self) -> &Self::Target {
352 self.list()
353 }
354}
355
356impl std::ops::DerefMut for Disks {
357 fn deref_mut(&mut self) -> &mut Self::Target {
358 self.list_mut()
359 }
360}
361
362/// Enum containing the different supported kinds of disks.
363///
364/// This type is returned by [`Disk::kind`](`crate::Disk::kind`).
365///
366/// ```no_run
367/// use sysinfo::Disks;
368///
369/// let disks = Disks::new_with_refreshed_list();
370/// for disk in disks.list() {
371/// println!("{:?}: {:?}", disk.name(), disk.kind());
372/// }
373/// ```
374#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
375#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
376pub enum DiskKind {
377 /// HDD type.
378 HDD,
379 /// SSD type.
380 SSD,
381 /// Unknown type.
382 Unknown(isize),
383}
384
385impl fmt::Display for DiskKind {
386 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
387 f.write_str(match *self {
388 DiskKind::HDD => "HDD",
389 DiskKind::SSD => "SSD",
390 _ => "Unknown",
391 })
392 }
393}
394
395/// Used to determine what you want to refresh specifically on the [`Disk`] type.
396///
397/// * `kind` is about refreshing the [`Disk::kind`] information.
398/// * `storage` is about refreshing the [`Disk::available_space`] and [`Disk::total_space`] information.
399/// * `io_usage` is about refreshing the [`Disk::usage`] information.
400///
401/// ```no_run
402/// use sysinfo::{Disks, DiskRefreshKind};
403///
404/// let mut disks = Disks::new_with_refreshed_list_specifics(DiskRefreshKind::everything());
405///
406/// for disk in disks.list() {
407/// assert!(disk.total_space() != 0);
408/// }
409/// ```
410#[derive(Clone, Copy, Debug, Default)]
411pub struct DiskRefreshKind {
412 kind: bool,
413 storage: bool,
414 io_usage: bool,
415}
416
417impl DiskRefreshKind {
418 /// Creates a new `DiskRefreshKind` with every refresh set to false.
419 ///
420 /// ```
421 /// use sysinfo::DiskRefreshKind;
422 ///
423 /// let r = DiskRefreshKind::nothing();
424 ///
425 /// assert_eq!(r.kind(), false);
426 /// assert_eq!(r.storage(), false);
427 /// assert_eq!(r.io_usage(), false);
428 /// ```
429 pub fn nothing() -> Self {
430 Self::default()
431 }
432
433 /// Creates a new `DiskRefreshKind` with every refresh set to true.
434 ///
435 /// ```
436 /// use sysinfo::DiskRefreshKind;
437 ///
438 /// let r = DiskRefreshKind::everything();
439 ///
440 /// assert_eq!(r.kind(), true);
441 /// assert_eq!(r.storage(), true);
442 /// assert_eq!(r.io_usage(), true);
443 /// ```
444 pub fn everything() -> Self {
445 Self {
446 kind: true,
447 storage: true,
448 io_usage: true,
449 }
450 }
451
452 impl_get_set!(DiskRefreshKind, kind, with_kind, without_kind);
453 impl_get_set!(DiskRefreshKind, storage, with_storage, without_storage);
454 impl_get_set!(DiskRefreshKind, io_usage, with_io_usage, without_io_usage);
455}
456
457#[cfg(test)]
458mod tests {
459 /// This first doctest ensure that we can create a new `Disks`.
460 ///
461 /// ```
462 /// let x = sysinfo::Disks::new();
463 /// ```
464 ///
465 /// This second doctest ensures that `Disks` doesn't implement `Clone`.
466 ///
467 /// ```compile_fail
468 /// let x = sysinfo::Disks::new();
469 /// x.clone();
470 /// ```
471 #[test]
472 fn check_if_disks_is_send() {
473 fn is_send<T: Send>(_: &T) {}
474
475 let disks = crate::Disks::new();
476 is_send(&disks);
477 }
478}