uv_git_types/
reference.rs1use std::borrow::Cow;
2use std::fmt::Display;
3use std::str;
4
5use percent_encoding::{AsciiSet, NON_ALPHANUMERIC, utf8_percent_encode};
6
7const GIT_REFERENCE_ENCODE_SET: &AsciiSet = &NON_ALPHANUMERIC
12 .remove(b'/')
13 .remove(b'-')
14 .remove(b'.')
15 .remove(b'_')
16 .remove(b'~');
17
18#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
20pub enum GitReference {
21 Branch(String),
23 Tag(String),
25 BranchOrTag(String),
27 BranchOrTagOrCommit(String),
29 NamedRef(String),
31 DefaultBranch,
33}
34
35impl GitReference {
36 pub fn from_rev(rev: String) -> Self {
39 if rev.starts_with("refs/") {
40 Self::NamedRef(rev)
41 } else if looks_like_commit_hash(&rev) {
42 Self::BranchOrTagOrCommit(rev)
43 } else {
44 Self::BranchOrTag(rev)
45 }
46 }
47
48 pub fn as_str(&self) -> Option<&str> {
50 match self {
51 Self::Tag(rev) => Some(rev),
52 Self::Branch(rev) => Some(rev),
53 Self::BranchOrTag(rev) => Some(rev),
54 Self::BranchOrTagOrCommit(rev) => Some(rev),
55 Self::NamedRef(rev) => Some(rev),
56 Self::DefaultBranch => None,
57 }
58 }
59
60 pub fn as_rev(&self) -> &str {
62 match self {
63 Self::Tag(rev) => rev,
64 Self::Branch(rev) => rev,
65 Self::BranchOrTag(rev) => rev,
66 Self::BranchOrTagOrCommit(rev) => rev,
67 Self::NamedRef(rev) => rev,
68 Self::DefaultBranch => "HEAD",
69 }
70 }
71
72 pub fn as_url_rev(&self) -> Option<Cow<'_, str>> {
74 self.as_str().map(Self::encode_rev)
75 }
76
77 pub(crate) fn encode_rev(rev: &str) -> Cow<'_, str> {
79 utf8_percent_encode(rev, GIT_REFERENCE_ENCODE_SET).into()
80 }
81
82 pub fn kind_str(&self) -> &str {
84 match self {
85 Self::Branch(_) => "branch",
86 Self::Tag(_) => "tag",
87 Self::BranchOrTag(_) => "branch or tag",
88 Self::BranchOrTagOrCommit(_) => "branch, tag, or commit",
89 Self::NamedRef(_) => "ref",
90 Self::DefaultBranch => "default branch",
91 }
92 }
93}
94
95impl Display for GitReference {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 write!(f, "{}", self.as_str().unwrap_or("HEAD"))
98 }
99}
100
101fn looks_like_commit_hash(rev: &str) -> bool {
103 rev.len() >= 7 && rev.chars().all(|ch| ch.is_ascii_hexdigit())
104}