summaryrefslogtreecommitdiffstats
path: root/vendor/gix-ref/src/name.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix-ref/src/name.rs')
-rw-r--r--vendor/gix-ref/src/name.rs273
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'_')
+}