path_rs/utf8.rs
1//! UTF-8 helpers for paths.
2//!
3//! Internal filesystem representation remains `Path` / `PathBuf` / `OsStr`.
4//! Never round-trip a path through lossy UTF-8 for filesystem operations.
5
6use crate::error::PathError;
7use std::borrow::Cow;
8use std::path::Path;
9
10/// Convert a path to a UTF-8 string slice, or error if it is not valid UTF-8.
11///
12/// # Filesystem access
13///
14/// **No.**
15pub fn path_to_utf8(path: &Path) -> Result<&str, PathError> {
16 path.to_str().ok_or(PathError::NotUtf8)
17}
18
19/// Lossy UTF-8 conversion suitable for logs and UI only.
20///
21/// **Never** use the result as a filesystem path for further I/O.
22///
23/// # Filesystem access
24///
25/// **No.**
26pub fn path_to_string_lossy(path: &Path) -> Cow<'_, str> {
27 path.to_string_lossy()
28}
29
30/// Produce a Unicode-normalized logical key for comparison purposes.
31///
32/// Requires the `unicode` feature. The result must **not** be used as a filesystem path.
33///
34/// Normalization form: NFC.
35#[cfg(feature = "unicode")]
36pub fn logical_path_key(path: &Path) -> String {
37 use unicode_normalization::UnicodeNormalization;
38 path.to_string_lossy().nfc().collect::<String>()
39}
40
41#[cfg(test)]
42mod tests {
43 use super::*;
44 use std::path::Path;
45
46 #[test]
47 fn utf8_ok() {
48 assert_eq!(path_to_utf8(Path::new("foo/bar")).unwrap(), "foo/bar");
49 }
50}