glib/
unicollate.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use crate::ffi;
4
5// rustdoc-stripper-ignore-next
6/// A `CollationKey` allows ordering strings using the linguistically correct rules for the current locale.
7#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
8pub struct CollationKey(crate::Slice<u8>);
9
10impl<T: AsRef<str>> From<T> for CollationKey {
11    // rustdoc-stripper-ignore-next
12    /// Converts a string into a `CollationKey` that can be compared with other
13    /// collation keys produced by the same function using `std::cmp::Ordering::cmp()`.
14    #[doc(alias = "g_utf8_collate_key")]
15    fn from(s: T) -> Self {
16        let s = s.as_ref();
17        let key = unsafe {
18            let ptr = ffi::g_utf8_collate_key(s.as_ptr() as *const _, s.len() as isize);
19            let len = libc::strlen(ptr);
20
21            crate::Slice::from_glib_full_num(ptr as *mut u8, len)
22        };
23        Self(key)
24    }
25}
26
27// rustdoc-stripper-ignore-next
28/// A `FilenameCollationKey` allows ordering file names using the linguistically correct rules for the current locale.
29/// Compared to `CollationKey`, filename collation keys take into consideration dots and other characters
30/// commonly found in file names.
31#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
32pub struct FilenameCollationKey(crate::Slice<u8>);
33
34impl<T: AsRef<str>> From<T> for FilenameCollationKey {
35    // rustdoc-stripper-ignore-next
36    /// Converts a string into a `FilenameCollationKey` that can be compared with other
37    /// collation keys produced by the same function using `std::cmp::Ordering::cmp()`.
38    #[doc(alias = "g_utf8_collate_key_for_filename")]
39    fn from(s: T) -> Self {
40        let s = s.as_ref();
41        let key = unsafe {
42            let ptr =
43                ffi::g_utf8_collate_key_for_filename(s.as_ptr() as *const _, s.len() as isize);
44            let len = libc::strlen(ptr);
45
46            crate::Slice::from_glib_full_num(ptr as *mut u8, len)
47        };
48        Self(key)
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test]
57    fn collate() {
58        let mut unsorted = vec![
59            String::from("bcd"),
60            String::from("cde"),
61            String::from("abc"),
62        ];
63
64        let sorted = vec![
65            String::from("abc"),
66            String::from("bcd"),
67            String::from("cde"),
68        ];
69
70        unsorted.sort_by(|s1, s2| CollationKey::from(&s1).cmp(&CollationKey::from(&s2)));
71
72        assert_eq!(unsorted, sorted);
73    }
74
75    #[test]
76    fn collate_non_ascii() {
77        let mut unsorted = vec![
78            String::from("猫の手も借りたい"),
79            String::from("日本語は難しい"),
80            String::from("ありがとう"),
81        ];
82
83        let sorted = vec![
84            String::from("ありがとう"),
85            String::from("日本語は難しい"),
86            String::from("猫の手も借りたい"),
87        ];
88
89        unsorted.sort_by(|s1, s2| CollationKey::from(&s1).cmp(&CollationKey::from(&s2)));
90
91        assert_eq!(unsorted, sorted);
92    }
93
94    #[test]
95    fn collate_filenames() {
96        let mut unsorted = vec![
97            String::from("bcd.a"),
98            String::from("cde.b"),
99            String::from("abc.c"),
100        ];
101
102        let sorted = vec![
103            String::from("abc.c"),
104            String::from("bcd.a"),
105            String::from("cde.b"),
106        ];
107
108        unsorted.sort_by(|s1, s2| {
109            FilenameCollationKey::from(&s1).cmp(&FilenameCollationKey::from(&s2))
110        });
111
112        assert_eq!(unsorted, sorted);
113    }
114
115    #[test]
116    fn collate_filenames_non_ascii() {
117        let mut unsorted = vec![
118            String::from("猫の手も借りたい.foo"),
119            String::from("日本語は難しい.bar"),
120            String::from("ありがとう.baz"),
121        ];
122
123        let sorted = vec![
124            String::from("ありがとう.baz"),
125            String::from("日本語は難しい.bar"),
126            String::from("猫の手も借りたい.foo"),
127        ];
128
129        unsorted.sort_by(|s1, s2| {
130            FilenameCollationKey::from(&s1).cmp(&FilenameCollationKey::from(&s2))
131        });
132
133        assert_eq!(unsorted, sorted);
134    }
135
136    #[test]
137    fn collate_filenames_from_path() {
138        use std::path::PathBuf;
139
140        let mut unsorted = vec![
141            PathBuf::from("猫の手も借りたい.foo"),
142            PathBuf::from("日本語は難しい.bar"),
143            PathBuf::from("ありがとう.baz"),
144        ];
145
146        let sorted = vec![
147            PathBuf::from("ありがとう.baz"),
148            PathBuf::from("日本語は難しい.bar"),
149            PathBuf::from("猫の手も借りたい.foo"),
150        ];
151
152        unsorted.sort_by(|s1, s2| {
153            FilenameCollationKey::from(&s1.to_string_lossy())
154                .cmp(&FilenameCollationKey::from(&s2.to_string_lossy()))
155        });
156
157        assert_eq!(unsorted, sorted);
158    }
159}