comparison rust/hg-core/src/utils/hg_path.rs @ 44266:9ab4830e9e3d

rust-hg-path: add useful methods to `HgPath` This changeset introduces the use of the `pretty_assertions` crate for easier to read test output. Differential Revision: https://phab.mercurial-scm.org/D7867
author Rapha?l Gom?s <rgomes@octobus.net>
date Tue, 14 Jan 2020 16:50:35 +0100
parents c18dd48cea4a
children 0e9ac3968b56
comparison
equal deleted inserted replaced
44265:c18dd48cea4a 44266:9ab4830e9e3d
171 &self.inner 171 &self.inner
172 } 172 }
173 pub fn contains(&self, other: u8) -> bool { 173 pub fn contains(&self, other: u8) -> bool {
174 self.inner.contains(&other) 174 self.inner.contains(&other)
175 } 175 }
176 pub fn starts_with(&self, needle: impl AsRef<HgPath>) -> bool { 176 pub fn starts_with(&self, needle: impl AsRef<Self>) -> bool {
177 self.inner.starts_with(needle.as_ref().as_bytes()) 177 self.inner.starts_with(needle.as_ref().as_bytes())
178 } 178 }
179 pub fn join<T: ?Sized + AsRef<HgPath>>(&self, other: &T) -> HgPathBuf { 179 pub fn trim_trailing_slash(&self) -> &Self {
180 Self::new(if self.inner.last() == Some(&b'/') {
181 &self.inner[..self.inner.len() - 1]
182 } else {
183 &self.inner[..]
184 })
185 }
186 pub fn join<T: ?Sized + AsRef<Self>>(&self, other: &T) -> HgPathBuf {
180 let mut inner = self.inner.to_owned(); 187 let mut inner = self.inner.to_owned();
181 if inner.len() != 0 && inner.last() != Some(&b'/') { 188 if inner.len() != 0 && inner.last() != Some(&b'/') {
182 inner.push(b'/'); 189 inner.push(b'/');
183 } 190 }
184 inner.extend(other.as_ref().bytes()); 191 inner.extend(other.as_ref().bytes());
185 HgPathBuf::from_bytes(&inner) 192 HgPathBuf::from_bytes(&inner)
186 } 193 }
194 pub fn parent(&self) -> &Self {
195 let inner = self.as_bytes();
196 HgPath::new(match inner.iter().rposition(|b| *b == b'/') {
197 Some(pos) => &inner[..pos],
198 None => &[],
199 })
200 }
187 /// Given a base directory, returns the slice of `self` relative to the 201 /// Given a base directory, returns the slice of `self` relative to the
188 /// base directory. If `base` is not a directory (does not end with a 202 /// base directory. If `base` is not a directory (does not end with a
189 /// `b'/'`), returns `None`. 203 /// `b'/'`), returns `None`.
190 pub fn relative_to(&self, base: impl AsRef<HgPath>) -> Option<&HgPath> { 204 pub fn relative_to(&self, base: impl AsRef<Self>) -> Option<&Self> {
191 let base = base.as_ref(); 205 let base = base.as_ref();
192 if base.is_empty() { 206 if base.is_empty() {
193 return Some(self); 207 return Some(self);
194 } 208 }
195 let is_dir = base.as_bytes().ends_with(b"/"); 209 let is_dir = base.as_bytes().ends_with(b"/");
196 if is_dir && self.starts_with(base) { 210 if is_dir && self.starts_with(base) {
197 Some(HgPath::new(&self.inner[base.len()..])) 211 Some(Self::new(&self.inner[base.len()..]))
198 } else { 212 } else {
199 None 213 None
200 } 214 }
201 } 215 }
202 216
482 } 496 }
483 497
484 #[cfg(test)] 498 #[cfg(test)]
485 mod tests { 499 mod tests {
486 use super::*; 500 use super::*;
501 use pretty_assertions::assert_eq;
487 502
488 #[test] 503 #[test]
489 fn test_path_states() { 504 fn test_path_states() {
490 assert_eq!( 505 assert_eq!(
491 Err(HgPathError::LeadingSlash(b"/".to_vec())), 506 Err(HgPathError::LeadingSlash(b"/".to_vec())),
710 HgPath::new(b"//conky/MOUNTPO\xc4\xb0NT"), 725 HgPath::new(b"//conky/MOUNTPO\xc4\xb0NT"),
711 HgPath::new(br"/foo/bar") 726 HgPath::new(br"/foo/bar")
712 ) 727 )
713 ); 728 );
714 } 729 }
715 } 730
731 #[test]
732 fn test_parent() {
733 let path = HgPath::new(b"");
734 assert_eq!(path.parent(), path);
735
736 let path = HgPath::new(b"a");
737 assert_eq!(path.parent(), HgPath::new(b""));
738
739 let path = HgPath::new(b"a/b");
740 assert_eq!(path.parent(), HgPath::new(b"a"));
741
742 let path = HgPath::new(b"a/other/b");
743 assert_eq!(path.parent(), HgPath::new(b"a/other"));
744 }
745 }