comparison rust/hg-core/src/utils/hg_path.rs @ 43833:4f1543a2f5c3

rust-hg-path: add method to get part of a path relative to a prefix This will be used in the next patch in this series. Differential Revision: https://phab.mercurial-scm.org/D7526
author Rapha?l Gom?s <rgomes@octobus.net>
date Fri, 29 Nov 2019 17:24:40 +0100
parents c27e688fcdc3
children 4b3c8df189bc
comparison
equal deleted inserted replaced
43832:1bb4e9b02984 43833:4f1543a2f5c3
110 &self.inner 110 &self.inner
111 } 111 }
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'/') {
118 inner.push(b'/'); 121 inner.push(b'/');
119 } 122 }
120 inner.extend(other.as_ref().bytes()); 123 inner.extend(other.as_ref().bytes());
121 HgPathBuf::from_bytes(&inner) 124 HgPathBuf::from_bytes(&inner)
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 }
122 } 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`.
126 pub fn check_state(&self) -> Result<(), HgPathError> { 144 pub fn check_state(&self) -> Result<(), HgPathError> {
410 let path = HgPathBuf::from_bytes(b"a/").join(HgPath::new(b"/b")); 428 let path = HgPathBuf::from_bytes(b"a/").join(HgPath::new(b"/b"));
411 assert_eq!(b"a//b", path.as_bytes()); 429 assert_eq!(b"a//b", path.as_bytes());
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 }
415 } 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 }
464 }