radicle_git_metadata/
commit.rs1pub mod headers;
2pub mod trailers;
3
4use core::fmt;
5use std::str;
6
7use headers::{Headers, Signature};
8use trailers::{OwnedTrailer, Trailer};
9
10use crate::author::Author;
11
12#[derive(Debug)]
15pub struct CommitData<Tree, Parent> {
16 tree: Tree,
17 parents: Vec<Parent>,
18 author: Author,
19 committer: Author,
20 headers: Headers,
21 message: String,
22 trailers: Vec<OwnedTrailer>,
23}
24
25impl<Tree, Parent> CommitData<Tree, Parent> {
26 pub fn new<P, I, T>(
27 tree: Tree,
28 parents: P,
29 author: Author,
30 committer: Author,
31 headers: Headers,
32 message: String,
33 trailers: I,
34 ) -> Self
35 where
36 P: IntoIterator<Item = Parent>,
37 I: IntoIterator<Item = T>,
38 OwnedTrailer: From<T>,
39 {
40 let trailers = trailers.into_iter().map(OwnedTrailer::from).collect();
41 let parents = parents.into_iter().collect();
42 Self {
43 tree,
44 parents,
45 author,
46 committer,
47 headers,
48 message,
49 trailers,
50 }
51 }
52
53 pub fn tree(&self) -> &Tree {
55 &self.tree
56 }
57
58 pub fn parents(&self) -> impl Iterator<Item = Parent> + '_
60 where
61 Parent: Clone,
62 {
63 self.parents.iter().cloned()
64 }
65
66 pub fn author(&self) -> &Author {
68 &self.author
69 }
70
71 pub fn committer(&self) -> &Author {
74 &self.committer
75 }
76
77 pub fn message(&self) -> &str {
79 &self.message
80 }
81
82 pub fn signatures(&self) -> impl Iterator<Item = Signature<'_>> + '_ {
85 self.headers.signatures()
86 }
87
88 pub fn headers(&self) -> impl Iterator<Item = (&str, &str)> {
92 self.headers.iter()
93 }
94
95 pub fn values<'a>(&'a self, name: &'a str) -> impl Iterator<Item = &'a str> + 'a {
97 self.headers.values(name)
98 }
99
100 pub fn push_header(&mut self, name: &str, value: &str) {
102 self.headers.push(name, value.trim());
103 }
104
105 pub fn trailers(&self) -> impl Iterator<Item = &OwnedTrailer> {
106 self.trailers.iter()
107 }
108
109 pub fn map_tree<U, E, F>(self, f: F) -> Result<CommitData<U, Parent>, E>
115 where
116 F: FnOnce(Tree) -> Result<U, E>,
117 {
118 Ok(CommitData {
119 tree: f(self.tree)?,
120 parents: self.parents,
121 author: self.author,
122 committer: self.committer,
123 headers: self.headers,
124 message: self.message,
125 trailers: self.trailers,
126 })
127 }
128
129 pub fn map_parents<U, E, F>(self, f: F) -> Result<CommitData<Tree, U>, E>
136 where
137 F: FnMut(Parent) -> Result<U, E>,
138 {
139 Ok(CommitData {
140 tree: self.tree,
141 parents: self
142 .parents
143 .into_iter()
144 .map(f)
145 .collect::<Result<Vec<_>, _>>()?,
146 author: self.author,
147 committer: self.committer,
148 headers: self.headers,
149 message: self.message,
150 trailers: self.trailers,
151 })
152 }
153}
154
155impl<Tree: fmt::Display, Parent: fmt::Display> fmt::Display for CommitData<Tree, Parent> {
156 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
157 writeln!(f, "tree {}", self.tree)?;
158 for parent in self.parents.iter() {
159 writeln!(f, "parent {parent}")?;
160 }
161 writeln!(f, "author {}", self.author)?;
162 writeln!(f, "committer {}", self.committer)?;
163
164 for (name, value) in self.headers.iter() {
165 writeln!(f, "{name} {}", value.replace('\n', "\n "))?;
166 }
167 writeln!(f)?;
168 write!(f, "{}", self.message.trim())?;
169 writeln!(f)?;
170
171 if !self.trailers.is_empty() {
172 writeln!(f)?;
173 }
174 for trailer in self.trailers.iter() {
175 writeln!(f, "{}", Trailer::from(trailer).display(": "))?;
176 }
177 Ok(())
178 }
179}