1 use std
::{convert, convert::Infallible, ffi::OsStr, path::Path}
;
3 use gix_object
::bstr
::{BStr, BString, ByteSlice, ByteVec}
;
5 use crate::{Category, FullName, FullNameRef, PartialName, PartialNameRef}
;
7 /// The error used in the [`PartialNameRef`][super::PartialNameRef]`::try_from`(…) implementations.
8 pub type Error
= gix_validate
::reference
::name
::Error
;
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
{
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(),
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
{
34 Category
::MainPseudoRef
36 | Category
::LinkedPseudoRef { .. }
37 | Category
::WorktreePrivate
45 pub(crate) fn new_unchecked(v
: &BStr
) -> &Self {
46 // SAFETY: FullNameRef is transparent and equivalent to a &BStr if provided as reference
49 std
::mem
::transmute(v
)
55 pub(crate) fn new_unchecked(v
: &BStr
) -> &Self {
56 // SAFETY: PartialNameRef is transparent and equivalent to a &BStr if provided as reference
59 std
::mem
::transmute(v
)
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
)
72 pub(crate) fn construct_full_name_ref
<'buf
>(&self, inbetween
: &str, buf
: &'buf
mut BString
) -> &'buf FullNameRef
{
74 if !self.looks_like_full_name() {
75 buf
.push_str("refs/");
77 if !inbetween
.is_empty() {
78 buf
.push_str(inbetween
);
81 buf
.extend_from_slice(&self.0);
82 FullNameRef
::new_unchecked(buf
.as_bstr())
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())
93 /// Provide the name as binary string which is known to be a valid partial ref name.
94 pub fn as_bstr(&self) -> &BStr
{
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
> {
104 b
.extend(component
.as_ref());
105 gix_validate
::reference
::name_partial(b
.as_ref())?
;
110 impl<'a
> convert
::TryFrom
<&'a BStr
> for &'a FullNameRef
{
113 fn try_from(v
: &'a BStr
) -> Result
<Self, Self::Error
> {
114 Ok(FullNameRef
::new_unchecked(gix_validate
::reference
::name(v
)?
))
118 impl<'a
> From
<&'a FullNameRef
> for &'a PartialNameRef
{
119 fn from(v
: &'a FullNameRef
) -> Self {
120 PartialNameRef
::new_unchecked(v
.0.as_bstr())
124 impl<'a
> convert
::TryFrom
<&'a OsStr
> for &'a PartialNameRef
{
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(),
133 Ok(PartialNameRef
::new_unchecked(gix_validate
::reference
::name_partial(
140 use std
::borrow
::Borrow
;
142 use crate::{bstr::ByteSlice, PartialName, PartialNameRef}
;
144 impl Borrow
<PartialNameRef
> for PartialName
{
146 fn borrow(&self) -> &PartialNameRef
{
147 PartialNameRef
::new_unchecked(self.0.as_bstr())
151 impl AsRef
<PartialNameRef
> for PartialName
{
152 fn as_ref(&self) -> &PartialNameRef
{
157 impl ToOwned
for PartialNameRef
{
158 type Owned
= PartialName
;
160 fn to_owned(&self) -> Self::Owned
{
161 PartialName(self.0.to_owned())
166 impl<'a
> convert
::TryFrom
<&'a BString
> for &'a PartialNameRef
{
169 fn try_from(v
: &'a BString
) -> Result
<Self, Self::Error
> {
170 Ok(PartialNameRef
::new_unchecked(gix_validate
::reference
::name_partial(
176 impl<'a
> convert
::TryFrom
<&'a BStr
> for &'a PartialNameRef
{
179 fn try_from(v
: &'a BStr
) -> Result
<Self, Self::Error
> {
180 Ok(PartialNameRef
::new_unchecked(gix_validate
::reference
::name_partial(v
)?
))
184 impl<'a
> convert
::TryFrom
<&'a PartialName
> for &'a PartialNameRef
{
187 fn try_from(v
: &'a PartialName
) -> Result
<Self, Self::Error
> {
188 Ok(PartialNameRef
::new_unchecked(v
.0.as_bstr()))
192 impl<'a
> convert
::TryFrom
<&'a
str> for &'a FullNameRef
{
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
)?
))
201 impl<'a
> convert
::TryFrom
<&'a
str> for &'a PartialNameRef
{
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
)?
))
210 impl<'a
> convert
::TryFrom
<&'a
str> for PartialName
{
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()))
219 impl<'a
> convert
::TryFrom
<&'a FullName
> for &'a PartialNameRef
{
220 type Error
= Infallible
;
222 fn try_from(v
: &'a FullName
) -> Result
<Self, Self::Error
> {
223 Ok(v
.as_ref().as_partial_name())
227 impl<'a
> convert
::TryFrom
<&'a String
> for &'a FullNameRef
{
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
)?
))
236 impl<'a
> convert
::TryFrom
<&'a String
> for &'a PartialNameRef
{
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
)?
))
245 impl convert
::TryFrom
<String
> for PartialName
{
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()))
254 impl convert
::TryFrom
<BString
> for PartialName
{
257 fn try_from(v
: BString
) -> Result
<Self, Self::Error
> {
258 gix_validate
::reference
::name_partial(v
.as_ref())?
;
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'_'
)