1 use bstr
::{BStr, ByteSlice}
;
3 use crate::{Commit, CommitRef, TagRef}
;
9 /// A parsed commit message that assumes a title separated from the body by two consecutive newlines.
11 /// Titles can have any amount of whitespace
12 #[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
13 #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
14 pub struct MessageRef
<'a
> {
15 /// The title of the commit, as separated from the body with two consecutive newlines. The newlines are not included.
16 #[cfg_attr(feature = "serde1", serde(borrow))]
18 /// All bytes not consumed by the title, excluding the separating newlines.
20 /// The body is `None` if there was now title separation or the body was empty after the separator.
21 pub body
: Option
<&'a BStr
>,
29 impl<'a
> CommitRef
<'a
> {
30 /// Deserialize a commit from the given `data` bytes while avoiding most allocations.
31 pub fn from_bytes(data
: &'a
[u8]) -> Result
<CommitRef
<'a
>, crate::decode
::Error
> {
32 decode
::commit(data
).map(|(_
, t
)| t
).map_err(crate::decode
::Error
::from
)
34 /// Return the `tree` fields hash digest.
35 pub fn tree(&self) -> gix_hash
::ObjectId
{
36 gix_hash
::ObjectId
::from_hex(self.tree
).expect("prior validation of tree hash during parsing")
39 /// Returns an iterator of parent object ids
40 pub fn parents(&self) -> impl Iterator
<Item
= gix_hash
::ObjectId
> + '_
{
43 .map(|hex_hash
| gix_hash
::ObjectId
::from_hex(hex_hash
).expect("prior validation of hashes during parsing"))
46 /// Returns a convenient iterator over all extra headers.
47 pub fn extra_headers(&self) -> crate::commit
::ExtraHeaders
<impl Iterator
<Item
= (&BStr
, &BStr
)>> {
48 crate::commit
::ExtraHeaders
::new(self.extra_headers
.iter().map(|(k
, v
)| (*k
, v
.as_ref())))
51 /// Return the author, with whitespace trimmed.
53 /// This is different from the `author` field which may contain whitespace.
54 pub fn author(&self) -> gix_actor
::SignatureRef
<'a
> {
58 /// Return the committer, with whitespace trimmed.
60 /// This is different from the `committer` field which may contain whitespace.
61 pub fn committer(&self) -> gix_actor
::SignatureRef
<'a
> {
65 /// Returns a partially parsed message from which more information can be derived.
66 pub fn message(&self) -> MessageRef
<'a
> {
67 MessageRef
::from_bytes(self.message
)
70 /// Returns the time at which this commit was created.
71 pub fn time(&self) -> gix_actor
::Time
{
77 /// Returns a convenient iterator over all extra headers.
78 pub fn extra_headers(&self) -> ExtraHeaders
<impl Iterator
<Item
= (&BStr
, &BStr
)>> {
79 ExtraHeaders
::new(self.extra_headers
.iter().map(|(k
, v
)| (k
.as_bstr(), v
.as_bstr())))
83 /// An iterator over extra headers in [owned][crate::Commit] and [borrowed][crate::CommitRef] commits.
84 pub struct ExtraHeaders
<I
> {
88 /// Instantiation and convenience.
89 impl<'a
, I
> ExtraHeaders
<I
>
91 I
: Iterator
<Item
= (&'a BStr
, &'a BStr
)>,
93 /// Create a new instance from an iterator over tuples of (name, value) pairs.
94 pub fn new(iter
: I
) -> Self {
95 ExtraHeaders { inner: iter }
97 /// Find the _value_ of the _first_ header with the given `name`.
98 pub fn find(mut self, name
: &str) -> Option
<&'a BStr
> {
100 .find_map(move |(k
, v
)| if k
== name
.as_bytes().as_bstr() { Some(v) }
else { None }
)
102 /// Return an iterator over all _values_ of headers with the given `name`.
103 pub fn find_all(self, name
: &'a
str) -> impl Iterator
<Item
= &'a BStr
> {
105 .filter_map(move |(k
, v
)| if k
== name
.as_bytes().as_bstr() { Some(v) }
else { None }
)
107 /// Return an iterator over all git mergetags.
109 /// A merge tag is a tag object embedded within the respective header field of a commit, making
110 /// it a child object of sorts.
111 pub fn mergetags(self) -> impl Iterator
<Item
= Result
<TagRef
<'a
>, crate::decode
::Error
>> {
112 self.find_all("mergetag").map(|b
| TagRef
::from_bytes(b
))
115 /// Return the cryptographic signature provided by gpg/pgp verbatim.
116 pub fn pgp_signature(self) -> Option
<&'a BStr
> {