Skip to main content

diskforge_core/
parsing.rs

1/// Parse a human-readable size string (e.g., "100MB", "1GB", "512KB") into bytes.
2///
3/// Supported suffixes (case-insensitive): GB, MB, KB.
4/// If no suffix is provided, defaults to bytes. If parsing fails, defaults to 1MB.
5pub fn parse_size(s: &str) -> u64 {
6    let s = s.trim().to_uppercase();
7    if let Some(num) = s.strip_suffix("GB") {
8        num.trim().parse::<u64>().unwrap_or(1) * 1024 * 1024 * 1024
9    } else if let Some(num) = s.strip_suffix("MB") {
10        num.trim().parse::<u64>().unwrap_or(1) * 1024 * 1024
11    } else if let Some(num) = s.strip_suffix("KB") {
12        num.trim().parse::<u64>().unwrap_or(1) * 1024
13    } else {
14        s.parse::<u64>().unwrap_or(1024 * 1024)
15    }
16}
17
18/// Parse a human-readable duration string (e.g., "30d", "2w", "6M") into seconds.
19///
20/// Supported suffixes:
21/// - `h` — hours
22/// - `d` — days
23/// - `w` — weeks
24/// - `M` — months (30 days)
25/// - `y` — years (365 days)
26///
27/// If no suffix is provided, the value is treated as raw seconds.
28/// If parsing fails, returns 0.
29pub fn parse_duration(s: &str) -> u64 {
30    let s = s.trim();
31    if let Some(num) = s.strip_suffix('d') {
32        num.parse::<u64>().unwrap_or(0) * 86400
33    } else if let Some(num) = s.strip_suffix('w') {
34        num.parse::<u64>().unwrap_or(0) * 604800
35    } else if let Some(num) = s.strip_suffix('M') {
36        num.parse::<u64>().unwrap_or(0) * 2592000
37    } else if let Some(num) = s.strip_suffix('y') {
38        num.parse::<u64>().unwrap_or(0) * 31536000
39    } else if let Some(num) = s.strip_suffix('h') {
40        num.parse::<u64>().unwrap_or(0) * 3600
41    } else {
42        s.parse::<u64>().unwrap_or(0)
43    }
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49
50    #[test]
51    fn parse_size_gb() {
52        assert_eq!(parse_size("1GB"), 1024 * 1024 * 1024);
53        assert_eq!(parse_size("2gb"), 2 * 1024 * 1024 * 1024);
54    }
55
56    #[test]
57    fn parse_size_mb() {
58        assert_eq!(parse_size("100MB"), 100 * 1024 * 1024);
59        assert_eq!(parse_size("50mb"), 50 * 1024 * 1024);
60    }
61
62    #[test]
63    fn parse_size_kb() {
64        assert_eq!(parse_size("512KB"), 512 * 1024);
65    }
66
67    #[test]
68    fn parse_size_bytes() {
69        assert_eq!(parse_size("4096"), 4096);
70    }
71
72    #[test]
73    fn parse_size_no_suffix_default() {
74        // Non-numeric without suffix defaults to 1MB
75        assert_eq!(parse_size("abc"), 1024 * 1024);
76    }
77
78    #[test]
79    fn parse_size_zero() {
80        assert_eq!(parse_size("0MB"), 0);
81        assert_eq!(parse_size("0"), 0);
82    }
83
84    #[test]
85    fn parse_size_with_whitespace() {
86        assert_eq!(parse_size("  100 MB  "), 100 * 1024 * 1024);
87    }
88
89    #[test]
90    fn parse_duration_days() {
91        assert_eq!(parse_duration("30d"), 30 * 86400);
92        assert_eq!(parse_duration("1d"), 86400);
93    }
94
95    #[test]
96    fn parse_duration_weeks() {
97        assert_eq!(parse_duration("2w"), 2 * 604800);
98    }
99
100    #[test]
101    fn parse_duration_months() {
102        assert_eq!(parse_duration("6M"), 6 * 2592000);
103    }
104
105    #[test]
106    fn parse_duration_years() {
107        assert_eq!(parse_duration("1y"), 31536000);
108    }
109
110    #[test]
111    fn parse_duration_hours() {
112        assert_eq!(parse_duration("24h"), 24 * 3600);
113    }
114
115    #[test]
116    fn parse_duration_raw_seconds() {
117        assert_eq!(parse_duration("3600"), 3600);
118    }
119
120    #[test]
121    fn parse_duration_zero() {
122        assert_eq!(parse_duration("0d"), 0);
123    }
124
125    #[test]
126    fn parse_duration_invalid() {
127        assert_eq!(parse_duration("abc"), 0);
128    }
129}