diff options
| author | Laurenz <laurmaedje@gmail.com> | 2023-06-26 13:57:21 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2023-06-27 18:40:17 +0200 |
| commit | 7b92bd7c340d9f9c094ed2fa57912049317d9b20 (patch) | |
| tree | b91399526ba94d87309d09d864df2935dd7a4d0a /src/util | |
| parent | 9c7f31870b4e1bf37df79ebbe1df9a56df83d878 (diff) | |
Basic package management
Diffstat (limited to 'src/util')
| -rw-r--r-- | src/util/bytes.rs (renamed from src/util/buffer.rs) | 18 | ||||
| -rw-r--r-- | src/util/mod.rs | 42 |
2 files changed, 47 insertions, 13 deletions
diff --git a/src/util/buffer.rs b/src/util/bytes.rs index 23fb9802..9165467b 100644 --- a/src/util/buffer.rs +++ b/src/util/bytes.rs @@ -5,11 +5,11 @@ use std::sync::Arc; use comemo::Prehashed; -/// A shared buffer that is cheap to clone and hash. +/// A shared byte buffer that is cheap to clone and hash. #[derive(Clone, Hash, Eq, PartialEq)] -pub struct Buffer(Arc<Prehashed<Cow<'static, [u8]>>>); +pub struct Bytes(Arc<Prehashed<Cow<'static, [u8]>>>); -impl Buffer { +impl Bytes { /// Create a buffer from a static byte slice. pub fn from_static(slice: &'static [u8]) -> Self { Self(Arc::new(Prehashed::new(Cow::Borrowed(slice)))) @@ -26,19 +26,19 @@ impl Buffer { } } -impl From<&[u8]> for Buffer { +impl From<&[u8]> for Bytes { fn from(slice: &[u8]) -> Self { Self(Arc::new(Prehashed::new(slice.to_vec().into()))) } } -impl From<Vec<u8>> for Buffer { +impl From<Vec<u8>> for Bytes { fn from(vec: Vec<u8>) -> Self { Self(Arc::new(Prehashed::new(vec.into()))) } } -impl Deref for Buffer { +impl Deref for Bytes { type Target = [u8]; fn deref(&self) -> &Self::Target { @@ -46,14 +46,14 @@ impl Deref for Buffer { } } -impl AsRef<[u8]> for Buffer { +impl AsRef<[u8]> for Bytes { fn as_ref(&self) -> &[u8] { self } } -impl Debug for Buffer { +impl Debug for Bytes { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.pad("Buffer(..)") + write!(f, "bytes({})", self.len()) } } diff --git a/src/util/mod.rs b/src/util/mod.rs index 71c5aefc..78c7bedf 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -2,9 +2,9 @@ pub mod fat; -mod buffer; +mod bytes; -pub use buffer::Buffer; +pub use bytes::Bytes; use std::fmt::{self, Debug, Formatter}; use std::hash::Hash; @@ -125,26 +125,60 @@ where pub trait PathExt { /// Lexically normalize a path. fn normalize(&self) -> PathBuf; + + /// Treat `self` as a virtual root relative to which the `path` is resolved. + /// + /// Returns `None` if the path lexically escapes the root. The path + /// might still escape through symlinks. + fn join_rooted(&self, path: &Path) -> Option<PathBuf>; } impl PathExt for Path { - #[tracing::instrument(skip_all)] fn normalize(&self) -> PathBuf { let mut out = PathBuf::new(); for component in self.components() { match component { Component::CurDir => {} Component::ParentDir => match out.components().next_back() { + Some(Component::RootDir) => {} Some(Component::Normal(_)) => { out.pop(); } _ => out.push(component), }, - _ => out.push(component), + Component::Prefix(_) | Component::RootDir | Component::Normal(_) => { + out.push(component) + } } } + if out.as_os_str().is_empty() { + out.push(Component::CurDir); + } out } + + fn join_rooted(&self, path: &Path) -> Option<PathBuf> { + let mut parts: Vec<_> = self.components().collect(); + let root = parts.len(); + for component in path.components() { + match component { + Component::Prefix(_) => return None, + Component::RootDir => parts.truncate(root), + Component::CurDir => {} + Component::ParentDir => { + if parts.len() <= root { + return None; + } + parts.pop(); + } + Component::Normal(_) => parts.push(component), + } + } + if parts.len() < root { + return None; + } + Some(parts.into_iter().collect()) + } } /// Format pieces separated with commas and a final "and" or "or". |
