summaryrefslogtreecommitdiffstats
path: root/vendor/gix-ref/src/fullname.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix-ref/src/fullname.rs')
-rw-r--r--vendor/gix-ref/src/fullname.rs238
1 files changed, 238 insertions, 0 deletions
diff --git a/vendor/gix-ref/src/fullname.rs b/vendor/gix-ref/src/fullname.rs
new file mode 100644
index 000000000..8870e6219
--- /dev/null
+++ b/vendor/gix-ref/src/fullname.rs
@@ -0,0 +1,238 @@
+use std::{borrow::Borrow, convert::TryFrom, path::Path};
+
+use gix_object::bstr::{BStr, BString, ByteSlice};
+
+use crate::{bstr::ByteVec, name::is_pseudo_ref, Category, FullName, FullNameRef, Namespace, PartialNameRef};
+
+impl TryFrom<&str> for FullName {
+ type Error = gix_validate::refname::Error;
+
+ fn try_from(value: &str) -> Result<Self, Self::Error> {
+ Ok(FullName(gix_validate::refname(value.as_bytes().as_bstr())?.into()))
+ }
+}
+
+impl TryFrom<String> for FullName {
+ type Error = gix_validate::refname::Error;
+
+ fn try_from(value: String) -> Result<Self, Self::Error> {
+ gix_validate::refname(value.as_bytes().as_bstr())?;
+ Ok(FullName(value.into()))
+ }
+}
+
+impl TryFrom<&BStr> for FullName {
+ type Error = gix_validate::refname::Error;
+
+ fn try_from(value: &BStr) -> Result<Self, Self::Error> {
+ Ok(FullName(gix_validate::refname(value)?.into()))
+ }
+}
+
+impl TryFrom<BString> for FullName {
+ type Error = gix_validate::refname::Error;
+
+ fn try_from(value: BString) -> Result<Self, Self::Error> {
+ gix_validate::refname(value.as_ref())?;
+ Ok(FullName(value))
+ }
+}
+
+impl TryFrom<&BString> for FullName {
+ type Error = gix_validate::refname::Error;
+
+ fn try_from(value: &BString) -> Result<Self, Self::Error> {
+ gix_validate::refname(value.as_ref())?;
+ Ok(FullName(value.clone()))
+ }
+}
+
+impl From<FullName> for BString {
+ fn from(name: FullName) -> Self {
+ name.0
+ }
+}
+
+impl<'a> From<&'a FullNameRef> for &'a BStr {
+ fn from(name: &'a FullNameRef) -> Self {
+ &name.0
+ }
+}
+
+impl<'a> From<&'a FullNameRef> for FullName {
+ fn from(value: &'a FullNameRef) -> Self {
+ FullName(value.as_bstr().into())
+ }
+}
+
+impl std::fmt::Display for FullName {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(&self.0, f)
+ }
+}
+
+impl FullNameRef {
+ /// Interpret this fully qualified reference name as partial name.
+ pub fn as_partial_name(&self) -> &PartialNameRef {
+ PartialNameRef::new_unchecked(self.0.as_bstr())
+ }
+
+ /// Convert this name into the relative path identifying the reference location.
+ pub fn to_path(&self) -> &Path {
+ gix_path::from_byte_slice(&self.0)
+ }
+
+ /// Return ourselves as byte string which is a valid refname
+ pub fn as_bstr(&self) -> &BStr {
+ &self.0
+ }
+
+ /// Strip well-known prefixes from the name and return it.
+ ///
+ /// If there is no such prefix, the original name is returned.
+ pub fn shorten(&self) -> &BStr {
+ self.category_and_short_name()
+ .map(|(_, short)| short)
+ .unwrap_or_else(|| self.0.as_bstr())
+ }
+
+ /// Classify this name, or return `None` if it's unclassified.
+ pub fn category(&self) -> Option<Category<'_>> {
+ self.category_and_short_name().map(|(cat, _)| cat)
+ }
+
+ /// Classify this name, or return `None` if it's unclassified. If `Some`,
+ /// the shortened name is returned as well.
+ pub fn category_and_short_name(&self) -> Option<(Category<'_>, &BStr)> {
+ let name = self.0.as_bstr();
+ for category in &[Category::Tag, Category::LocalBranch, Category::RemoteBranch] {
+ if let Some(shortened) = name.strip_prefix(category.prefix().as_bytes()) {
+ return Some((*category, shortened.as_bstr()));
+ }
+ }
+
+ for category in &[
+ Category::Note,
+ Category::Bisect,
+ Category::WorktreePrivate,
+ Category::Rewritten,
+ ] {
+ if name.starts_with(category.prefix().as_ref()) {
+ return Some((
+ *category,
+ name.strip_prefix(b"refs/")
+ .expect("we checked for refs/* above")
+ .as_bstr(),
+ ));
+ }
+ }
+
+ if is_pseudo_ref(name) {
+ Some((Category::PseudoRef, name))
+ } else if let Some(shortened) = name.strip_prefix(Category::MainPseudoRef.prefix().as_bytes()) {
+ if shortened.starts_with_str("refs/") {
+ (Category::MainRef, shortened.as_bstr()).into()
+ } else {
+ is_pseudo_ref(shortened).then(|| (Category::MainPseudoRef, shortened.as_bstr()))
+ }
+ } else if let Some(shortened_with_worktree_name) =
+ name.strip_prefix(Category::LinkedPseudoRef { name: "".into() }.prefix().as_bytes())
+ {
+ let (name, shortened) = shortened_with_worktree_name.find_byte(b'/').map(|pos| {
+ (
+ shortened_with_worktree_name[..pos].as_bstr(),
+ shortened_with_worktree_name[pos + 1..].as_bstr(),
+ )
+ })?;
+ if shortened.starts_with_str("refs/") {
+ (Category::LinkedRef { name }, shortened.as_bstr()).into()
+ } else {
+ is_pseudo_ref(shortened).then(|| (Category::LinkedPseudoRef { name }, shortened.as_bstr()))
+ }
+ } else {
+ None
+ }
+ }
+}
+
+impl FullName {
+ /// Convert this name into the relative path, lossily, identifying the reference location relative to a repository
+ pub fn to_path(&self) -> &Path {
+ gix_path::from_byte_slice(&self.0)
+ }
+
+ /// Dissolve this instance and return the buffer.
+ pub fn into_inner(self) -> BString {
+ self.0
+ }
+
+ /// Return ourselves as byte string which is a valid refname
+ pub fn as_bstr(&self) -> &BStr {
+ self.0.as_bstr()
+ }
+
+ /// Modify ourself so that we use `namespace` as prefix, if it is not yet in the `namespace`
+ pub fn prefix_namespace(&mut self, namespace: &Namespace) -> &mut Self {
+ if !self.0.starts_with_str(&namespace.0) {
+ self.0.insert_str(0, &namespace.0);
+ }
+ self
+ }
+
+ /// Strip the given `namespace` off the beginning of this name, if it is in this namespace.
+ pub fn strip_namespace(&mut self, namespace: &Namespace) -> &mut Self {
+ if self.0.starts_with_str(&namespace.0) {
+ let prev_len = self.0.len();
+ self.0.copy_within(namespace.0.len().., 0);
+ self.0.resize(prev_len - namespace.0.len(), 0);
+ }
+ self
+ }
+
+ /// Strip well-known prefixes from the name and return it.
+ ///
+ /// If there is no such prefix, the original name is returned.
+ pub fn shorten(&self) -> &BStr {
+ self.as_ref().shorten()
+ }
+
+ /// Classify this name, or return `None` if it's unclassified.
+ pub fn category(&self) -> Option<crate::Category<'_>> {
+ self.as_ref().category()
+ }
+
+ /// Classify this name, or return `None` if it's unclassified. If `Some`,
+ /// the shortened name is returned as well.
+ pub fn category_and_short_name(&self) -> Option<(crate::Category<'_>, &BStr)> {
+ self.as_ref().category_and_short_name()
+ }
+}
+
+impl FullNameRef {
+ /// Return the file name portion of a full name, for instance `main` if the
+ /// full name was `refs/heads/main`.
+ pub fn file_name(&self) -> &BStr {
+ self.0.rsplitn(2, |b| *b == b'/').next().expect("valid ref").as_bstr()
+ }
+}
+
+impl Borrow<FullNameRef> for FullName {
+ #[inline]
+ fn borrow(&self) -> &FullNameRef {
+ FullNameRef::new_unchecked(self.0.as_bstr())
+ }
+}
+
+impl AsRef<FullNameRef> for FullName {
+ fn as_ref(&self) -> &FullNameRef {
+ self.borrow()
+ }
+}
+
+impl ToOwned for FullNameRef {
+ type Owned = FullName;
+
+ fn to_owned(&self) -> Self::Owned {
+ FullName(self.0.to_owned())
+ }
+}