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}