gix_utils/
str.rs

1use std::borrow::Cow;
2use std::ffi::OsStr;
3use std::path::Path;
4
5/// Assure that `s` is precomposed, i.e. `ä` is a single code-point, and not two i.e. `a` and `<umlaut>`.
6///
7/// At the expense of extra-compute, it does nothing if there is no work to be done, returning the original input without allocating.
8pub fn precompose(s: Cow<'_, str>) -> Cow<'_, str> {
9    use unicode_normalization::UnicodeNormalization;
10    if s.as_ref().nfc().cmp(s.as_ref().chars()).is_eq() {
11        s
12    } else {
13        Cow::Owned(s.as_ref().nfc().collect())
14    }
15}
16
17/// Assure that `s` is decomposed, i.e. `ä` turns into `a` and `<umlaut>`.
18///
19/// At the expense of extra-compute, it does nothing if there is no work to be done, returning the original input without allocating.
20pub fn decompose(s: Cow<'_, str>) -> Cow<'_, str> {
21    use unicode_normalization::UnicodeNormalization;
22    if s.as_ref().nfd().cmp(s.as_ref().chars()).is_eq() {
23        s
24    } else {
25        Cow::Owned(s.as_ref().nfd().collect())
26    }
27}
28
29/// Return the precomposed version of `path`, or `path` itself if it contained illformed unicode,
30/// or if the unicode version didn't contains decomposed unicode.
31/// Otherwise, similar to [`precompose()`]
32pub fn precompose_path(path: Cow<'_, Path>) -> Cow<'_, Path> {
33    match path.to_str() {
34        None => path,
35        Some(maybe_decomposed) => match precompose(maybe_decomposed.into()) {
36            Cow::Borrowed(_) => path,
37            Cow::Owned(precomposed) => Cow::Owned(precomposed.into()),
38        },
39    }
40}
41
42/// Return the precomposed version of `name`, or `name` itself if it contained illformed unicode,
43/// or if the unicode version didn't contains decomposed unicode.
44/// Otherwise, similar to [`precompose()`]
45pub fn precompose_os_string(name: Cow<'_, OsStr>) -> Cow<'_, OsStr> {
46    match name.to_str() {
47        None => name,
48        Some(maybe_decomposed) => match precompose(maybe_decomposed.into()) {
49            Cow::Borrowed(_) => name,
50            Cow::Owned(precomposed) => Cow::Owned(precomposed.into()),
51        },
52    }
53}
54
55/// Return the precomposed version of `s`, or `s` itself if it contained illformed unicode,
56/// or if the unicode version didn't contains decomposed unicode.
57/// Otherwise, similar to [`precompose()`]
58#[cfg(feature = "bstr")]
59pub fn precompose_bstr(s: Cow<'_, bstr::BStr>) -> Cow<'_, bstr::BStr> {
60    use bstr::ByteSlice;
61    match s.to_str().ok() {
62        None => s,
63        Some(maybe_decomposed) => match precompose(maybe_decomposed.into()) {
64            Cow::Borrowed(_) => s,
65            Cow::Owned(precomposed) => Cow::Owned(precomposed.into()),
66        },
67    }
68}