glib/
unicollate.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Take a look at the license at the top of the repository in the LICENSE file.

use crate::ffi;

// rustdoc-stripper-ignore-next
/// A `CollationKey` allows ordering strings using the linguistically correct rules for the current locale.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct CollationKey(crate::Slice<u8>);

impl<T: AsRef<str>> From<T> for CollationKey {
    // rustdoc-stripper-ignore-next
    /// Converts a string into a `CollationKey` that can be compared with other
    /// collation keys produced by the same function using `std::cmp::Ordering::cmp()`.
    #[doc(alias = "g_utf8_collate_key")]
    fn from(s: T) -> Self {
        let s = s.as_ref();
        let key = unsafe {
            let ptr = ffi::g_utf8_collate_key(s.as_ptr() as *const _, s.len() as isize);
            let len = libc::strlen(ptr);

            crate::Slice::from_glib_full_num(ptr as *mut u8, len)
        };
        Self(key)
    }
}

// rustdoc-stripper-ignore-next
/// A `FilenameCollationKey` allows ordering file names using the linguistically correct rules for the current locale.
/// Compared to `CollationKey`, filename collation keys take into consideration dots and other characters
/// commonly found in file names.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct FilenameCollationKey(crate::Slice<u8>);

impl<T: AsRef<str>> From<T> for FilenameCollationKey {
    // rustdoc-stripper-ignore-next
    /// Converts a string into a `FilenameCollationKey` that can be compared with other
    /// collation keys produced by the same function using `std::cmp::Ordering::cmp()`.
    #[doc(alias = "g_utf8_collate_key_for_filename")]
    fn from(s: T) -> Self {
        let s = s.as_ref();
        let key = unsafe {
            let ptr =
                ffi::g_utf8_collate_key_for_filename(s.as_ptr() as *const _, s.len() as isize);
            let len = libc::strlen(ptr);

            crate::Slice::from_glib_full_num(ptr as *mut u8, len)
        };
        Self(key)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn collate() {
        let mut unsorted = vec![
            String::from("bcd"),
            String::from("cde"),
            String::from("abc"),
        ];

        let sorted = vec![
            String::from("abc"),
            String::from("bcd"),
            String::from("cde"),
        ];

        unsorted.sort_by(|s1, s2| CollationKey::from(&s1).cmp(&CollationKey::from(&s2)));

        assert_eq!(unsorted, sorted);
    }

    #[test]
    fn collate_non_ascii() {
        let mut unsorted = vec![
            String::from("猫の手も借りたい"),
            String::from("日本語は難しい"),
            String::from("ありがとう"),
        ];

        let sorted = vec![
            String::from("ありがとう"),
            String::from("日本語は難しい"),
            String::from("猫の手も借りたい"),
        ];

        unsorted.sort_by(|s1, s2| CollationKey::from(&s1).cmp(&CollationKey::from(&s2)));

        assert_eq!(unsorted, sorted);
    }

    #[test]
    fn collate_filenames() {
        let mut unsorted = vec![
            String::from("bcd.a"),
            String::from("cde.b"),
            String::from("abc.c"),
        ];

        let sorted = vec![
            String::from("abc.c"),
            String::from("bcd.a"),
            String::from("cde.b"),
        ];

        unsorted.sort_by(|s1, s2| {
            FilenameCollationKey::from(&s1).cmp(&FilenameCollationKey::from(&s2))
        });

        assert_eq!(unsorted, sorted);
    }

    #[test]
    fn collate_filenames_non_ascii() {
        let mut unsorted = vec![
            String::from("猫の手も借りたい.foo"),
            String::from("日本語は難しい.bar"),
            String::from("ありがとう.baz"),
        ];

        let sorted = vec![
            String::from("ありがとう.baz"),
            String::from("日本語は難しい.bar"),
            String::from("猫の手も借りたい.foo"),
        ];

        unsorted.sort_by(|s1, s2| {
            FilenameCollationKey::from(&s1).cmp(&FilenameCollationKey::from(&s2))
        });

        assert_eq!(unsorted, sorted);
    }

    #[test]
    fn collate_filenames_from_path() {
        use std::path::PathBuf;

        let mut unsorted = vec![
            PathBuf::from("猫の手も借りたい.foo"),
            PathBuf::from("日本語は難しい.bar"),
            PathBuf::from("ありがとう.baz"),
        ];

        let sorted = vec![
            PathBuf::from("ありがとう.baz"),
            PathBuf::from("日本語は難しい.bar"),
            PathBuf::from("猫の手も借りたい.foo"),
        ];

        unsorted.sort_by(|s1, s2| {
            FilenameCollationKey::from(&s1.to_string_lossy())
                .cmp(&FilenameCollationKey::from(&s2.to_string_lossy()))
        });

        assert_eq!(unsorted, sorted);
    }
}