]> git.proxmox.com Git - rustc.git/blob - vendor/gix-ref/src/fullname.rs
New upstream version 1.74.1+dfsg1
[rustc.git] / vendor / gix-ref / src / fullname.rs
1 use std::{borrow::Borrow, convert::TryFrom, path::Path};
2
3 use gix_object::bstr::{BStr, BString, ByteSlice};
4
5 use crate::{bstr::ByteVec, name::is_pseudo_ref, Category, FullName, FullNameRef, Namespace, PartialNameRef};
6
7 impl TryFrom<&str> for FullName {
8 type Error = gix_validate::reference::name::Error;
9
10 fn try_from(value: &str) -> Result<Self, Self::Error> {
11 Ok(FullName(
12 gix_validate::reference::name(value.as_bytes().as_bstr())?.into(),
13 ))
14 }
15 }
16
17 impl TryFrom<String> for FullName {
18 type Error = gix_validate::reference::name::Error;
19
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()))
23 }
24 }
25
26 impl TryFrom<&BStr> for FullName {
27 type Error = gix_validate::reference::name::Error;
28
29 fn try_from(value: &BStr) -> Result<Self, Self::Error> {
30 Ok(FullName(gix_validate::reference::name(value)?.into()))
31 }
32 }
33
34 impl TryFrom<BString> for FullName {
35 type Error = gix_validate::reference::name::Error;
36
37 fn try_from(value: BString) -> Result<Self, Self::Error> {
38 gix_validate::reference::name(value.as_ref())?;
39 Ok(FullName(value))
40 }
41 }
42
43 impl TryFrom<&BString> for FullName {
44 type Error = gix_validate::reference::name::Error;
45
46 fn try_from(value: &BString) -> Result<Self, Self::Error> {
47 gix_validate::reference::name(value.as_ref())?;
48 Ok(FullName(value.clone()))
49 }
50 }
51
52 impl From<FullName> for BString {
53 fn from(name: FullName) -> Self {
54 name.0
55 }
56 }
57
58 impl<'a> From<&'a FullNameRef> for &'a BStr {
59 fn from(name: &'a FullNameRef) -> Self {
60 &name.0
61 }
62 }
63
64 impl<'a> From<&'a FullNameRef> for FullName {
65 fn from(value: &'a FullNameRef) -> Self {
66 FullName(value.as_bstr().into())
67 }
68 }
69
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)
73 }
74 }
75
76 impl FullNameRef {
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())
80 }
81
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)
85 }
86
87 /// Return ourselves as byte string which is a valid refname
88 pub fn as_bstr(&self) -> &BStr {
89 &self.0
90 }
91
92 /// Strip well-known prefixes from the name and return it.
93 ///
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)
98 }
99
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)
103 }
104
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()));
112 }
113 }
114
115 for category in &[
116 Category::Note,
117 Category::Bisect,
118 Category::WorktreePrivate,
119 Category::Rewritten,
120 ] {
121 if name.starts_with(category.prefix().as_ref()) {
122 return Some((
123 *category,
124 name.strip_prefix(b"refs/")
125 .expect("we checked for refs/* above")
126 .as_bstr(),
127 ));
128 }
129 }
130
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()
136 } else {
137 is_pseudo_ref(shortened.into()).then(|| (Category::MainPseudoRef, shortened.as_bstr()))
138 }
139 } else if let Some(shortened_with_worktree_name) =
140 name.strip_prefix(Category::LinkedPseudoRef { name: "".into() }.prefix().as_bytes())
141 {
142 let (name, shortened) = shortened_with_worktree_name.find_byte(b'/').map(|pos| {
143 (
144 shortened_with_worktree_name[..pos].as_bstr(),
145 shortened_with_worktree_name[pos + 1..].as_bstr(),
146 )
147 })?;
148 if shortened.starts_with_str("refs/") {
149 (Category::LinkedRef { name }, shortened.as_bstr()).into()
150 } else {
151 is_pseudo_ref(shortened).then(|| (Category::LinkedPseudoRef { name }, shortened.as_bstr()))
152 }
153 } else {
154 None
155 }
156 }
157 }
158
159 impl FullName {
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)
163 }
164
165 /// Dissolve this instance and return the buffer.
166 pub fn into_inner(self) -> BString {
167 self.0
168 }
169
170 /// Return ourselves as byte string which is a valid refname
171 pub fn as_bstr(&self) -> &BStr {
172 self.0.as_bstr()
173 }
174
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);
179 }
180 self
181 }
182
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);
189 }
190 self
191 }
192
193 /// Strip well-known prefixes from the name and return it.
194 ///
195 /// If there is no such prefix, the original name is returned.
196 pub fn shorten(&self) -> &BStr {
197 self.as_ref().shorten()
198 }
199
200 /// Classify this name, or return `None` if it's unclassified.
201 pub fn category(&self) -> Option<crate::Category<'_>> {
202 self.as_ref().category()
203 }
204
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()
209 }
210 }
211
212 impl FullNameRef {
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()
217 }
218 }
219
220 impl Borrow<FullNameRef> for FullName {
221 #[inline]
222 fn borrow(&self) -> &FullNameRef {
223 FullNameRef::new_unchecked(self.0.as_bstr())
224 }
225 }
226
227 impl AsRef<FullNameRef> for FullName {
228 fn as_ref(&self) -> &FullNameRef {
229 self.borrow()
230 }
231 }
232
233 impl ToOwned for FullNameRef {
234 type Owned = FullName;
235
236 fn to_owned(&self) -> Self::Owned {
237 FullName(self.0.to_owned())
238 }
239 }