feat(tvix/castore/path): single-component paths are children of ROOT
The empty path (Path::ROOT) is explicitly a valid path, and "foo" is simply a child of "". The root itself is the only path without a parent. Change-Id: Iff00dc8aed89eaf98702b664c0df658bd5a1d88a Reviewed-on: https://cl.tvl.fyi/c/depot/+/11569 Reviewed-by: flokli <flokli@flokli.de> Tested-by: BuildkiteCI
This commit is contained in:
parent
aa53338ddb
commit
1bb023df91
1 changed files with 21 additions and 11 deletions
|
|
@ -46,11 +46,25 @@ impl Path {
|
||||||
Some(unsafe { Path::from_bytes_unchecked(bytes) })
|
Some(unsafe { Path::from_bytes_unchecked(bytes) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the path without its final component, if there is one.
|
||||||
|
///
|
||||||
|
/// Note that the parent of a bare file name is [Path::ROOT].
|
||||||
|
/// [Path::ROOT] is the only path without a parent.
|
||||||
pub fn parent(&self) -> Option<&Path> {
|
pub fn parent(&self) -> Option<&Path> {
|
||||||
let (parent, _file_name) = self.inner.rsplit_once_str(b"/")?;
|
// The root does not have a parent.
|
||||||
|
if self.inner.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
// SAFETY: The parent of a valid Path is a valid Path.
|
Some(
|
||||||
Some(unsafe { Path::from_bytes_unchecked(parent) })
|
if let Some((parent, _file_name)) = self.inner.rsplit_once_str(b"/") {
|
||||||
|
// SAFETY: The parent of a valid Path is a valid Path.
|
||||||
|
unsafe { Path::from_bytes_unchecked(parent) }
|
||||||
|
} else {
|
||||||
|
// The parent of a bare file name is the root.
|
||||||
|
Path::ROOT
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn join(&self, name: &[u8]) -> Result<PathBuf, std::io::Error> {
|
pub fn join(&self, name: &[u8]) -> Result<PathBuf, std::io::Error> {
|
||||||
|
|
@ -166,7 +180,7 @@ impl Display for PathBuf {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::PathBuf;
|
use super::{Path, PathBuf};
|
||||||
use bstr::ByteSlice;
|
use bstr::ByteSlice;
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
|
||||||
|
|
@ -214,6 +228,7 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
|
#[case("foo", "")]
|
||||||
#[case("foo/bar", "foo")]
|
#[case("foo/bar", "foo")]
|
||||||
#[case("foo2/bar2", "foo2")]
|
#[case("foo2/bar2", "foo2")]
|
||||||
#[case("foo/bar/baz", "foo/bar")]
|
#[case("foo/bar/baz", "foo/bar")]
|
||||||
|
|
@ -222,13 +237,8 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case::empty("")]
|
pub fn no_parent() {
|
||||||
#[case::single("foo")]
|
assert!(Path::ROOT.parent().is_none());
|
||||||
pub fn no_parent(#[case] p: PathBuf) {
|
|
||||||
assert!(p.parent().is_none());
|
|
||||||
|
|
||||||
// same for Path
|
|
||||||
assert!(p.as_ref().parent().is_none());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue