git_prole/git/refs/
remote_branch.rs1use std::fmt::Debug;
2use std::fmt::Display;
3use std::ops::Deref;
4
5use miette::miette;
6
7use super::LocalBranchRef;
8use super::Ref;
9
10#[derive(Clone, Hash, PartialEq, Eq)]
12pub struct RemoteBranchRef(Ref);
13
14impl Debug for RemoteBranchRef {
15 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16 Debug::fmt(&self.0, f)
17 }
18}
19
20impl PartialEq<Ref> for RemoteBranchRef {
21 fn eq(&self, other: &Ref) -> bool {
22 self.0.eq(other)
23 }
24}
25
26impl RemoteBranchRef {
27 pub fn new(remote: &str, name: &str) -> Self {
28 Self(Ref::new(
29 Ref::REMOTES.to_owned(),
30 format!("{remote}/{name}"),
31 ))
32 }
33
34 pub fn qualified_branch_name(&self) -> &str {
36 self.name()
37 }
38
39 pub fn remote_and_branch(&self) -> (&str, &str) {
41 self.0
42 .name()
43 .split_once('/')
44 .expect("A remote branch always has a remote and a branch")
45 }
46
47 pub fn remote(&self) -> &str {
49 self.remote_and_branch().0
50 }
51
52 pub fn branch_name(&self) -> &str {
54 self.remote_and_branch().1
55 }
56
57 pub fn as_local(&self) -> LocalBranchRef {
59 LocalBranchRef::new(self.branch_name().to_owned())
60 }
61}
62
63impl Deref for RemoteBranchRef {
64 type Target = Ref;
65
66 fn deref(&self) -> &Self::Target {
67 &self.0
68 }
69}
70
71impl TryFrom<Ref> for RemoteBranchRef {
72 type Error = miette::Report;
73
74 fn try_from(value: Ref) -> Result<Self, Self::Error> {
75 if value.is_remote_branch() {
76 Ok(Self(value))
77 } else {
78 Err(miette!("Ref is not a remote branch: {value}"))
79 }
80 }
81}
82
83impl Display for RemoteBranchRef {
84 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85 Display::fmt(&self.0, f)
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use std::str::FromStr;
92
93 use pretty_assertions::assert_eq;
94
95 use super::*;
96
97 #[test]
98 fn remote_branch_ref_try_from() {
99 let branch =
100 RemoteBranchRef::try_from(Ref::from_str("refs/remotes/puppy/doggy").unwrap()).unwrap();
101
102 assert_eq!(branch.remote(), "puppy");
103 assert_eq!(branch.branch_name(), "doggy");
104 }
105
106 #[test]
107 fn test_remote_branch_new() {
108 assert_eq!(
109 RemoteBranchRef::new("origin", "puppy"),
110 Ref::from_str("refs/remotes/origin/puppy").unwrap(),
111 );
112 }
113
114 #[test]
115 fn test_remote_branch_qualified_branch_name() {
116 assert_eq!(
117 RemoteBranchRef::new("origin", "puppy").qualified_branch_name(),
118 "origin/puppy",
119 );
120 }
121
122 #[test]
123 fn test_remote_branch_remote_and_branch() {
124 assert_eq!(
125 RemoteBranchRef::new("origin", "puppy/doggy").remote_and_branch(),
126 ("origin", "puppy/doggy"),
127 );
128 }
129
130 #[test]
131 fn test_remote_branch_branch_name() {
132 assert_eq!(
133 RemoteBranchRef::new("origin", "puppy").branch_name(),
134 "puppy",
135 );
136 }
137
138 #[test]
139 fn test_remote_branch_as_local() {
140 assert_eq!(
141 RemoteBranchRef::new("origin", "puppy").as_local(),
142 Ref::from_str("refs/heads/puppy").unwrap(),
143 );
144 }
145
146 #[test]
147 fn test_remote_branch_display() {
148 let branch = RemoteBranchRef::new("origin", "puppy");
149 assert_eq!(format!("{branch}"), "origin/puppy");
150 assert_eq!(format!("{branch:#}"), "refs/remotes/origin/puppy");
151 }
152}