src/plus.rs in faster_path-0.3.9 vs src/plus.rs in faster_path-0.3.10
- old
+ new
@@ -1,85 +1,82 @@
-extern crate array_tool;
-use std::path::Path;
+use std::borrow::Cow;
use std::str;
+use std::path::MAIN_SEPARATOR;
+
use chop_basename::chop_basename;
-use basename::basename;
-use dirname::dirname;
-use self::array_tool::vec::Shift;
-use std::ops::Index;
+use path_parsing::SEP;
-pub fn plus_paths(path1: &str, path2: &str) -> String {
- let mut prefix2 = path2.to_string();
+pub fn plus_paths<'a>(path1: &'a str, path2: &str) -> Cow<'a, str> {
+ let mut prefix2 = path2;
let mut index_list2: Vec<usize> = vec![];
- let mut basename_list2: Vec<String> = vec![];
-
+ let mut basename_list2: Vec<&str> = vec![];
loop {
- match chop_basename(&prefix2.clone()[..]) {
- None => { break },
+ match chop_basename(prefix2) {
+ None => { break; }
Some((pfx2, basename2)) => {
- prefix2 = pfx2.to_string();
- index_list2.unshift(pfx2.len());
- basename_list2.unshift(basename2.to_owned());
- },
+ prefix2 = pfx2;
+ index_list2.push(pfx2.len());
+ basename_list2.push(basename2);
+ }
}
}
if !prefix2.is_empty() {
- return path2.to_string()
+ return path2.to_string().into();
};
- let mut prefix1 = path1.to_string();
-
+ let result_prefix: Cow<str>;
+ let mut prefix1 = path1;
loop {
- while !basename_list2.is_empty() && basename_list2.first().unwrap() == "." {
- index_list2.shift();
- basename_list2.shift();
- }
- match chop_basename(&prefix1.clone()[..]) {
- None => { break },
+ let mut new_len = basename_list2.len() - count_trailing(".", &basename_list2);
+ index_list2.truncate(new_len);
+ basename_list2.truncate(new_len);
+ match chop_basename(prefix1) {
+ None => {
+ result_prefix = prefix1.into();
+ break;
+ }
Some((pfx1, basename1)) => {
- prefix1 = pfx1.to_string();
- if basename1 == "." { continue };
- if basename1 == ".." || basename_list2.is_empty() || basename_list2.first().unwrap() != ".." {
- prefix1.push_str(&basename1);
- break
- }
+ prefix1 = pfx1;
+ if basename1 == "." { continue; };
+ if basename1 == ".." || basename_list2.last() != Some(&"..") {
+ result_prefix = [prefix1, basename1].concat().into();
+ break;
}
+ }
}
- index_list2.shift();
- basename_list2.shift();
+ if new_len > 0 {
+ new_len -= 1;
+ index_list2.truncate(new_len);
+ basename_list2.truncate(new_len);
+ }
}
- let result: String;
-
- let mut r1 = if let Some((_,_)) = chop_basename(&prefix1[..]) {true} else {false};
-
- if !r1 {
- r1 = basename(&prefix1[..], "").contains("/");
- if r1 {
- while !basename_list2.is_empty() && basename_list2.first().unwrap() == ".." {
- index_list2.shift();
- basename_list2.shift();
- }
- }
+ if !result_prefix.is_empty() && result_prefix.as_bytes().iter().cloned().all(|b| b == SEP) {
+ let new_len = basename_list2.len() - count_trailing("..", &basename_list2);
+ index_list2.truncate(new_len);
+ basename_list2.truncate(new_len);
}
- if !basename_list2.is_empty() {
- let suffix2 = path2.index(index_list2.first().unwrap().to_owned()..);
- if r1 {
- result = Path::new(&prefix1).join(Path::new(&suffix2)).to_str().unwrap().to_string();
- } else {
- prefix1.push_str(&suffix2);
- result = prefix1.to_string();
+ if let Some(last_index2) = index_list2.last() {
+ let suffix = &path2[*last_index2..];
+ match (result_prefix.as_bytes().last(), suffix.as_bytes().first()) {
+ (Some(&SEP), Some(&SEP)) => [&result_prefix, &suffix[1..]].concat().into(),
+ (Some(&SEP), Some(_)) | (Some(_), Some(&SEP)) => [&result_prefix, suffix].concat().into(),
+ (None, Some(_)) => suffix.to_string().into(),
+ _ => format!("{}{}{}", result_prefix.as_ref(), MAIN_SEPARATOR, suffix).into(),
}
} else {
- if r1 {
- result = prefix1.to_string();
+ if result_prefix.is_empty() {
+ ".".into()
} else {
- result = dirname(&prefix1[..]).to_string();
+ result_prefix
}
}
+}
- String::from(result)
+#[inline(always)]
+fn count_trailing(x: &str, xs: &Vec<&str>) -> usize {
+ xs.iter().rev().take_while(|&c| c == &x).count()
}
#[test]
fn it_will_plus_same_as_ruby() {
assert_eq!("/" , plus_paths("/" , "/"));
@@ -88,9 +85,10 @@
assert_eq!("b" , plus_paths("." , "b"));
assert_eq!("." , plus_paths("." , "."));
assert_eq!("/b" , plus_paths("a" , "/b"));
assert_eq!("/" , plus_paths("/" , ".."));
+ assert_eq!("////" , plus_paths("////", ""));
assert_eq!("." , plus_paths("a" , ".."));
assert_eq!("a" , plus_paths("a/b", ".."));
assert_eq!("../.." , plus_paths(".." , ".."));
assert_eq!("/c" , plus_paths("/" , "../c"));
assert_eq!("c" , plus_paths("a" , "../c"));