1#![warn(clippy::all, missing_docs, nonstandard_style, future_incompatible)]
22
23#[derive(Debug)]
25pub struct Df(pub Vec<DfLine>);
26
27#[derive(Debug)]
29pub struct DfLine {
30 pub filesystem: String,
32 pub mounted: String,
34 pub total: u64,
36 pub used: u64,
38}
39
40impl From<&str> for Df {
41 fn from(value: &str) -> Self {
42 Self(value.lines().filter_map(DfLine::from_str).collect())
43 }
44}
45
46impl Df {
47 pub fn get_by_filesystem(&self, filesystem: &str) -> Option<&DfLine> {
49 self.0.iter().find(|x| x.filesystem == filesystem)
50 }
51
52 pub fn get_by_mount(&self, mounted: &str) -> Option<&DfLine> {
54 self.0.iter().find(|x| x.mounted == mounted)
55 }
56}
57
58impl DfLine {
59 fn from_str(s: &str) -> Option<Self> {
60 let mut parts = s.split_whitespace();
61 let filesystem = parts.next()?.into();
62 let total = parts.next()?.parse().ok()?;
63 let used = parts.next()?.parse().ok()?;
64 parts.next()?;
65 parts.next()?;
66 let mounted = parts.next()?.into();
67 Some(Self {
68 filesystem,
69 mounted,
70 total,
71 used,
72 })
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn test_line_from_str() {
82 assert!(DfLine::from_str("df: /run/user/1000/doc: Operation not permitted").is_none());
83 assert!(DfLine::from_str(
84 "Filesystem 1B-blocks Used Available Use% Mounted on"
85 )
86 .is_none());
87
88 let line = DfLine::from_str(
89 "udev 12294803456 0 12294803456 0% /dev",
90 )
91 .unwrap();
92 assert_eq!(line.filesystem, "udev");
93 assert_eq!(line.mounted, "/dev");
94 assert_eq!(line.total, 12294803456);
95 assert_eq!(line.used, 0);
96 }
97
98 #[test]
99 fn test_df() {
100 let src = r#"
101 df: /run/user/1000/doc: Operation not permitted
102 Filesystem 1B-blocks Used Available Use% Mounted on
103 udev 12294803456 0 12294803456 0% /dev
104 /dev/nvme0n1p2 493201408 121312256 346304512 26% /boot
105 /dev/nvme0n1p1 535805952 3579904 532226048 1% /boot/efi
106 "#
107 .trim();
108
109 let df = Df::from(src);
111 assert_eq!(df.0.len(), 3);
112 assert_eq!(df.0.get(1).unwrap().mounted, "/boot");
113
114 assert!(df.get_by_filesystem("unknown").is_none());
116 assert_eq!(df.get_by_filesystem("udev").unwrap().mounted, "/dev");
117
118 assert!(df.get_by_mount("unknown").is_none());
120 assert_eq!(df.get_by_mount("/dev").unwrap().filesystem, "udev");
121 }
122}