diff options
Diffstat (limited to 'vendor/gix-ref/src/name.rs')
-rw-r--r-- | vendor/gix-ref/src/name.rs | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/vendor/gix-ref/src/name.rs b/vendor/gix-ref/src/name.rs new file mode 100644 index 000000000..dbf96c1e5 --- /dev/null +++ b/vendor/gix-ref/src/name.rs @@ -0,0 +1,273 @@ +use std::{convert, convert::Infallible, ffi::OsStr, path::Path}; + +use gix_object::bstr::{BStr, BString, ByteSlice, ByteVec}; + +use crate::{Category, FullName, FullNameRef, PartialName, PartialNameRef}; + +/// The error used in the [`PartialNameRef`][super::PartialNameRef]::try_from(…) implementations. +pub type Error = gix_validate::reference::name::Error; + +impl<'a> Category<'a> { + /// Return the prefix that would contain all references of our kind, or an empty string if the reference would + /// be directly inside of the [`git_dir()`][crate::file::Store::git_dir()]. + pub fn prefix(&self) -> &BStr { + match self { + Category::Tag => b"refs/tags/".as_bstr(), + Category::LocalBranch => b"refs/heads/".as_bstr(), + Category::RemoteBranch => b"refs/remotes/".as_bstr(), + Category::Note => b"refs/notes/".as_bstr(), + Category::MainPseudoRef => b"main-worktree/".as_bstr(), + Category::MainRef => b"main-worktree/refs/".as_bstr(), + Category::PseudoRef => b"".as_bstr(), + Category::LinkedPseudoRef { .. } => b"worktrees/".as_bstr(), + Category::LinkedRef { .. } => b"worktrees/".as_bstr(), + Category::Bisect => b"refs/bisect/".as_bstr(), + Category::Rewritten => b"refs/rewritten/".as_bstr(), + Category::WorktreePrivate => b"refs/worktree/".as_bstr(), + } + } + + /// Returns true if the category is private to their worktrees, and never shared with other worktrees. + pub fn is_worktree_private(&self) -> bool { + matches!( + self, + Category::MainPseudoRef + | Category::PseudoRef + | Category::LinkedPseudoRef { .. } + | Category::WorktreePrivate + | Category::Rewritten + | Category::Bisect + ) + } +} + +impl FullNameRef { + pub(crate) fn new_unchecked(v: &BStr) -> &Self { + // SAFETY: FullNameRef is transparent and equivalent to a &BStr if provided as reference + #[allow(unsafe_code)] + unsafe { + std::mem::transmute(v) + } + } +} + +impl PartialNameRef { + pub(crate) fn new_unchecked(v: &BStr) -> &Self { + // SAFETY: PartialNameRef is transparent and equivalent to a &BStr if provided as reference + #[allow(unsafe_code)] + unsafe { + std::mem::transmute(v) + } + } +} + +impl PartialNameRef { + pub(crate) fn looks_like_full_name(&self) -> bool { + let name = self.0.as_bstr(); + name.starts_with_str("refs/") + || name.starts_with(Category::MainPseudoRef.prefix()) + || name.starts_with(Category::LinkedPseudoRef { name: "".into() }.prefix()) + || is_pseudo_ref(name) + } + pub(crate) fn construct_full_name_ref<'buf>( + &self, + add_refs_prefix: bool, + inbetween: &str, + buf: &'buf mut BString, + ) -> &'buf FullNameRef { + buf.clear(); + if add_refs_prefix && !self.looks_like_full_name() { + buf.push_str("refs/"); + } + if !inbetween.is_empty() { + buf.push_str(inbetween); + buf.push_byte(b'/'); + } + buf.extend_from_slice(&self.0); + FullNameRef::new_unchecked(buf.as_bstr()) + } +} + +impl PartialNameRef { + /// Convert this name into the relative path possibly identifying the reference location. + /// Note that it may be only a partial path though. + pub fn to_partial_path(&self) -> &Path { + gix_path::from_byte_slice(self.0.as_bstr()) + } + + /// Provide the name as binary string which is known to be a valid partial ref name. + pub fn as_bstr(&self) -> &BStr { + &self.0 + } +} + +impl PartialName { + /// Append the `component` to ourselves and validate the newly created partial path. + pub fn join(self, component: impl AsRef<[u8]>) -> Result<Self, Error> { + let mut b = self.0; + b.push_byte(b'/'); + b.extend(component.as_ref()); + gix_validate::reference::name_partial(b.as_ref())?; + Ok(PartialName(b)) + } +} + +impl<'a> convert::TryFrom<&'a BStr> for &'a FullNameRef { + type Error = Error; + + fn try_from(v: &'a BStr) -> Result<Self, Self::Error> { + Ok(FullNameRef::new_unchecked(gix_validate::reference::name(v)?)) + } +} + +impl<'a> From<&'a FullNameRef> for &'a PartialNameRef { + fn from(v: &'a FullNameRef) -> Self { + PartialNameRef::new_unchecked(v.0.as_bstr()) + } +} + +impl<'a> convert::TryFrom<&'a OsStr> for &'a PartialNameRef { + type Error = Error; + + fn try_from(v: &'a OsStr) -> Result<Self, Self::Error> { + let v = gix_path::os_str_into_bstr(v).map_err(|_| { + Error::Tag(gix_validate::tag::name::Error::InvalidByte { + byte: "<unknown encoding>".into(), + }) + })?; + Ok(PartialNameRef::new_unchecked(gix_validate::reference::name_partial( + v.as_bstr(), + )?)) + } +} + +mod impls { + use std::borrow::Borrow; + + use crate::{bstr::ByteSlice, PartialName, PartialNameRef}; + + impl Borrow<PartialNameRef> for PartialName { + #[inline] + fn borrow(&self) -> &PartialNameRef { + PartialNameRef::new_unchecked(self.0.as_bstr()) + } + } + + impl AsRef<PartialNameRef> for PartialName { + fn as_ref(&self) -> &PartialNameRef { + self.borrow() + } + } + + impl ToOwned for PartialNameRef { + type Owned = PartialName; + + fn to_owned(&self) -> Self::Owned { + PartialName(self.0.to_owned()) + } + } +} + +impl<'a> convert::TryFrom<&'a BString> for &'a PartialNameRef { + type Error = Error; + + fn try_from(v: &'a BString) -> Result<Self, Self::Error> { + Ok(PartialNameRef::new_unchecked(gix_validate::reference::name_partial( + v.as_ref(), + )?)) + } +} + +impl<'a> convert::TryFrom<&'a BStr> for &'a PartialNameRef { + type Error = Error; + + fn try_from(v: &'a BStr) -> Result<Self, Self::Error> { + Ok(PartialNameRef::new_unchecked(gix_validate::reference::name_partial(v)?)) + } +} + +impl<'a> convert::TryFrom<&'a PartialName> for &'a PartialNameRef { + type Error = Error; + + fn try_from(v: &'a PartialName) -> Result<Self, Self::Error> { + Ok(PartialNameRef::new_unchecked(v.0.as_bstr())) + } +} + +impl<'a> convert::TryFrom<&'a str> for &'a FullNameRef { + type Error = Error; + + fn try_from(v: &'a str) -> Result<Self, Self::Error> { + let v = v.as_bytes().as_bstr(); + Ok(FullNameRef::new_unchecked(gix_validate::reference::name(v)?)) + } +} + +impl<'a> convert::TryFrom<&'a str> for &'a PartialNameRef { + type Error = Error; + + fn try_from(v: &'a str) -> Result<Self, Self::Error> { + let v = v.as_bytes().as_bstr(); + Ok(PartialNameRef::new_unchecked(gix_validate::reference::name_partial(v)?)) + } +} + +impl<'a> convert::TryFrom<&'a str> for PartialName { + type Error = Error; + + fn try_from(v: &'a str) -> Result<Self, Self::Error> { + let v = v.as_bytes().as_bstr(); + Ok(PartialName(gix_validate::reference::name_partial(v)?.to_owned())) + } +} + +impl<'a> convert::TryFrom<&'a FullName> for &'a PartialNameRef { + type Error = Infallible; + + fn try_from(v: &'a FullName) -> Result<Self, Self::Error> { + Ok(v.as_ref().as_partial_name()) + } +} + +impl<'a> convert::TryFrom<&'a String> for &'a FullNameRef { + type Error = Error; + + fn try_from(v: &'a String) -> Result<Self, Self::Error> { + let v = v.as_bytes().as_bstr(); + Ok(FullNameRef::new_unchecked(gix_validate::reference::name(v)?)) + } +} + +impl<'a> convert::TryFrom<&'a String> for &'a PartialNameRef { + type Error = Error; + + fn try_from(v: &'a String) -> Result<Self, Self::Error> { + let v = v.as_bytes().as_bstr(); + Ok(PartialNameRef::new_unchecked(gix_validate::reference::name_partial(v)?)) + } +} + +impl convert::TryFrom<String> for PartialName { + type Error = Error; + + fn try_from(v: String) -> Result<Self, Self::Error> { + gix_validate::reference::name_partial(v.as_bytes().as_bstr())?; + Ok(PartialName(v.into())) + } +} + +impl convert::TryFrom<BString> for PartialName { + type Error = Error; + + fn try_from(v: BString) -> Result<Self, Self::Error> { + gix_validate::reference::name_partial(v.as_ref())?; + Ok(PartialName(v)) + } +} + +/// Note that this method is disagreeing with gix_validate as it allows dashes '-' for some reason. +/// Since partial names cannot be created with dashes inside we adjusted this as it's probably unintended or git creates pseudo-refs +/// which wouldn't pass its safety checks. +pub(crate) fn is_pseudo_ref<'a>(name: impl Into<&'a BStr>) -> bool { + name.into().bytes().all(|b| b.is_ascii_uppercase() || b == b'_') +} |