about summary refs log tree commit diff
path: root/tvix/castore/src/proto
diff options
context:
space:
mode:
Diffstat (limited to 'tvix/castore/src/proto')
-rw-r--r--tvix/castore/src/proto/mod.rs40
-rw-r--r--tvix/castore/src/proto/tests/mod.rs21
2 files changed, 45 insertions, 16 deletions
diff --git a/tvix/castore/src/proto/mod.rs b/tvix/castore/src/proto/mod.rs
index 15e55ad049cf..89c68a4ad97b 100644
--- a/tvix/castore/src/proto/mod.rs
+++ b/tvix/castore/src/proto/mod.rs
@@ -124,7 +124,7 @@ impl TryFrom<Directory> for crate::Directory {
                 Node {
                     node: Some(node::Node::Directory(e)),
                 }
-                .into_name_and_node()?,
+                .try_into_name_and_node()?,
             );
         }
 
@@ -133,7 +133,7 @@ impl TryFrom<Directory> for crate::Directory {
                 Node {
                     node: Some(node::Node::File(e)),
                 }
-                .into_name_and_node()?,
+                .try_into_name_and_node()?,
             )
         }
 
@@ -142,7 +142,7 @@ impl TryFrom<Directory> for crate::Directory {
                 Node {
                     node: Some(node::Node::Symlink(e)),
                 }
-                .into_name_and_node()?,
+                .try_into_name_and_node()?,
             )
         }
 
@@ -191,22 +191,20 @@ impl From<crate::Directory> for Directory {
 }
 
 impl Node {
-    /// Converts a proto [Node] to a [crate::Node], and splits off the name.
-    pub fn into_name_and_node(self) -> Result<(PathComponent, crate::Node), DirectoryError> {
-        let (unvalidated_name, node) = self.into_name_bytes_and_node()?;
+    /// Converts a proto [Node] to a [crate::Node], and splits off the name as a [PathComponent].
+    pub fn try_into_name_and_node(self) -> Result<(PathComponent, crate::Node), DirectoryError> {
+        let (name_bytes, node) = self.try_into_unchecked_name_and_checked_node()?;
         Ok((
-            unvalidated_name
-                .try_into()
-                .map_err(DirectoryError::InvalidName)?,
+            name_bytes.try_into().map_err(DirectoryError::InvalidName)?,
             node,
         ))
     }
 
-    /// Converts a proto [Node] to a [crate::Node], and splits off the name and returns it as a
-    /// [bytes::Bytes].
-    ///
-    /// Note: the returned name is not validated.
-    pub fn into_name_bytes_and_node(self) -> Result<(bytes::Bytes, crate::Node), DirectoryError> {
+    /// Converts a proto [Node] to a [crate::Node], and splits off the name as a
+    /// [bytes::Bytes] without doing any checking of it.
+    fn try_into_unchecked_name_and_checked_node(
+        self,
+    ) -> Result<(bytes::Bytes, crate::Node), DirectoryError> {
         match self.node.ok_or_else(|| DirectoryError::NoNodeSet)? {
             node::Node::Directory(n) => {
                 let digest = B3Digest::try_from(n.digest)
@@ -247,6 +245,20 @@ impl Node {
         }
     }
 
+    /// Converts a proto [Node] to a [crate::Node], and splits off the name and returns it as a
+    /// [bytes::Bytes].
+    ///
+    /// The name must be empty.
+    pub fn try_into_anonymous_node(self) -> Result<crate::Node, DirectoryError> {
+        let (name, node) = Self::try_into_unchecked_name_and_checked_node(self)?;
+
+        if !name.is_empty() {
+            return Err(DirectoryError::NameInAnonymousNode);
+        }
+
+        Ok(node)
+    }
+
     /// Constructs a [Node] from a name and [crate::Node].
     /// The name is a [bytes::Bytes], not a [PathComponent], as we have use an
     /// empty name in some places.
diff --git a/tvix/castore/src/proto/tests/mod.rs b/tvix/castore/src/proto/tests/mod.rs
index 8efb92870374..9f6330914bff 100644
--- a/tvix/castore/src/proto/tests/mod.rs
+++ b/tvix/castore/src/proto/tests/mod.rs
@@ -1,4 +1,5 @@
 use super::{node, Node, SymlinkNode};
+use crate::DirectoryError;
 
 mod directory;
 
@@ -11,7 +12,7 @@ fn convert_symlink_empty_target_invalid() {
             target: "".into(),
         })),
     }
-    .into_name_and_node()
+    .try_into_name_and_node()
     .expect_err("must fail validation");
 }
 
@@ -25,6 +26,22 @@ fn convert_symlink_target_null_byte_invalid() {
             target: "foo\0".into(),
         })),
     }
-    .into_name_and_node()
+    .try_into_name_and_node()
     .expect_err("must fail validation");
 }
+
+/// Create a node with a name, and ensure our ano
+#[test]
+fn convert_anonymous_with_name_fail() {
+    assert_eq!(
+        DirectoryError::NameInAnonymousNode,
+        Node {
+            node: Some(node::Node::Symlink(SymlinkNode {
+                name: "foo".into(),
+                target: "somewhereelse".into(),
+            })),
+        }
+        .try_into_anonymous_node()
+        .expect_err("must fail")
+    )
+}