Struct git_ref::FullNameRef
source · #[repr(transparent)]pub struct FullNameRef(_);
Expand description
A validated and potentially partial reference name - it can safely be used for common operations.
Implementations§
source§impl FullNameRef
impl FullNameRef
sourcepub fn as_partial_name(&self) -> &PartialNameRef
pub fn as_partial_name(&self) -> &PartialNameRef
Interpret this fully qualified reference name as partial name.
Examples found in repository?
More examples
src/transaction/ext.rs (line 75)
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
fn extend_with_splits_of_symbolic_refs(
&mut self,
mut find: impl FnMut(&PartialNameRef) -> Option<Target>,
mut make_entry: impl FnMut(usize, RefEdit) -> E,
) -> Result<(), std::io::Error> {
let mut new_edits = Vec::new();
let mut first = 0;
let mut round = 1;
loop {
for (eid, edit) in self[first..].iter_mut().enumerate().map(|(eid, v)| (eid + first, v)) {
let edit = edit.borrow_mut();
if !edit.deref {
continue;
};
// we can't tell what happened and we are here because it's a non-existing ref or an invalid one.
// In any case, we don't want the following algorithms to try dereffing it and assume they deal with
// broken refs gracefully.
edit.deref = false;
if let Some(Target::Symbolic(referent)) = find(edit.name.as_ref().as_partial_name()) {
new_edits.push(make_entry(
eid,
match &mut edit.change {
Change::Delete {
expected: previous,
log: mode,
} => {
let current_mode = *mode;
*mode = RefLog::Only;
RefEdit {
change: Change::Delete {
expected: previous.clone(),
log: current_mode,
},
name: referent,
deref: true,
}
}
Change::Update { log, expected, new } => {
let current = std::mem::replace(
log,
LogChange {
message: log.message.clone(),
mode: RefLog::Only,
force_create_reflog: log.force_create_reflog,
},
);
let next = std::mem::replace(expected, PreviousValue::Any);
RefEdit {
change: Change::Update {
expected: next,
new: new.clone(),
log: current,
},
name: referent,
deref: true,
}
}
},
));
}
}
if new_edits.is_empty() {
break Ok(());
}
if round == 5 {
break Err(std::io::Error::new(
std::io::ErrorKind::WouldBlock,
format!(
"Could not follow all splits after {} rounds, assuming reference cycle",
round
),
));
}
round += 1;
first = self.len();
self.append(&mut new_edits);
}
}
sourcepub fn to_path(&self) -> &Path
pub fn to_path(&self) -> &Path
Convert this name into the relative path identifying the reference location.
Examples found in repository?
src/store/file/find.rs (line 152)
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
fn find_inner(
&self,
inbetween: &str,
partial_name: &PartialNameRef,
packed: Option<&packed::Buffer>,
transform: Transform,
path_buf: &mut BString,
) -> Result<Option<Reference>, Error> {
let add_refs_prefix = matches!(transform, Transform::EnforceRefsPrefix);
let full_name = partial_name.construct_full_name_ref(add_refs_prefix, inbetween, path_buf);
let content_buf = self.ref_contents(full_name).map_err(|err| Error::ReadFileContents {
source: err,
path: self.reference_path(full_name),
})?;
match content_buf {
None => {
if let Some(packed) = packed {
if let Some(full_name) = packed::find::transform_full_name_for_lookup(full_name) {
let full_name_backing;
let full_name = match &self.namespace {
Some(namespace) => {
full_name_backing = namespace.to_owned().into_namespaced_name(full_name);
full_name_backing.as_ref()
}
None => full_name,
};
if let Some(packed_ref) = packed.try_find_full_name(full_name)? {
let mut res: Reference = packed_ref.into();
if let Some(namespace) = &self.namespace {
res.strip_namespace(namespace);
}
return Ok(Some(res));
};
}
}
Ok(None)
}
Some(content) => Ok(Some(
loose::Reference::try_from_path(full_name.to_owned(), &content)
.map(Into::into)
.map(|mut r: Reference| {
if let Some(namespace) = &self.namespace {
r.strip_namespace(namespace);
}
r
})
.map_err(|err| Error::ReferenceCreation {
source: err,
relative_path: full_name.to_path().to_owned(),
})?,
)),
}
}
sourcepub fn as_bstr(&self) -> &BStr
pub fn as_bstr(&self) -> &BStr
Return ourselves as byte string which is a valid refname
Examples found in repository?
More examples
src/store/file/find.rs (line 201)
196 197 198 199 200 201 202 203 204 205 206 207
pub(crate) fn reference_path_with_base<'b>(&self, name: &'b FullNameRef) -> (Cow<'_, Path>, Cow<'b, Path>) {
let (base, name) = self.to_base_dir_and_relative_name(name, false);
(
base,
match &self.namespace {
None => git_path::to_native_path_on_windows(name.as_bstr()),
Some(namespace) => {
git_path::to_native_path_on_windows(namespace.to_owned().into_namespaced_name(name).into_inner())
}
},
)
}
src/store/packed/find.rs (line 42)
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
pub(crate) fn try_find_full_name(&self, name: &FullNameRef) -> Result<Option<packed::Reference<'_>>, Error> {
match self.binary_search_by(name.as_bstr()) {
Ok(line_start) => Ok(Some(
packed::decode::reference::<()>(&self.as_ref()[line_start..])
.map_err(|_| Error::Parse)?
.1,
)),
Err((parse_failure, _)) => {
if parse_failure {
Err(Error::Parse)
} else {
Ok(None)
}
}
}
}
/// Find a reference with the given `name` and return it.
pub fn find<'a, Name, E>(&self, name: Name) -> Result<packed::Reference<'_>, existing::Error>
where
Name: TryInto<&'a PartialNameRef, Error = E>,
Error: From<E>,
{
match self.try_find(name) {
Ok(Some(r)) => Ok(r),
Ok(None) => Err(existing::Error::NotFound),
Err(err) => Err(existing::Error::Find(err)),
}
}
/// Perform a binary search where `Ok(pos)` is the beginning of the line that matches `name` perfectly and `Err(pos)`
/// is the beginning of the line at which `name` could be inserted to still be in sort order.
pub(in crate::store_impl::packed) fn binary_search_by(&self, full_name: &BStr) -> Result<usize, (bool, usize)> {
let a = self.as_ref();
let search_start_of_record = |ofs: usize| {
a[..ofs]
.rfind(b"\n")
.and_then(|pos| {
let candidate = pos + 1;
a.get(candidate).and_then(|b| {
if *b == b'^' {
a[..pos].rfind(b"\n").map(|pos| pos + 1)
} else {
Some(candidate)
}
})
})
.unwrap_or(0)
};
let mut encountered_parse_failure = false;
a.binary_search_by_key(&full_name.as_ref(), |b: &u8| {
let ofs = b as *const u8 as usize - a.as_ptr() as usize;
let line = &a[search_start_of_record(ofs)..];
packed::decode::reference::<()>(line)
.map(|(_rest, r)| r.name.as_bstr().as_ref())
.map_err(|err| {
encountered_parse_failure = true;
err
})
.unwrap_or(&[])
})
.map(search_start_of_record)
.map_err(|pos| (encountered_parse_failure, search_start_of_record(pos)))
}
src/store/file/loose/reflog.rs (line 192)
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
pub(in crate::store_impl::file) fn reflog_base_and_relative_path<'a>(
&self,
name: &'a FullNameRef,
) -> (PathBuf, Cow<'a, Path>) {
let is_reflog = true;
let (base, name) = self.to_base_dir_and_relative_name(name, is_reflog);
(
base.join("logs"),
match &self.namespace {
None => git_path::to_native_path_on_windows(name.as_bstr()),
Some(namespace) => git_path::to_native_path_on_windows(
namespace.to_owned().into_namespaced_name(name).into_inner(),
),
},
)
}
Additional examples can be found in:
sourcepub fn shorten(&self) -> &BStr
pub fn shorten(&self) -> &BStr
Strip well-known prefixes from the name and return it.
If there is no such prefix, the original name is returned.
sourcepub fn category(&self) -> Option<Category<'_>>
pub fn category(&self) -> Option<Category<'_>>
Classify this name, or return None
if it’s unclassified.
Examples found in repository?
More examples
src/store/file/transaction/prepare.rs (line 418)
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
fn possibly_adjust_name_for_prefixes(name: &FullNameRef) -> Option<FullName> {
match name.category_and_short_name() {
Some((c, sn)) => {
use crate::Category::*;
let sn = FullNameRef::new_unchecked(sn);
match c {
Bisect | Rewritten | WorktreePrivate | LinkedPseudoRef { .. } | PseudoRef | MainPseudoRef => None,
Tag | LocalBranch | RemoteBranch | Note => name.into(),
MainRef | LinkedRef { .. } => sn
.category()
.map_or(false, |cat| !cat.is_worktree_private())
.then(|| sn),
}
.map(|n| n.to_owned())
}
None => Some(name.to_owned()), // allow (uncategorized/very special) refs to be packed
}
}
src/store/file/find.rs (line 179)
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
pub(crate) fn to_base_dir_and_relative_name<'a>(
&self,
name: &'a FullNameRef,
is_reflog: bool,
) -> (Cow<'_, Path>, &'a FullNameRef) {
let commondir = self.common_dir_resolved();
let linked_git_dir =
|worktree_name: &BStr| commondir.join("worktrees").join(git_path::from_bstr(worktree_name));
name.category_and_short_name()
.and_then(|(c, sn)| {
use crate::Category::*;
let sn = FullNameRef::new_unchecked(sn);
Some(match c {
LinkedPseudoRef { name: worktree_name } => is_reflog
.then(|| (linked_git_dir(worktree_name).into(), sn))
.unwrap_or((commondir.into(), name)),
Tag | LocalBranch | RemoteBranch | Note => (commondir.into(), name),
MainRef | MainPseudoRef => (commondir.into(), sn),
LinkedRef { name: worktree_name } => sn
.category()
.map_or(false, |cat| cat.is_worktree_private())
.then(|| {
if is_reflog {
(linked_git_dir(worktree_name).into(), sn)
} else {
(commondir.into(), name)
}
})
.unwrap_or((commondir.into(), sn)),
PseudoRef | Bisect | Rewritten | WorktreePrivate => return None,
})
})
.unwrap_or((self.git_dir.as_path().into(), name))
}
sourcepub fn category_and_short_name(&self) -> Option<(Category<'_>, &BStr)>
pub fn category_and_short_name(&self) -> Option<(Category<'_>, &BStr)>
Classify this name, or return None
if it’s unclassified. If Some
,
the shortened name is returned as well.
Examples found in repository?
src/fullname.rs (line 94)
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
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_ref()) {
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_ref()) {
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_ref())
{
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 {
git_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()
}
More examples
src/store/packed/find.rs (line 143)
142 143 144 145 146 147 148 149 150 151 152 153 154
pub(crate) fn transform_full_name_for_lookup(name: &FullNameRef) -> Option<&FullNameRef> {
match name.category_and_short_name() {
Some((c, sn)) => {
use crate::Category::*;
Some(match c {
MainRef | LinkedRef { .. } => FullNameRef::new_unchecked(sn),
Tag | RemoteBranch | LocalBranch | Bisect | Rewritten | Note => name,
MainPseudoRef | PseudoRef | LinkedPseudoRef { .. } | WorktreePrivate => return None,
})
}
None => Some(name),
}
}
src/store/file/transaction/prepare.rs (line 410)
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
fn possibly_adjust_name_for_prefixes(name: &FullNameRef) -> Option<FullName> {
match name.category_and_short_name() {
Some((c, sn)) => {
use crate::Category::*;
let sn = FullNameRef::new_unchecked(sn);
match c {
Bisect | Rewritten | WorktreePrivate | LinkedPseudoRef { .. } | PseudoRef | MainPseudoRef => None,
Tag | LocalBranch | RemoteBranch | Note => name.into(),
MainRef | LinkedRef { .. } => sn
.category()
.map_or(false, |cat| !cat.is_worktree_private())
.then(|| sn),
}
.map(|n| n.to_owned())
}
None => Some(name.to_owned()), // allow (uncategorized/very special) refs to be packed
}
}
src/store/file/find.rs (line 168)
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
pub(crate) fn to_base_dir_and_relative_name<'a>(
&self,
name: &'a FullNameRef,
is_reflog: bool,
) -> (Cow<'_, Path>, &'a FullNameRef) {
let commondir = self.common_dir_resolved();
let linked_git_dir =
|worktree_name: &BStr| commondir.join("worktrees").join(git_path::from_bstr(worktree_name));
name.category_and_short_name()
.and_then(|(c, sn)| {
use crate::Category::*;
let sn = FullNameRef::new_unchecked(sn);
Some(match c {
LinkedPseudoRef { name: worktree_name } => is_reflog
.then(|| (linked_git_dir(worktree_name).into(), sn))
.unwrap_or((commondir.into(), name)),
Tag | LocalBranch | RemoteBranch | Note => (commondir.into(), name),
MainRef | MainPseudoRef => (commondir.into(), sn),
LinkedRef { name: worktree_name } => sn
.category()
.map_or(false, |cat| cat.is_worktree_private())
.then(|| {
if is_reflog {
(linked_git_dir(worktree_name).into(), sn)
} else {
(commondir.into(), name)
}
})
.unwrap_or((commondir.into(), sn)),
PseudoRef | Bisect | Rewritten | WorktreePrivate => return None,
})
})
.unwrap_or((self.git_dir.as_path().into(), name))
}
source§impl FullNameRef
impl FullNameRef
Trait Implementations§
source§impl AsRef<FullNameRef> for FullName
impl AsRef<FullNameRef> for FullName
source§fn as_ref(&self) -> &FullNameRef
fn as_ref(&self) -> &FullNameRef
Converts this type into a shared reference of the (usually inferred) input type.
source§impl Borrow<FullNameRef> for FullName
impl Borrow<FullNameRef> for FullName
source§fn borrow(&self) -> &FullNameRef
fn borrow(&self) -> &FullNameRef
Immutably borrows from an owned value. Read more
source§impl Debug for FullNameRef
impl Debug for FullNameRef
source§impl<'a> From<&'a FullNameRef> for &'a BStr
impl<'a> From<&'a FullNameRef> for &'a BStr
source§fn from(name: &'a FullNameRef) -> Self
fn from(name: &'a FullNameRef) -> Self
Converts to this type from the input type.
source§impl<'a> From<&'a FullNameRef> for &'a PartialNameRef
impl<'a> From<&'a FullNameRef> for &'a PartialNameRef
source§fn from(v: &'a FullNameRef) -> Self
fn from(v: &'a FullNameRef) -> Self
Converts to this type from the input type.
source§impl<'a> From<&'a FullNameRef> for FullName
impl<'a> From<&'a FullNameRef> for FullName
source§fn from(value: &'a FullNameRef) -> Self
fn from(value: &'a FullNameRef) -> Self
Converts to this type from the input type.
source§impl Hash for FullNameRef
impl Hash for FullNameRef
source§impl Ord for FullNameRef
impl Ord for FullNameRef
source§impl PartialEq<FullNameRef> for FullNameRef
impl PartialEq<FullNameRef> for FullNameRef
source§fn eq(&self, other: &FullNameRef) -> bool
fn eq(&self, other: &FullNameRef) -> bool
This method tests for
self
and other
values to be equal, and is used
by ==
.source§impl PartialOrd<FullNameRef> for FullNameRef
impl PartialOrd<FullNameRef> for FullNameRef
source§fn partial_cmp(&self, other: &FullNameRef) -> Option<Ordering>
fn partial_cmp(&self, other: &FullNameRef) -> Option<Ordering>
1.0.0 · source§fn le(&self, other: &Rhs) -> bool
fn le(&self, other: &Rhs) -> bool
This method tests less than or equal to (for
self
and other
) and is used by the <=
operator. Read more