interface_rs/helper/
sort.rs1use std::cmp::Ordering;
2
3pub fn natural(a: &str, b: &str) -> Ordering {
14 let mut a_iter = a.chars().peekable();
15 let mut b_iter = b.chars().peekable();
16
17 loop {
18 match (a_iter.peek(), b_iter.peek()) {
19 (Some(a_c), Some(b_c)) => {
20 if a_c.is_ascii_digit() && b_c.is_ascii_digit() {
21 let mut a_num = String::new();
23 while let Some(c) = a_iter.peek() {
24 if c.is_ascii_digit() {
25 a_num.push(*c);
26 a_iter.next();
27 } else {
28 break;
29 }
30 }
31
32 let mut b_num = String::new();
33 while let Some(c) = b_iter.peek() {
34 if c.is_ascii_digit() {
35 b_num.push(*c);
36 b_iter.next();
37 } else {
38 break;
39 }
40 }
41
42 let a_int = a_num.parse::<u64>().expect("a_num contains only digits");
44 let b_int = b_num.parse::<u64>().expect("b_num contains only digits");
45
46 match a_int.cmp(&b_int) {
47 Ordering::Equal => continue,
48 other => return other,
49 }
50 } else {
51 match a_c.cmp(b_c) {
53 Ordering::Equal => {
54 a_iter.next();
55 b_iter.next();
56 continue;
57 }
58 other => return other,
59 }
60 }
61 }
62 (Some(_), None) => return Ordering::Greater,
63 (None, Some(_)) => return Ordering::Less,
64 (None, None) => return Ordering::Equal,
65 }
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn test_sort_natural_basic() {
75 assert_eq!(natural("swp1", "swp2"), Ordering::Less);
76 assert_eq!(natural("swp10", "swp2"), Ordering::Greater);
77 assert_eq!(natural("swp10", "swp10"), Ordering::Equal);
78 assert_eq!(natural("swp100", "swp20"), Ordering::Greater);
79 assert_eq!(natural("swp2", "swp2"), Ordering::Equal);
80 assert_eq!(natural("swp10s1", "swp10s2"), Ordering::Less);
81 assert_eq!(natural("swp10", "swp9s1"), Ordering::Greater);
82 }
83
84 #[test]
85 fn test_sort_natural_different_prefixes() {
86 assert_eq!(natural("eth0", "swp0"), Ordering::Less);
87 assert_eq!(natural("lo", "eth0"), Ordering::Greater);
88 assert_eq!(natural("bridge", "bond0"), Ordering::Greater);
89 }
90
91 #[test]
92 fn test_sort_natural_vlan_interfaces() {
93 assert_eq!(natural("vlan1", "vlan2"), Ordering::Less);
94 assert_eq!(natural("vlan10", "vlan9"), Ordering::Greater);
95 assert_eq!(natural("vlan100", "vlan1000"), Ordering::Less);
96 }
97
98 #[test]
99 fn test_sort_natural_empty_and_numeric() {
100 assert_eq!(natural("", ""), Ordering::Equal);
101 assert_eq!(natural("a", ""), Ordering::Greater);
102 assert_eq!(natural("", "a"), Ordering::Less);
103 assert_eq!(natural("1", "2"), Ordering::Less);
104 assert_eq!(natural("10", "2"), Ordering::Greater);
105 }
106
107 #[test]
108 fn test_sort_natural_leading_zeros() {
109 assert_eq!(natural("swp01", "swp1"), Ordering::Equal);
111 assert_eq!(natural("swp001", "swp1"), Ordering::Equal);
112 }
113
114 #[test]
115 fn test_sort_vec() {
116 let mut interfaces = vec!["swp10", "swp2", "swp1", "eth0", "lo", "swp20"];
117 interfaces.sort_by(|a, b| natural(a, b));
118 assert_eq!(interfaces, vec!["eth0", "lo", "swp1", "swp2", "swp10", "swp20"]);
119 }
120}