about summary refs log tree commit diff
path: root/tvix/castore/src/path.rs
diff options
context:
space:
mode:
authoredef <edef@edef.eu>2024-05-01T11·49+0000
committeredef <edef@edef.eu>2024-05-01T13·40+0000
commit687291cebcffca7cc0d2a480444b9e6559486c1a (patch)
tree75db298263f8425fae62b366c0e9780145e2ee4f /tvix/castore/src/path.rs
parent1bb023df91640268fad1e74571b5dc94822a79b3 (diff)
feat(tvix/castore/path): more conversions r/8059
Change-Id: I3ee510b444848316df520dc8ca445d0f3c7d607f
Reviewed-on: https://cl.tvl.fyi/c/depot/+/11567
Tested-by: BuildkiteCI
Reviewed-by: flokli <flokli@flokli.de>
Diffstat (limited to 'tvix/castore/src/path.rs')
-rw-r--r--tvix/castore/src/path.rs39
1 files changed, 37 insertions, 2 deletions
diff --git a/tvix/castore/src/path.rs b/tvix/castore/src/path.rs
index d2b011947a87..7e0ad391c7ca 100644
--- a/tvix/castore/src/path.rs
+++ b/tvix/castore/src/path.rs
@@ -46,6 +46,11 @@ impl Path {
         Some(unsafe { Path::from_bytes_unchecked(bytes) })
     }
 
+    pub fn into_boxed_bytes(self: Box<Path>) -> Box<[u8]> {
+        // SAFETY: Box<Path> and Box<[u8]> have the same representation.
+        unsafe { mem::transmute(self) }
+    }
+
     /// Returns the path without its final component, if there is one.
     ///
     /// Note that the parent of a bare file name is [Path::ROOT].
@@ -100,7 +105,7 @@ impl Path {
         self.components().last()
     }
 
-    pub fn as_slice(&self) -> &[u8] {
+    pub fn as_bytes(&self) -> &[u8] {
         &self.inner
     }
 }
@@ -156,6 +161,19 @@ impl Borrow<Path> for PathBuf {
     }
 }
 
+impl From<Box<Path>> for PathBuf {
+    fn from(value: Box<Path>) -> Self {
+        // SAFETY: Box<Path> is always a valid path.
+        unsafe { PathBuf::from_bytes_unchecked(value.into_boxed_bytes().into_vec()) }
+    }
+}
+
+impl From<&Path> for PathBuf {
+    fn from(value: &Path) -> Self {
+        value.to_owned()
+    }
+}
+
 impl FromStr for PathBuf {
     type Err = std::io::Error;
 
@@ -178,6 +196,23 @@ impl Display for PathBuf {
     }
 }
 
+impl PathBuf {
+    /// Convert a byte vector to a PathBuf, without checking validity.
+    unsafe fn from_bytes_unchecked(bytes: Vec<u8>) -> PathBuf {
+        PathBuf { inner: bytes }
+    }
+
+    pub fn into_boxed_path(self) -> Box<Path> {
+        // SAFETY: Box<[u8]> and Box<Path> have the same representation,
+        // and PathBuf always contains a valid Path.
+        unsafe { mem::transmute(self.inner.into_boxed_slice()) }
+    }
+
+    pub fn into_bytes(self) -> Vec<u8> {
+        self.inner
+    }
+}
+
 #[cfg(test)]
 mod test {
     use super::{Path, PathBuf};
@@ -201,7 +236,7 @@ mod test {
     pub fn from_str(#[case] s: &str, #[case] num_components: usize) {
         let p: PathBuf = s.parse().expect("must parse");
 
-        assert_eq!(s.as_bytes(), p.as_slice(), "inner bytes mismatch");
+        assert_eq!(s.as_bytes(), p.as_bytes(), "inner bytes mismatch");
         assert_eq!(
             num_components,
             p.components().count(),