1 use std
::{borrow::Borrow, convert::TryFrom, path::Path}
;
3 use gix_object
::bstr
::{BStr, BString, ByteSlice}
;
5 use crate::{bstr::ByteVec, name::is_pseudo_ref, Category, FullName, FullNameRef, Namespace, PartialNameRef}
;
7 impl TryFrom
<&str> for FullName
{
8 type Error
= gix_validate
::reference
::name
::Error
;
10 fn try_from(value
: &str) -> Result
<Self, Self::Error
> {
12 gix_validate
::reference
::name(value
.as_bytes().as_bstr())?
.into(),
17 impl TryFrom
<String
> for FullName
{
18 type Error
= gix_validate
::reference
::name
::Error
;
20 fn try_from(value
: String
) -> Result
<Self, Self::Error
> {
21 gix_validate
::reference
::name(value
.as_bytes().as_bstr())?
;
22 Ok(FullName(value
.into()))
26 impl TryFrom
<&BStr
> for FullName
{
27 type Error
= gix_validate
::reference
::name
::Error
;
29 fn try_from(value
: &BStr
) -> Result
<Self, Self::Error
> {
30 Ok(FullName(gix_validate
::reference
::name(value
)?
.into()))
34 impl TryFrom
<BString
> for FullName
{
35 type Error
= gix_validate
::reference
::name
::Error
;
37 fn try_from(value
: BString
) -> Result
<Self, Self::Error
> {
38 gix_validate
::reference
::name(value
.as_ref())?
;
43 impl TryFrom
<&BString
> for FullName
{
44 type Error
= gix_validate
::reference
::name
::Error
;
46 fn try_from(value
: &BString
) -> Result
<Self, Self::Error
> {
47 gix_validate
::reference
::name(value
.as_ref())?
;
48 Ok(FullName(value
.clone()))
52 impl From
<FullName
> for BString
{
53 fn from(name
: FullName
) -> Self {
58 impl<'a
> From
<&'a FullNameRef
> for &'a BStr
{
59 fn from(name
: &'a FullNameRef
) -> Self {
64 impl<'a
> From
<&'a FullNameRef
> for FullName
{
65 fn from(value
: &'a FullNameRef
) -> Self {
66 FullName(value
.as_bstr().into())
70 impl std
::fmt
::Display
for FullName
{
71 fn fmt(&self, f
: &mut std
::fmt
::Formatter
<'_
>) -> std
::fmt
::Result
{
72 std
::fmt
::Display
::fmt(&self.0, f
)
77 /// Interpret this fully qualified reference name as partial name.
78 pub fn as_partial_name(&self) -> &PartialNameRef
{
79 PartialNameRef
::new_unchecked(self.0.as_bstr())
82 /// Convert this name into the relative path identifying the reference location.
83 pub fn to_path(&self) -> &Path
{
84 gix_path
::from_byte_slice(&self.0)
87 /// Return ourselves as byte string which is a valid refname
88 pub fn as_bstr(&self) -> &BStr
{
92 /// Strip well-known prefixes from the name and return it.
94 /// If there is no such prefix, the original name is returned.
95 pub fn shorten(&self) -> &BStr
{
96 self.category_and_short_name()
97 .map_or_else(|| self.0.as_bstr(), |(_
, short
)| short
)
100 /// Classify this name, or return `None` if it's unclassified.
101 pub fn category(&self) -> Option
<Category
<'_
>> {
102 self.category_and_short_name().map(|(cat
, _
)| cat
)
105 /// Classify this name, or return `None` if it's unclassified. If `Some`,
106 /// the shortened name is returned as well.
107 pub fn category_and_short_name(&self) -> Option
<(Category
<'_
>, &BStr
)> {
108 let name
= self.0.as_bstr();
109 for category
in &[Category
::Tag
, Category
::LocalBranch
, Category
::RemoteBranch
] {
110 if let Some(shortened
) = name
.strip_prefix(category
.prefix().as_bytes()) {
111 return Some((*category
, shortened
.as_bstr()));
118 Category
::WorktreePrivate
,
121 if name
.starts_with(category
.prefix().as_ref()) {
124 name
.strip_prefix(b
"refs/")
125 .expect("we checked for refs/* above")
131 if is_pseudo_ref(name
) {
132 Some((Category
::PseudoRef
, name
))
133 } else if let Some(shortened
) = name
.strip_prefix(Category
::MainPseudoRef
.prefix().as_bytes()) {
134 if shortened
.starts_with_str("refs/") {
135 (Category
::MainRef
, shortened
.as_bstr()).into()
137 is_pseudo_ref(shortened
.into()).then(|| (Category
::MainPseudoRef
, shortened
.as_bstr()))
139 } else if let Some(shortened_with_worktree_name
) =
140 name
.strip_prefix(Category
::LinkedPseudoRef { name: "".into() }
.prefix().as_bytes())
142 let (name
, shortened
) = shortened_with_worktree_name
.find_byte(b'
/'
).map(|pos
| {
144 shortened_with_worktree_name
[..pos
].as_bstr(),
145 shortened_with_worktree_name
[pos
+ 1..].as_bstr(),
148 if shortened
.starts_with_str("refs/") {
149 (Category
::LinkedRef { name }
, shortened
.as_bstr()).into()
151 is_pseudo_ref(shortened
).then(|| (Category
::LinkedPseudoRef { name }
, shortened
.as_bstr()))
160 /// Convert this name into the relative path, lossily, identifying the reference location relative to a repository
161 pub fn to_path(&self) -> &Path
{
162 gix_path
::from_byte_slice(&self.0)
165 /// Dissolve this instance and return the buffer.
166 pub fn into_inner(self) -> BString
{
170 /// Return ourselves as byte string which is a valid refname
171 pub fn as_bstr(&self) -> &BStr
{
175 /// Modify ourself so that we use `namespace` as prefix, if it is not yet in the `namespace`
176 pub fn prefix_namespace(&mut self, namespace
: &Namespace
) -> &mut Self {
177 if !self.0.starts_with_str(&namespace
.0) {
178 self.0.insert_str
(0, &namespace
.0);
183 /// Strip the given `namespace` off the beginning of this name, if it is in this namespace.
184 pub fn strip_namespace(&mut self, namespace
: &Namespace
) -> &mut Self {
185 if self.0.starts_with_str(&namespace
.0) {
186 let prev_len
= self.0.len();
187 self.0.copy_within(namespace
.0.len().., 0);
188 self.0.resize(prev_len
- namespace
.0.len(), 0);
193 /// Strip well-known prefixes from the name and return it.
195 /// If there is no such prefix, the original name is returned.
196 pub fn shorten(&self) -> &BStr
{
197 self.as_ref().shorten()
200 /// Classify this name, or return `None` if it's unclassified.
201 pub fn category(&self) -> Option
<crate::Category
<'_
>> {
202 self.as_ref().category()
205 /// Classify this name, or return `None` if it's unclassified. If `Some`,
206 /// the shortened name is returned as well.
207 pub fn category_and_short_name(&self) -> Option
<(crate::Category
<'_
>, &BStr
)> {
208 self.as_ref().category_and_short_name()
213 /// Return the file name portion of a full name, for instance `main` if the
214 /// full name was `refs/heads/main`.
215 pub fn file_name(&self) -> &BStr
{
216 self.0.rsplitn(2, |b
| *b
== b'
/'
).next().expect("valid ref").as_bstr()
220 impl Borrow
<FullNameRef
> for FullName
{
222 fn borrow(&self) -> &FullNameRef
{
223 FullNameRef
::new_unchecked(self.0.as_bstr())
227 impl AsRef
<FullNameRef
> for FullName
{
228 fn as_ref(&self) -> &FullNameRef
{
233 impl ToOwned
for FullNameRef
{
234 type Owned
= FullName
;
236 fn to_owned(&self) -> Self::Owned
{
237 FullName(self.0.to_owned())