use std::path::MAIN_SEPARATOR; /// Removes the parent component of the path pub fn basename(path: &str) -> &str { let mut index = 0; for (id, character) in path.char_indices() { if character == MAIN_SEPARATOR { index = id; } } // FIXME: On Windows, should return what for C:file.txt D:file.txt and \\server\share ? if index != 0 { return &path[index + 1..]; } path } /// Removes the extension from the path pub fn remove_extension(path: &str) -> &str { let mut has_dir = false; let mut dir_index = 0; let mut ext_index = 0; for (id, character) in path.char_indices() { if character == MAIN_SEPARATOR { has_dir = true; dir_index = id; } if character == '.' { ext_index = id; } } // Account for hidden files and directories if ext_index != 0 && (!has_dir || dir_index + 2 <= ext_index) { return &path[0..ext_index]; } path } /// Removes the basename from the path. pub fn dirname(path: &str) -> &str { let mut has_dir = false; let mut index = 0; for (id, character) in path.char_indices() { if character == MAIN_SEPARATOR { has_dir = true; index = id; } } // FIXME: On Windows, return what for C:file.txt D:file.txt and \\server\share ? if !has_dir { "." } else if index == 0 { &path[..1] } else { &path[0..index] } } #[cfg(test)] mod path_tests { use super::*; fn correct(input: &str) -> String { input.replace('/', &MAIN_SEPARATOR.to_string()) } macro_rules! func_tests { ($($name:ident: $func:ident for $input:expr => $output:expr)+) => { $( #[test] fn $name() { assert_eq!($func(&correct($input)), correct($output)); } )+ } } func_tests! { remove_ext_simple: remove_extension for "foo.txt" => "foo" remove_ext_dir: remove_extension for "dir/foo.txt" => "dir/foo" hidden: remove_extension for ".foo" => ".foo" remove_ext_utf8: remove_extension for "💖.txt" => "💖" remove_ext_empty: remove_extension for "" => "" basename_simple: basename for "foo.txt" => "foo.txt" basename_dir: basename for "dir/foo.txt" => "foo.txt" basename_empty: basename for "" => "" basename_utf8_0: basename for "💖/foo.txt" => "foo.txt" basename_utf8_1: basename for "dir/💖.txt" => "💖.txt" dirname_simple: dirname for "foo.txt" => "." dirname_dir: dirname for "dir/foo.txt" => "dir" dirname_utf8_0: dirname for "💖/foo.txt" => "💖" dirname_utf8_1: dirname for "dir/💖.txt" => "dir" dirname_empty: dirname for "" => "." } #[test] fn dirname_root() { #[cfg(windows)] assert_eq!(dirname("C:\\"), "C:"); #[cfg(windows)] assert_eq!(dirname("\\"), "\\"); #[cfg(not(windows))] assert_eq!(dirname("/"), "/"); } }