Skip to main content

radicle_surf/
revision.rs

1use std::{convert::Infallible, str::FromStr};
2
3use git_ext::{
4    ref_format::{Qualified, RefString},
5    Oid,
6};
7
8use crate::{Branch, Commit, Error, Repository, Tag};
9
10/// The signature of a commit
11#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
12pub struct Signature(Vec<u8>);
13
14impl From<git2::Buf> for Signature {
15    fn from(other: git2::Buf) -> Self {
16        Signature((*other).into())
17    }
18}
19
20/// Supports various ways to specify a revision used in Git.
21pub trait Revision {
22    type Error: std::error::Error + Send + Sync + 'static;
23
24    /// Returns the object id of this revision in `repo`.
25    fn object_id(&self, repo: &Repository) -> Result<Oid, Self::Error>;
26}
27
28impl Revision for RefString {
29    type Error = git2::Error;
30
31    fn object_id(&self, repo: &Repository) -> Result<Oid, Self::Error> {
32        repo.refname_to_id(self)
33    }
34}
35
36impl Revision for Qualified<'_> {
37    type Error = git2::Error;
38
39    fn object_id(&self, repo: &Repository) -> Result<Oid, Self::Error> {
40        repo.refname_to_id(self)
41    }
42}
43
44impl Revision for Oid {
45    type Error = Infallible;
46
47    fn object_id(&self, _repo: &Repository) -> Result<Oid, Self::Error> {
48        Ok(*self)
49    }
50}
51
52impl Revision for &str {
53    type Error = git2::Error;
54
55    fn object_id(&self, _repo: &Repository) -> Result<Oid, Self::Error> {
56        Oid::from_str(self)
57    }
58}
59
60impl Revision for Branch {
61    type Error = Error;
62
63    fn object_id(&self, repo: &Repository) -> Result<Oid, Self::Error> {
64        let refname = repo.namespaced_refname(&self.refname())?;
65        Ok(repo.refname_to_id(&refname)?)
66    }
67}
68
69impl Revision for Tag {
70    type Error = Infallible;
71
72    fn object_id(&self, _repo: &Repository) -> Result<Oid, Self::Error> {
73        Ok(self.id())
74    }
75}
76
77impl Revision for String {
78    type Error = git2::Error;
79
80    fn object_id(&self, _repo: &Repository) -> Result<Oid, Self::Error> {
81        Oid::from_str(self)
82    }
83}
84
85impl<R: Revision> Revision for &R {
86    type Error = R::Error;
87
88    fn object_id(&self, repo: &Repository) -> Result<Oid, Self::Error> {
89        (*self).object_id(repo)
90    }
91}
92
93impl<R: Revision> Revision for Box<R> {
94    type Error = R::Error;
95
96    fn object_id(&self, repo: &Repository) -> Result<Oid, Self::Error> {
97        self.as_ref().object_id(repo)
98    }
99}
100
101/// A common trait for anything that can convert to a `Commit`.
102pub trait ToCommit {
103    type Error: std::error::Error + Send + Sync + 'static;
104
105    /// Converts to a commit in `repo`.
106    fn to_commit(self, repo: &Repository) -> Result<Commit, Self::Error>;
107}
108
109impl ToCommit for Commit {
110    type Error = Infallible;
111
112    fn to_commit(self, _repo: &Repository) -> Result<Commit, Self::Error> {
113        Ok(self)
114    }
115}
116
117impl<R: Revision> ToCommit for R {
118    type Error = Error;
119
120    fn to_commit(self, repo: &Repository) -> Result<Commit, Self::Error> {
121        let oid = repo.object_id(&self)?;
122        let commit = repo.find_commit(oid)?;
123        Ok(Commit::try_from(commit)?)
124    }
125}