diff options
Diffstat (limited to 'tvix/castore/src/proto')
-rw-r--r-- | tvix/castore/src/proto/mod.rs | 40 | ||||
-rw-r--r-- | tvix/castore/src/proto/tests/mod.rs | 21 |
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") + ) +} |