]> git.proxmox.com Git - rustc.git/blob - vendor/gix-ref/src/name.rs
b21fdaf567d7b4349ff0afe349de7d112ec8db42
[rustc.git] / vendor / gix-ref / src / name.rs
1 use std::{convert, convert::Infallible, ffi::OsStr, path::Path};
2
3 use gix_object::bstr::{BStr, BString, ByteSlice, ByteVec};
4
5 use crate::{Category, FullName, FullNameRef, PartialName, PartialNameRef};
6
7 /// The error used in the [`PartialNameRef`][super::PartialNameRef]`::try_from`(…) implementations.
8 pub type Error = gix_validate::reference::name::Error;
9
10 impl<'a> Category<'a> {
11 /// Return the prefix that would contain all references of our kind, or an empty string if the reference would
12 /// be directly inside of the [`git_dir()`][crate::file::Store::git_dir()].
13 pub fn prefix(&self) -> &BStr {
14 match self {
15 Category::Tag => b"refs/tags/".as_bstr(),
16 Category::LocalBranch => b"refs/heads/".as_bstr(),
17 Category::RemoteBranch => b"refs/remotes/".as_bstr(),
18 Category::Note => b"refs/notes/".as_bstr(),
19 Category::MainPseudoRef => b"main-worktree/".as_bstr(),
20 Category::MainRef => b"main-worktree/refs/".as_bstr(),
21 Category::PseudoRef => b"".as_bstr(),
22 Category::LinkedPseudoRef { .. } => b"worktrees/".as_bstr(),
23 Category::LinkedRef { .. } => b"worktrees/".as_bstr(),
24 Category::Bisect => b"refs/bisect/".as_bstr(),
25 Category::Rewritten => b"refs/rewritten/".as_bstr(),
26 Category::WorktreePrivate => b"refs/worktree/".as_bstr(),
27 }
28 }
29
30 /// Returns true if the category is private to their worktrees, and never shared with other worktrees.
31 pub fn is_worktree_private(&self) -> bool {
32 matches!(
33 self,
34 Category::MainPseudoRef
35 | Category::PseudoRef
36 | Category::LinkedPseudoRef { .. }
37 | Category::WorktreePrivate
38 | Category::Rewritten
39 | Category::Bisect
40 )
41 }
42 }
43
44 impl FullNameRef {
45 pub(crate) fn new_unchecked(v: &BStr) -> &Self {
46 // SAFETY: FullNameRef is transparent and equivalent to a &BStr if provided as reference
47 #[allow(unsafe_code)]
48 unsafe {
49 std::mem::transmute(v)
50 }
51 }
52 }
53
54 impl PartialNameRef {
55 pub(crate) fn new_unchecked(v: &BStr) -> &Self {
56 // SAFETY: PartialNameRef is transparent and equivalent to a &BStr if provided as reference
57 #[allow(unsafe_code)]
58 unsafe {
59 std::mem::transmute(v)
60 }
61 }
62 }
63
64 impl PartialNameRef {
65 pub(crate) fn looks_like_full_name(&self) -> bool {
66 let name = self.0.as_bstr();
67 name.starts_with_str("refs/")
68 || name.starts_with(Category::MainPseudoRef.prefix())
69 || name.starts_with(Category::LinkedPseudoRef { name: "".into() }.prefix())
70 || is_pseudo_ref(name)
71 }
72 pub(crate) fn construct_full_name_ref<'buf>(&self, inbetween: &str, buf: &'buf mut BString) -> &'buf FullNameRef {
73 buf.clear();
74 if !self.looks_like_full_name() {
75 buf.push_str("refs/");
76 }
77 if !inbetween.is_empty() {
78 buf.push_str(inbetween);
79 buf.push_byte(b'/');
80 }
81 buf.extend_from_slice(&self.0);
82 FullNameRef::new_unchecked(buf.as_bstr())
83 }
84 }
85
86 impl PartialNameRef {
87 /// Convert this name into the relative path possibly identifying the reference location.
88 /// Note that it may be only a partial path though.
89 pub fn to_partial_path(&self) -> &Path {
90 gix_path::from_byte_slice(self.0.as_bstr())
91 }
92
93 /// Provide the name as binary string which is known to be a valid partial ref name.
94 pub fn as_bstr(&self) -> &BStr {
95 &self.0
96 }
97 }
98
99 impl PartialName {
100 /// Append the `component` to ourselves and validate the newly created partial path.
101 pub fn join(self, component: impl AsRef<[u8]>) -> Result<Self, Error> {
102 let mut b = self.0;
103 b.push_byte(b'/');
104 b.extend(component.as_ref());
105 gix_validate::reference::name_partial(b.as_ref())?;
106 Ok(PartialName(b))
107 }
108 }
109
110 impl<'a> convert::TryFrom<&'a BStr> for &'a FullNameRef {
111 type Error = Error;
112
113 fn try_from(v: &'a BStr) -> Result<Self, Self::Error> {
114 Ok(FullNameRef::new_unchecked(gix_validate::reference::name(v)?))
115 }
116 }
117
118 impl<'a> From<&'a FullNameRef> for &'a PartialNameRef {
119 fn from(v: &'a FullNameRef) -> Self {
120 PartialNameRef::new_unchecked(v.0.as_bstr())
121 }
122 }
123
124 impl<'a> convert::TryFrom<&'a OsStr> for &'a PartialNameRef {
125 type Error = Error;
126
127 fn try_from(v: &'a OsStr) -> Result<Self, Self::Error> {
128 let v = gix_path::os_str_into_bstr(v).map_err(|_| {
129 Error::Tag(gix_validate::tag::name::Error::InvalidByte {
130 byte: "<unknown encoding>".into(),
131 })
132 })?;
133 Ok(PartialNameRef::new_unchecked(gix_validate::reference::name_partial(
134 v.as_bstr(),
135 )?))
136 }
137 }
138
139 mod impls {
140 use std::borrow::Borrow;
141
142 use crate::{bstr::ByteSlice, PartialName, PartialNameRef};
143
144 impl Borrow<PartialNameRef> for PartialName {
145 #[inline]
146 fn borrow(&self) -> &PartialNameRef {
147 PartialNameRef::new_unchecked(self.0.as_bstr())
148 }
149 }
150
151 impl AsRef<PartialNameRef> for PartialName {
152 fn as_ref(&self) -> &PartialNameRef {
153 self.borrow()
154 }
155 }
156
157 impl ToOwned for PartialNameRef {
158 type Owned = PartialName;
159
160 fn to_owned(&self) -> Self::Owned {
161 PartialName(self.0.to_owned())
162 }
163 }
164 }
165
166 impl<'a> convert::TryFrom<&'a BString> for &'a PartialNameRef {
167 type Error = Error;
168
169 fn try_from(v: &'a BString) -> Result<Self, Self::Error> {
170 Ok(PartialNameRef::new_unchecked(gix_validate::reference::name_partial(
171 v.as_ref(),
172 )?))
173 }
174 }
175
176 impl<'a> convert::TryFrom<&'a BStr> for &'a PartialNameRef {
177 type Error = Error;
178
179 fn try_from(v: &'a BStr) -> Result<Self, Self::Error> {
180 Ok(PartialNameRef::new_unchecked(gix_validate::reference::name_partial(v)?))
181 }
182 }
183
184 impl<'a> convert::TryFrom<&'a PartialName> for &'a PartialNameRef {
185 type Error = Error;
186
187 fn try_from(v: &'a PartialName) -> Result<Self, Self::Error> {
188 Ok(PartialNameRef::new_unchecked(v.0.as_bstr()))
189 }
190 }
191
192 impl<'a> convert::TryFrom<&'a str> for &'a FullNameRef {
193 type Error = Error;
194
195 fn try_from(v: &'a str) -> Result<Self, Self::Error> {
196 let v = v.as_bytes().as_bstr();
197 Ok(FullNameRef::new_unchecked(gix_validate::reference::name(v)?))
198 }
199 }
200
201 impl<'a> convert::TryFrom<&'a str> for &'a PartialNameRef {
202 type Error = Error;
203
204 fn try_from(v: &'a str) -> Result<Self, Self::Error> {
205 let v = v.as_bytes().as_bstr();
206 Ok(PartialNameRef::new_unchecked(gix_validate::reference::name_partial(v)?))
207 }
208 }
209
210 impl<'a> convert::TryFrom<&'a str> for PartialName {
211 type Error = Error;
212
213 fn try_from(v: &'a str) -> Result<Self, Self::Error> {
214 let v = v.as_bytes().as_bstr();
215 Ok(PartialName(gix_validate::reference::name_partial(v)?.to_owned()))
216 }
217 }
218
219 impl<'a> convert::TryFrom<&'a FullName> for &'a PartialNameRef {
220 type Error = Infallible;
221
222 fn try_from(v: &'a FullName) -> Result<Self, Self::Error> {
223 Ok(v.as_ref().as_partial_name())
224 }
225 }
226
227 impl<'a> convert::TryFrom<&'a String> for &'a FullNameRef {
228 type Error = Error;
229
230 fn try_from(v: &'a String) -> Result<Self, Self::Error> {
231 let v = v.as_bytes().as_bstr();
232 Ok(FullNameRef::new_unchecked(gix_validate::reference::name(v)?))
233 }
234 }
235
236 impl<'a> convert::TryFrom<&'a String> for &'a PartialNameRef {
237 type Error = Error;
238
239 fn try_from(v: &'a String) -> Result<Self, Self::Error> {
240 let v = v.as_bytes().as_bstr();
241 Ok(PartialNameRef::new_unchecked(gix_validate::reference::name_partial(v)?))
242 }
243 }
244
245 impl convert::TryFrom<String> for PartialName {
246 type Error = Error;
247
248 fn try_from(v: String) -> Result<Self, Self::Error> {
249 gix_validate::reference::name_partial(v.as_bytes().as_bstr())?;
250 Ok(PartialName(v.into()))
251 }
252 }
253
254 impl convert::TryFrom<BString> for PartialName {
255 type Error = Error;
256
257 fn try_from(v: BString) -> Result<Self, Self::Error> {
258 gix_validate::reference::name_partial(v.as_ref())?;
259 Ok(PartialName(v))
260 }
261 }
262
263 /// Note that this method is disagreeing with `gix_validate` as it allows dashes '-' for some reason.
264 /// Since partial names cannot be created with dashes inside we adjusted this as it's probably unintended or git creates pseudo-refs
265 /// which wouldn't pass its safety checks.
266 pub(crate) fn is_pseudo_ref<'a>(name: impl Into<&'a BStr>) -> bool {
267 name.into().bytes().all(|b| b.is_ascii_uppercase() || b == b'_')
268 }