src/basename.rs in faster_path-0.3.7 vs src/basename.rs in faster_path-0.3.8
- old
+ new
@@ -1,27 +1,70 @@
extern crate memchr;
-use self::memchr::memrchr;
-use path_parsing::{SEP, last_non_sep_i};
-pub fn basename<'a>(pth: &'a str, ext: &str) -> &'a str {
- let name_end = (last_non_sep_i(pth) + 1) as usize;
- // Known edge case, all '/'.
- if !pth.is_empty() && name_end == 0 {
- return &pth[..1];
+use path_parsing::{find_last_sep_pos, find_last_non_sep_pos, find_last_dot_pos};
+
+pub fn basename<'a>(path: &'a str, ext: &str) -> &'a str {
+ let bytes: &[u8] = path.as_bytes();
+ let mut left: usize = 0;
+ let mut right: usize = bytes.len();
+ if let Some(last_slash_pos) = find_last_sep_pos(bytes) {
+ if last_slash_pos == right - 1 {
+ if let Some(pos) = find_last_non_sep_pos(&bytes[..last_slash_pos]) {
+ right = pos + 1;
+ } else {
+ return "/";
+ }
+ if let Some(pos) = find_last_sep_pos(&bytes[..right]) {
+ left = pos + 1;
+ }
+ } else {
+ left = last_slash_pos + 1;
+ }
}
- let name_start = match memrchr(SEP, &pth.as_bytes()[..name_end]) {
- Some(i) => i + 1,
- _ => 0
- };
- let mut name = &pth[name_start..name_end];
- if ext == ".*" {
- if let Some(dot_i) = memrchr('.' as u8, name.as_bytes()) {
- name = &name[..dot_i];
+ let ext_bytes = ext.as_bytes();
+ if ext_bytes == b".*" {
+ if let Some(dot_pos) = find_last_dot_pos(&bytes[left..right]) {
+ right = left + dot_pos;
}
- } else if name.ends_with(ext) {
- name = &name[..name.len() - ext.len()];
- };
- name
+ } else if bytes[left..right].ends_with(ext_bytes) {
+ right -= ext_bytes.len();
+ }
+ &path[left..right]
+}
+
+#[test]
+fn absolute() {
+ assert_eq!(basename("/a/b///c", ""), "c");
+}
+
+#[test]
+fn trailing_slashes_absolute() {
+ assert_eq!(basename("/a/b///c//////", ""), "c");
+}
+
+#[test]
+fn relative() {
+ assert_eq!(basename("b///c", ""), "c");
+}
+
+#[test]
+fn trailing_slashes_relative() {
+ assert_eq!(basename("b/c//", ""), "c");
+}
+
+#[test]
+fn root() {
+ assert_eq!(basename("//c", ""), "c");
+}
+
+#[test]
+fn trailing_slashes_root() {
+ assert_eq!(basename("//c//", ""), "c");
+}
+
+#[test]
+fn trailing_slashes_relative_root() {
+ assert_eq!(basename("c//", ""), "c");
}
#[test]
fn edge_case_all_seps() {
assert_eq!("/", basename("///", ".*"));