diff options
author | Florian Klink <flokli@flokli.de> | 2024-08-15T23·24+0300 |
---|---|---|
committer | clbot <clbot@tvl.fyi> | 2024-08-17T09·46+0000 |
commit | 8ea7d2b60eb4052d934820078c31ff25786376a4 (patch) | |
tree | da04e2f8f655f31c07a03d13ccbb1e0a7ed8e159 /tvix/castore/src/nodes/symlink_target.rs | |
parent | 49b173786cba575dbeb9d28fa7a62275d45ce41a (diff) |
refactor(tvix/castore): drop {Directory,File,Symlink}Node r/8505
Add a `SymlinkTarget` type to represent validated symlink targets. With this, no invalid states are representable, so we can make `Node` be just an enum of all three kind of types, and allow access to these fields directly. Change-Id: I20bdd480c8d5e64a827649f303c97023b7e390f2 Reviewed-on: https://cl.tvl.fyi/c/depot/+/12216 Reviewed-by: benjaminedwardwebb <benjaminedwardwebb@gmail.com> Autosubmit: flokli <flokli@flokli.de> Reviewed-by: Connor Brewster <cbrewster@hey.com> Tested-by: BuildkiteCI
Diffstat (limited to 'tvix/castore/src/nodes/symlink_target.rs')
-rw-r--r-- | tvix/castore/src/nodes/symlink_target.rs | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/tvix/castore/src/nodes/symlink_target.rs b/tvix/castore/src/nodes/symlink_target.rs new file mode 100644 index 000000000000..838cdaaeda5b --- /dev/null +++ b/tvix/castore/src/nodes/symlink_target.rs @@ -0,0 +1,82 @@ +// TODO: split out this error +use crate::ValidateNodeError; + +use bstr::ByteSlice; +use std::fmt::{self, Debug, Display}; + +/// A wrapper type for symlink targets. +/// Internally uses a [bytes::Bytes], but disallows empty targets and those +/// containing null bytes. +#[repr(transparent)] +#[derive(Clone, PartialEq, Eq)] +pub struct SymlinkTarget { + inner: bytes::Bytes, +} + +impl AsRef<[u8]> for SymlinkTarget { + fn as_ref(&self) -> &[u8] { + self.inner.as_ref() + } +} + +impl From<SymlinkTarget> for bytes::Bytes { + fn from(value: SymlinkTarget) -> Self { + value.inner + } +} + +impl TryFrom<bytes::Bytes> for SymlinkTarget { + type Error = ValidateNodeError; + + fn try_from(value: bytes::Bytes) -> Result<Self, Self::Error> { + if value.is_empty() || value.contains(&b'\0') { + return Err(ValidateNodeError::InvalidSymlinkTarget(value)); + } + + Ok(Self { inner: value }) + } +} + +impl TryFrom<&'static [u8]> for SymlinkTarget { + type Error = ValidateNodeError; + + fn try_from(value: &'static [u8]) -> Result<Self, Self::Error> { + if value.is_empty() || value.contains(&b'\0') { + return Err(ValidateNodeError::InvalidSymlinkTarget( + bytes::Bytes::from_static(value), + )); + } + + Ok(Self { + inner: bytes::Bytes::from_static(value), + }) + } +} + +impl TryFrom<&str> for SymlinkTarget { + type Error = ValidateNodeError; + + fn try_from(value: &str) -> Result<Self, Self::Error> { + if value.is_empty() { + return Err(ValidateNodeError::InvalidSymlinkTarget( + bytes::Bytes::copy_from_slice(value.as_bytes()), + )); + } + + Ok(Self { + inner: bytes::Bytes::copy_from_slice(value.as_bytes()), + }) + } +} + +impl Debug for SymlinkTarget { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(self.inner.as_bstr(), f) + } +} + +impl Display for SymlinkTarget { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(self.inner.as_bstr(), f) + } +} |