1#[derive(Clone, Debug, Default, Eq, PartialEq)]
12pub struct LogSnapshot {
13 title: String,
14 rendered: String,
15 entries: Vec<LogEntry>,
16}
17
18impl LogSnapshot {
19 #[must_use]
24 pub fn new(rendered: impl Into<String>, entries: Vec<LogEntry>) -> Self {
25 Self {
26 title: String::new(),
27 rendered: rendered.into(),
28 entries,
29 }
30 }
31
32 #[must_use]
34 pub fn with_title(mut self, title: impl Into<String>) -> Self {
35 self.title = title.into();
36 self
37 }
38
39 #[must_use]
41 pub fn title(&self) -> &str {
42 &self.title
43 }
44
45 #[must_use]
47 pub fn rendered(&self) -> &str {
48 &self.rendered
49 }
50
51 #[must_use]
53 pub fn entries(&self) -> &[LogEntry] {
54 &self.entries
55 }
56
57 #[must_use]
59 pub fn into_parts(self) -> (String, String, Vec<LogEntry>) {
60 (self.title, self.rendered, self.entries)
61 }
62}
63
64#[derive(Clone, Debug, Default, Eq, PartialEq)]
66pub struct DiffSnapshot {
67 title: String,
68 change_id: String,
69 rendered: String,
70 file_stats: Vec<DiffFileStat>,
71}
72
73impl DiffSnapshot {
74 #[must_use]
76 pub fn new(change_id: impl Into<String>, rendered: impl Into<String>) -> Self {
77 Self {
78 title: String::new(),
79 change_id: change_id.into(),
80 rendered: rendered.into(),
81 file_stats: Vec::new(),
82 }
83 }
84
85 #[must_use]
87 pub fn with_title(mut self, title: impl Into<String>) -> Self {
88 self.title = title.into();
89 self
90 }
91
92 #[must_use]
94 pub fn with_file_stats(mut self, file_stats: Vec<DiffFileStat>) -> Self {
95 self.file_stats = file_stats;
96 self
97 }
98
99 #[must_use]
101 pub fn title(&self) -> &str {
102 &self.title
103 }
104
105 #[must_use]
107 pub fn change_id(&self) -> &str {
108 &self.change_id
109 }
110
111 #[must_use]
113 pub fn rendered(&self) -> &str {
114 &self.rendered
115 }
116
117 #[must_use]
119 pub fn file_stats(&self) -> &[DiffFileStat] {
120 &self.file_stats
121 }
122
123 #[must_use]
125 pub fn into_parts(self) -> (String, String, String, Vec<DiffFileStat>) {
126 (self.title, self.change_id, self.rendered, self.file_stats)
127 }
128}
129
130#[derive(Clone, Debug, Default, Eq, PartialEq)]
132pub struct DiffFileStat {
133 path: String,
134 added: usize,
135 removed: usize,
136 rendered: String,
137}
138
139impl DiffFileStat {
140 #[must_use]
142 pub fn new(path: impl Into<String>, added: usize, removed: usize) -> Self {
143 Self {
144 path: path.into(),
145 added,
146 removed,
147 rendered: String::new(),
148 }
149 }
150
151 #[must_use]
153 pub fn with_rendered(mut self, rendered: impl Into<String>) -> Self {
154 self.rendered = rendered.into();
155 self
156 }
157
158 #[must_use]
160 pub fn path(&self) -> &str {
161 &self.path
162 }
163
164 #[must_use]
166 pub const fn added(&self) -> usize {
167 self.added
168 }
169
170 #[must_use]
172 pub const fn removed(&self) -> usize {
173 self.removed
174 }
175
176 #[must_use]
178 pub fn rendered(&self) -> &str {
179 &self.rendered
180 }
181}
182
183#[derive(Clone, Debug, Eq, PartialEq)]
185pub struct LogEntry {
186 change_id: String,
187 commit_id: String,
188 description: String,
189 details: String,
190 rendered_line: usize,
191}
192
193impl LogEntry {
194 #[must_use]
199 pub fn new(
200 change_id: impl Into<String>,
201 commit_id: impl Into<String>,
202 description: impl Into<String>,
203 ) -> Self {
204 Self {
205 change_id: change_id.into(),
206 commit_id: commit_id.into(),
207 description: description.into(),
208 details: String::new(),
209 rendered_line: 0,
210 }
211 }
212
213 #[must_use]
215 pub fn with_details(mut self, details: impl Into<String>) -> Self {
216 self.details = details.into();
217 self
218 }
219
220 #[must_use]
222 pub const fn with_rendered_line(mut self, rendered_line: usize) -> Self {
223 self.rendered_line = rendered_line;
224 self
225 }
226
227 #[must_use]
229 pub fn change_id(&self) -> &str {
230 &self.change_id
231 }
232
233 #[must_use]
235 pub fn commit_id(&self) -> &str {
236 &self.commit_id
237 }
238
239 #[must_use]
241 pub fn description(&self) -> &str {
242 &self.description
243 }
244
245 #[must_use]
247 pub fn details(&self) -> &str {
248 &self.details
249 }
250
251 #[must_use]
253 pub const fn rendered_line(&self) -> usize {
254 self.rendered_line
255 }
256
257 #[must_use]
259 pub fn summary(&self) -> &str {
260 let first_line = self.description.lines().next().unwrap_or_default();
261 if first_line.is_empty() {
262 "(no description set)"
263 } else {
264 first_line
265 }
266 }
267}