use std::path::{Path, PathBuf};
pub struct PathNormalizer;
impl PathNormalizer {
pub fn normalize_separators(path: &str) -> String {
path.replace('\\', "/")
}
pub fn paths_equal(path1: &str, path2: &str) -> bool {
Self::normalize_separators(path1) == Self::normalize_separators(path2)
}
pub fn find_path_in_collection<'a>(
target: &str,
paths: &'a [impl AsRef<str>],
) -> Option<&'a str> {
let normalized_target = Self::normalize_separators(target);
for path in paths {
let path_str = path.as_ref();
if Self::normalize_separators(path_str) == normalized_target {
return Some(path_str);
}
}
None
}
pub fn normalize_path(path: &str) -> String {
let normalized_separators = Self::normalize_separators(path);
let path_buf = Path::new(&normalized_separators);
let mut components = Vec::new();
for component in path_buf.components() {
match component {
std::path::Component::ParentDir => {
components.pop();
}
std::path::Component::CurDir => {
}
std::path::Component::Prefix(_) => {
}
std::path::Component::RootDir => {
}
std::path::Component::Normal(name) => {
components.push(name.to_string_lossy().to_string());
}
}
}
let normalized: PathBuf = components.into_iter().collect();
Self::normalize_separators(&normalized.to_string_lossy())
}
pub fn to_relative_string(path: &Path, current_dir: &Path) -> String {
let relative = path.strip_prefix(current_dir).unwrap_or(path);
Self::normalize_separators(&relative.to_string_lossy())
}
pub fn for_display(path: &Path, current_dir: &Path) -> String {
let relative = Self::to_relative_string(path, current_dir);
if relative.starts_with('/') || relative.contains(":\\") {
path.file_name()
.and_then(|name| name.to_str())
.unwrap_or("unknown")
.to_string()
} else {
relative
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_normalize_separators() {
assert_eq!(
PathNormalizer::normalize_separators("src\\main.rs"),
"src/main.rs"
);
assert_eq!(
PathNormalizer::normalize_separators("src\\utils\\helper.rs"),
"src/utils/helper.rs"
);
assert_eq!(
PathNormalizer::normalize_separators("src/main.rs"),
"src/main.rs"
);
assert_eq!(
PathNormalizer::normalize_separators("src/utils/helper.rs"),
"src/utils/helper.rs"
);
assert_eq!(
PathNormalizer::normalize_separators("src\\utils/helper.rs"),
"src/utils/helper.rs"
);
assert_eq!(
PathNormalizer::normalize_separators("src/utils\\helper.rs"),
"src/utils/helper.rs"
);
assert_eq!(PathNormalizer::normalize_separators(""), "");
assert_eq!(PathNormalizer::normalize_separators("\\"), "/");
assert_eq!(PathNormalizer::normalize_separators("/"), "/");
}
#[test]
fn test_paths_equal() {
assert!(PathNormalizer::paths_equal("src\\main.rs", "src/main.rs"));
assert!(PathNormalizer::paths_equal(
"src/utils/helper.rs",
"src\\utils\\helper.rs"
));
assert!(PathNormalizer::paths_equal("src/main.rs", "src/main.rs"));
assert!(!PathNormalizer::paths_equal("src/main.rs", "lib/main.rs"));
assert!(!PathNormalizer::paths_equal("src\\main.rs", "src\\lib.rs"));
}
#[test]
fn test_find_path_in_collection() {
let files = vec!["src/main.rs", "src\\utils\\helper.rs", "lib/config.rs"];
assert_eq!(
PathNormalizer::find_path_in_collection("src\\main.rs", &files),
Some("src/main.rs")
);
assert_eq!(
PathNormalizer::find_path_in_collection("src/utils/helper.rs", &files),
Some("src\\utils\\helper.rs")
);
assert_eq!(
PathNormalizer::find_path_in_collection("nonexistent.rs", &files),
None
);
}
#[test]
fn test_normalize_path() {
assert_eq!(
PathNormalizer::normalize_path("src\\main.rs"),
"src/main.rs"
);
let result = PathNormalizer::normalize_path("src/utils/../main.rs");
assert!(!result.contains("\\"));
assert_eq!(result, "src/main.rs");
assert_eq!(
PathNormalizer::normalize_path("src\\utils\\..\\main.rs"),
"src/main.rs"
);
}
}