Skip to content

Commit e7e4ba2

Browse files
committed
feat: Fullname(Ref)::category() and Category (#364)
A way to classify references.
1 parent 2066a80 commit e7e4ba2

File tree

4 files changed

+59
-7
lines changed

4 files changed

+59
-7
lines changed

git-ref/src/fullname.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ impl FullName {
112112
pub fn strip_prefix(&self) -> &BStr {
113113
self.to_ref().strip_prefix()
114114
}
115+
116+
/// Classify this name, or return `None` if it's unclassified.
117+
pub fn category(&self) -> Option<crate::Category> {
118+
self.to_ref().category()
119+
}
115120
}
116121

117122
impl<'a> FullNameRef<'a> {

git-ref/src/lib.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,22 @@ pub enum Kind {
118118
Symbolic,
119119
}
120120

121+
/// The various known categories of references.
122+
///
123+
/// This translates into a prefix containing all references of a given category.
124+
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
125+
pub enum Category {
126+
/// A tag in `refs/tags`
127+
Tag,
128+
/// A branch in `refs/heads`
129+
LocalBranch,
130+
/// A branch in `refs/remotes`
131+
RemoteBranch,
132+
/// A tag in `refs/notes`
133+
Note,
134+
// NOTE: when adding something here, add it to `kind()` and `strip_prefix()` too.
135+
}
136+
121137
/// Denotes a ref target, equivalent to [`Kind`], but with mutable data.
122138
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
123139
pub enum Target {

git-ref/src/name.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,23 @@ use std::{
66

77
use git_object::bstr::{BStr, BString, ByteSlice, ByteVec};
88

9-
use crate::{FullNameRef, PartialNameRef};
9+
use crate::{Category, FullNameRef, PartialNameRef};
1010

1111
/// The error used in the [`PartialNameRef`][super::PartialNameRef]::try_from(…) implementations.
1212
pub type Error = git_validate::reference::name::Error;
1313

14+
impl Category {
15+
/// Return the prefix that would contain all references of our kind.
16+
pub fn prefix(&self) -> &BStr {
17+
match self {
18+
Category::Tag => b"refs/tags/".as_bstr(),
19+
Category::LocalBranch => b"refs/heads/".as_bstr(),
20+
Category::RemoteBranch => b"refs/remotes/".as_bstr(),
21+
Category::Note => b"refs/notes/".as_bstr(),
22+
}
23+
}
24+
}
25+
1426
impl<'a> FullNameRef<'a> {
1527
/// Convert this name into the relative path identifying the reference location.
1628
pub fn to_path(self) -> &'a Path {
@@ -34,6 +46,21 @@ impl<'a> FullNameRef<'a> {
3446
.map(|n| n.as_bstr())
3547
.unwrap_or(n)
3648
}
49+
50+
/// Classify this name, or return `None` if it's unclassified.
51+
pub fn category(&self) -> Option<Category> {
52+
for kind in &[
53+
Category::Tag,
54+
Category::LocalBranch,
55+
Category::RemoteBranch,
56+
Category::Note,
57+
] {
58+
if self.0.starts_with(kind.prefix()) {
59+
return (*kind).into();
60+
}
61+
}
62+
None
63+
}
3764
}
3865

3966
impl<'a> PartialNameRef<'a> {

git-ref/tests/fullname/mod.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use git_ref::Category;
12
use std::convert::TryInto;
23

34
#[test]
@@ -7,15 +8,18 @@ fn file_name() {
78
}
89
#[test]
910
fn strip_prefix() {
10-
for (input, expected) in [
11-
("refs/tags/tag-name", "tag-name"),
12-
("refs/heads/main", "main"),
13-
("refs/remotes/origin/main", "origin/main"),
14-
("refs/notes/note-name", "notes/note-name"),
11+
for (input, expected, category) in [
12+
("refs/tags/tag-name", "tag-name", Category::Tag),
13+
("refs/heads/main", "main", Category::LocalBranch),
14+
("refs/remotes/origin/main", "origin/main", Category::RemoteBranch),
15+
("refs/notes/note-name", "notes/note-name", Category::Note),
1516
] {
1617
let name: git_ref::FullName = input.try_into().unwrap();
18+
let category = Some(category);
1719
assert_eq!(name.to_ref().strip_prefix(), expected);
1820
assert_eq!(name.strip_prefix(), expected);
21+
assert_eq!(name.category(), category);
22+
assert_eq!(name.to_ref().category(), category);
1923
}
2024

2125
let special = "HEAD";
@@ -25,7 +29,7 @@ fn strip_prefix() {
2529
special,
2630
"the whole name is returned if there is no prefix"
2731
);
28-
assert_eq!(name.strip_prefix(), name.to_ref().strip_prefix());
32+
assert_eq!(name.category(), None);
2933
}
3034

3135
#[test]

0 commit comments

Comments
 (0)