Show More
@@ -112,6 +112,9 b' impl HgPath {' | |||||
112 | pub fn contains(&self, other: u8) -> bool { |
|
112 | pub fn contains(&self, other: u8) -> bool { | |
113 | self.inner.contains(&other) |
|
113 | self.inner.contains(&other) | |
114 | } |
|
114 | } | |
|
115 | pub fn starts_with(&self, needle: impl AsRef<HgPath>) -> bool { | |||
|
116 | self.inner.starts_with(needle.as_ref().as_bytes()) | |||
|
117 | } | |||
115 | pub fn join<T: ?Sized + AsRef<HgPath>>(&self, other: &T) -> HgPathBuf { |
|
118 | pub fn join<T: ?Sized + AsRef<HgPath>>(&self, other: &T) -> HgPathBuf { | |
116 | let mut inner = self.inner.to_owned(); |
|
119 | let mut inner = self.inner.to_owned(); | |
117 | if inner.len() != 0 && inner.last() != Some(&b'/') { |
|
120 | if inner.len() != 0 && inner.last() != Some(&b'/') { | |
@@ -120,6 +123,21 b' impl HgPath {' | |||||
120 | inner.extend(other.as_ref().bytes()); |
|
123 | inner.extend(other.as_ref().bytes()); | |
121 | HgPathBuf::from_bytes(&inner) |
|
124 | HgPathBuf::from_bytes(&inner) | |
122 | } |
|
125 | } | |
|
126 | /// Given a base directory, returns the slice of `self` relative to the | |||
|
127 | /// base directory. If `base` is not a directory (does not end with a | |||
|
128 | /// `b'/'`), returns `None`. | |||
|
129 | pub fn relative_to(&self, base: impl AsRef<HgPath>) -> Option<&HgPath> { | |||
|
130 | let base = base.as_ref(); | |||
|
131 | if base.is_empty() { | |||
|
132 | return Some(self); | |||
|
133 | } | |||
|
134 | let is_dir = base.as_bytes().ends_with(b"/"); | |||
|
135 | if is_dir && self.starts_with(base) { | |||
|
136 | Some(HgPath::new(&self.inner[base.len()..])) | |||
|
137 | } else { | |||
|
138 | None | |||
|
139 | } | |||
|
140 | } | |||
123 | /// Checks for errors in the path, short-circuiting at the first one. |
|
141 | /// Checks for errors in the path, short-circuiting at the first one. | |
124 | /// This generates fine-grained errors useful for debugging. |
|
142 | /// This generates fine-grained errors useful for debugging. | |
125 | /// To simply check if the path is valid during tests, use `is_valid`. |
|
143 | /// To simply check if the path is valid during tests, use `is_valid`. | |
@@ -412,4 +430,35 b' mod tests {' | |||||
412 | let path = HgPathBuf::from_bytes(b"a").join(HgPath::new(b"/b")); |
|
430 | let path = HgPathBuf::from_bytes(b"a").join(HgPath::new(b"/b")); | |
413 | assert_eq!(b"a//b", path.as_bytes()); |
|
431 | assert_eq!(b"a//b", path.as_bytes()); | |
414 | } |
|
432 | } | |
|
433 | ||||
|
434 | #[test] | |||
|
435 | fn test_relative_to() { | |||
|
436 | let path = HgPath::new(b""); | |||
|
437 | let base = HgPath::new(b""); | |||
|
438 | assert_eq!(Some(path), path.relative_to(base)); | |||
|
439 | ||||
|
440 | let path = HgPath::new(b"path"); | |||
|
441 | let base = HgPath::new(b""); | |||
|
442 | assert_eq!(Some(path), path.relative_to(base)); | |||
|
443 | ||||
|
444 | let path = HgPath::new(b"a"); | |||
|
445 | let base = HgPath::new(b"b"); | |||
|
446 | assert_eq!(None, path.relative_to(base)); | |||
|
447 | ||||
|
448 | let path = HgPath::new(b"a/b"); | |||
|
449 | let base = HgPath::new(b"a"); | |||
|
450 | assert_eq!(None, path.relative_to(base)); | |||
|
451 | ||||
|
452 | let path = HgPath::new(b"a/b"); | |||
|
453 | let base = HgPath::new(b"a/"); | |||
|
454 | assert_eq!(Some(HgPath::new(b"b")), path.relative_to(base)); | |||
|
455 | ||||
|
456 | let path = HgPath::new(b"nested/path/to/b"); | |||
|
457 | let base = HgPath::new(b"nested/path/"); | |||
|
458 | assert_eq!(Some(HgPath::new(b"to/b")), path.relative_to(base)); | |||
|
459 | ||||
|
460 | let path = HgPath::new(b"ends/with/dir/"); | |||
|
461 | let base = HgPath::new(b"ends/"); | |||
|
462 | assert_eq!(Some(HgPath::new(b"with/dir/")), path.relative_to(base)); | |||
|
463 | } | |||
415 | } |
|
464 | } |
General Comments 0
You need to be logged in to leave comments.
Login now